/* ═════════════════════════════════════════════════════════════════════
 * Altoria UI v2 — the shell. Rebuilt on UREDNO. (C6, 2026-08-10)
 *
 * Loads after uredno.css, which carries every token. Nothing here invents a
 * value; where a number appears literally it is because the source states it
 * literally (the sheet's 14px top-left radius, the 12px inset).
 *
 * THE FOUR PLANES — the application is not a page, it is a stack of planes.
 * The logic is QuickBooks'; what differs is where the planes sit.
 *
 *   POLJE      brand green, 100dvh, never scrolls
 *   ZAGLAVLJE  on the field: wordmark · client selector · title · utils
 *   TRAKA      on the field, left, below the header — no card of its own
 *   LIST       white sheet, radius 14 TOP-LEFT ONLY, inset 12px top+left,
 *              bleeding off the right and bottom edges
 *
 * The asymmetric inset is the distinctive move and a considered one. A fully
 * floating panel is what Figma shipped in UI3 and spent two years defending;
 * the recurring complaint is movement in the corner of the eye and colour
 * flashing in the gaps during scroll. Apple reversed the same float in macOS
 * 27. Insetting on two sides gives the layered read where the eye actually
 * looks — top-left, where the brand and nav are — while the data runs to the
 * edge where the user needs the width.
 *
 * Rules this file is bound by:
 *   · every class prefixed `alt2-`, zero bare generics
 *   · zero `!important`
 *   · element selectors only under `.alt2-body`
 *   · zero box-shadow outside the overlay layer (popover e1, modal e2)
 *   · weights 400/500/600 only — no 700, no 300
 *   · the CTA is never green
 * ═══════════════════════════════════════════════════════════════════ */

/* ── 1. Reset — scoped, never global ────────────────────────────────── */
.alt2-body,
.alt2-body *,
.alt2-body *::before,
.alt2-body *::after { box-sizing: border-box; }

.alt2-body {
  margin: 0;
  padding: 0;
  /* 100dvh, not vh — the mobile toolbar collapse makes vh lie. */
  min-height: 100dvh;
  background: var(--alt-ref-logo);
  color: var(--alt-text-1);
  /* SYSTEM UI carries data, controls and operational clarity — brand
     foundation p9, "System UI nosi podatak, kontrolu i operativnu jasnoću".
     Archivo was never in the brand; it was chosen because it is tabular by
     default, and that property is preserved explicitly by the
     font-variant-numeric below rather than by the choice of face. */
  font-family: system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif;
  font-size: 14px;
  line-height: 20px;
  letter-spacing: -0.006em;
  /* Set once at the root so a new table cannot forget it. */
  font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased;
}

.alt2-body h1, .alt2-body h2, .alt2-body h3,
.alt2-body h4, .alt2-body h5, .alt2-body h6,
.alt2-body p,  .alt2-body figure, .alt2-body dl, .alt2-body dd { margin: 0; }

.alt2-body ul, .alt2-body ol { margin: 0; padding: 0; list-style: none; }
.alt2-body img, .alt2-body svg { max-width: 100%; display: block; }
.alt2-body a { color: inherit; text-decoration: none; }

.alt2-body button, .alt2-body input,
.alt2-body select, .alt2-body textarea { font: inherit; color: inherit; margin: 0; }

.alt2-body table {
  border-collapse: collapse;
  width: 100%;
  font-variant-numeric: tabular-nums;
}

/* ── 1b. §0.3 — THE UNIVERSAL INTERACTION LAWS ────────────────────────
 * The blueprint states four laws that "apply to every interactive element
 * in this document. They are not repeated per component." Measured at
 * 4b5f6ad1, none of the four was actually implemented as a law:
 *
 *   FOCUS     zero universal rules; EIGHT per-class :focus-visible rules
 *             using THREE ring colours (currentColor, #FFFFFF,
 *             var(--alt-accent)) and three offsets — and eight interactive
 *             classes with no focus rule at all, including .alt2-link (194
 *             call sites) and .alt2-chip (52).
 *   DISABLED  exactly ONE [disabled] rule in the whole stylesheet, and zero
 *             aria-disabled rules, against 23 disabled interactive elements
 *             in the v2 templates — 14 disabled .alt2-btn across 10 files,
 *             FOUR of them --primary. A disabled CTA rendered at full
 *             opacity with cursor:pointer, because the reset's
 *             `.alt2-body button { color: inherit }` also defeats the UA grey.
 *   MOTION    substantially homed (uredno collapses --dur-1/2/3 to 1ms) but
 *             LEAKING: `scroll-behavior: smooth` and two
 *             scrollBy({behavior:"smooth"}) calls ran unconditionally.
 *   HIT       held for 2 controls of the eight that needed it.
 *
 * They are laws here now, in ONE place, ahead of every component so that a
 * component which genuinely needs to differ can still override by source
 * order rather than by inventing a second ring.
 * ------------------------------------------------------------------- */

/* LAW 1 — ONE focus ring, everywhere, keyboard only.
 *
 * `:where()` contributes ZERO specificity, so this whole selector weighs
 * (0,2,0): `.alt2-body` + `:focus-visible`. That is deliberately the same
 * weight as a bare `.alt2-btn:focus-visible`, so any remaining per-class
 * focus rule must come LATER in the file to win — which makes an override
 * a visible, reviewable act instead of an accident.
 *
 * The blueprint's snippet also writes `border-radius: inherit` inside this
 * rule. That is NOT carried over, and the omission is deliberate: applied
 * to a real element it would replace the control's own radius with its
 * PARENT's on focus, so every pill button would visibly square off the
 * moment it took focus. `outline` already follows `border-radius` per CSS
 * UI 4 in every browser this ships to, so the declaration buys nothing and
 * costs a visible defect. (DEC-24.) */
.alt2-body :where(button, a, input, select, textarea, [tabindex]):focus-visible {
  outline: 2px solid var(--alt-focus-ring);
  outline-offset: 2px;
}
.alt2-body :where(button, a, input, select, textarea, [tabindex]):focus:not(:focus-visible) {
  outline: none;
}

/* The chrome plane is DARK IN BOTH THEMES (--alt-ref-logo is #003320 light /
   #04100B dark), so the light-theme ring measures only 3.11:1 against it —
   which is exactly why .alt2-area and .alt2-rail__btn had forked to a pinned
   #FFFFFF. The surface RE-BINDS THE VARIABLE; the rule does not fork
   (DEC-15). Measured: #7FC4AB is 6.95:1 on chrome-light, 9.58:1 on
   chrome-dark.

   The offset flips to inset here for a mechanical reason, not a stylistic
   one: `.alt2-shell` sets `overflow: hidden`, so a +2px OUTSET ring on a
   control at the rail's edge is clipped by the shell and the keyboard user
   sees three sides of a rectangle. */
.alt2-body .alt2-masthead,
.alt2-body .alt2-rail,
.alt2-body .alt2-submenu { --alt-focus-ring: var(--alt-focus-ring-chrome); }

.alt2-body .alt2-masthead :where(button, a, [tabindex]):focus-visible,
.alt2-body .alt2-rail :where(button, a, [tabindex]):focus-visible,
.alt2-body .alt2-submenu :where(button, a, [tabindex]):focus-visible {
  outline-offset: -2px;
}

/* §0.3 LAW 1 note — the DISABLED half of this section lives at the END of this
   file, not here. Measured in Chromium on the running build: with the rule in
   its natural place at the top, `cursor: default` LOST to `.alt2-btn`'s own
   `cursor: pointer` (line ~657) and four siblings — identical specificity
   (0,2,0), later source position wins. `opacity` and `pointer-events` survived
   only because no component sets them. That is the DEC-20 failure mode exactly:
   a rule losing to a base rule it is supposed to override.

   The focus ring deliberately STAYS here, early, because a component with a
   real reason to differ (the chrome plane's inset offset) should be able to
   override it by source order. A DISABLED control has no such case: it must
   beat every component default, so it goes last. */

/* LAW 4 — a finger target is never below 44x44.
 *
 * "Extend the target with padding or a ::after overlay — NEVER by growing
 * the visual." So the overlay is centred on the control and grows only the
 * hit area; the pill, the glyph and the row rhythm are untouched.
 *
 * Gated on `pointer: coarse` because the law is about what A FINGER
 * touches. Applying it to a mouse would silently enlarge every control's
 * hit box on dense desktop tables, where 8px of invisible overhang on a
 * 36px button is a mis-click waiting to happen rather than an
 * accessibility win.
 *
 * .alt2-carousel__scroll and .alt2-row-open are ABSENT from this list on
 * purpose: both already carry their own ::after target (lines below), and
 * a second one would collide with the first. */
@media (pointer: coarse) {
  .alt2-body :where(.alt2-iconbtn, .alt2-btn, .alt2-chip,
                    .alt2-carousel__item, .alt2-client, .alt2-carousel__all,
                    .alt2-link, .alt2-quickact, .info-tip) {
    position: relative;
  }
  .alt2-body :where(.alt2-iconbtn, .alt2-btn, .alt2-chip,
                    .alt2-carousel__item, .alt2-client, .alt2-carousel__all,
                    .alt2-link, .alt2-quickact, .info-tip)::after {
    content: "";
    position: absolute;
    inset-block-start: 50%;
    inset-inline-start: 50%;
    translate: -50% -50%;
    min-width: 44px;
    min-height: 44px;
    width: 100%;
    height: 100%;
  }
}

/* ── 2. POLJE — the field ─────────────────────────────────────────────
 * The only place brand colour appears at full strength. It stays green in
 * both themes: a product that changes identity when someone turns on the
 * lights doesn't have one. The field is CHROME, not content — it sits
 * outside the work surface and never touches a number, which is what keeps
 * it clear of the three-chromatic-token budget.
 * ------------------------------------------------------------------- */
.alt2-shell {
  height: 100dvh;
  display: grid;
  grid-template-rows: var(--masthead-h) 1fr;
  grid-template-columns: var(--rail-w) 1fr;
  grid-template-areas:
    'head head'
    'rail sheet';
  background: var(--alt-ref-logo);
  overflow: hidden;
}

/* C40 / ALT-948 — NO RAIL, NO COLUMN. Emitted whenever the rail has nothing to
   put in it (today: `client_user`, whose areas strip is deliberately suppressed
   and whose domains moved to the module pills). Reserving 78px for an element
   that renders zero children is the "unearned element" this shell's own
   carousel guard refuses, applied to the widest one on the page.

   Same two-row shape the mobile breakpoint already uses, so nothing new is
   introduced — the rail simply stops existing on this axis too. */
.alt2-body .alt2-shell--norail {
  grid-template-columns: 1fr;
  grid-template-areas:
    'head'
    'sheet';
}

/* ── 3. ZAGLAVLJE — the header, on the field ──────────────────────────
 * Because it lives on the field rather than in the scroller, page scroll
 * never moves it: no sticky, no shadow, no backdrop filter.
 * ------------------------------------------------------------------- */
.alt2-masthead {
  grid-area: head;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--sp-4);
  padding: 0 var(--sp-4);
  color: #FFFFFF;
}

.alt2-masthead__lead,
.alt2-masthead__utils { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; }
.alt2-masthead__utils { justify-content: flex-end; }

.alt2-body .alt2-wordmark {
  /* OUTFIT carries the message and the character (brand foundation p9).
     Never mixed with the work face inside one role — "NE MIJEŠATI UNUTAR
     ISTE ULOGE". Only 400 and 700 are vendored, so a declared 500/600
     resolves by CSS font matching to a REAL file, never a
     synthetic weight — but NOT both to 700. For a desired weight of 500 the
     algorithm checks weights below 500 in descending order first, so 500 -> the
     400 file (Regular); only 600 -> 700 (Bold). Corrected 21.08.2026; DEC-4 and
     four copies of this comment claimed "500/600 -> 700". Declared weights stay 400/500/600 per the Uredno rule
     the isolation gate enforces. */
  font-family: 'Outfit', system-ui, -apple-system, 'Segoe UI', sans-serif;
  font-weight: 600;
  font-size: 18px;
  letter-spacing: -0.02em;
  color: #FFFFFF;
}

/* Screen title, centred. The brand face is permitted — a title is not a number. */
.alt2-masthead__title {
  /* OUTFIT carries the message and the character (brand foundation p9).
     Never mixed with the work face inside one role — "NE MIJEŠATI UNUTAR
     ISTE ULOGE". Only 400 and 700 are vendored, so a declared 500/600
     resolves by CSS font matching to a REAL file, never a
     synthetic weight — but NOT both to 700. For a desired weight of 500 the
     algorithm checks weights below 500 in descending order first, so 500 -> the
     400 file (Regular); only 600 -> 700 (Bold). Corrected 21.08.2026; DEC-4 and
     four copies of this comment claimed "500/600 -> 700". Declared weights stay 400/500/600 per the Uredno rule
     the isolation gate enforces. */
  font-family: 'Outfit', system-ui, -apple-system, 'Segoe UI', sans-serif;
  font-size: 15px;
  font-weight: 500;
  letter-spacing: -0.01em;
  color: rgba(255, 255, 255, .92);
  white-space: nowrap;
}

/* Aktivni klijent — the session's most-consulted fact, so it sits beside the
   wordmark rather than inside a menu. */
.alt2-client {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  height: 32px;
  padding: 0 var(--sp-3);
  border: 1px solid rgba(255, 255, 255, .28);
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, .10);
  color: #FFFFFF;
  font-size: 13px;
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--dur-1) var(--alt-ease-in);
}

.alt2-client:hover { background: rgba(255, 255, 255, .18); }

/* The workspace sentence for altoria_self is "ADMIN - administracija
   platforme" — 32 characters, which would push the centred domain title off
   its axis. Clip it here and keep the whole string on the button's title. */
.alt2-client__name {
  display: block;
  max-width: 24ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.alt2-body .alt2-iconbtn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border: 0;
  border-radius: var(--r-md);
  background: transparent;
  /* inherit the SURFACE's ink — see the surface-affinity note below */
  color: inherit;
  cursor: pointer;
  transition: background var(--dur-1) var(--alt-ease-in),
              color var(--dur-1) var(--alt-ease-in);
}

.alt2-body .alt2-iconbtn:hover { background: var(--alt-bg-surface-2); }

/* SURFACE AFFINITY. `.alt2-iconbtn` serves two surfaces and they want opposite
   ink, which is exactly the law the design system states: bind by SURFACE,
   never by preference.
     on the chrome  — masthead utils, 6 call sites: white ink is correct
     in the sheet   — 8 call sites: white ink is INVISIBLE
   MEASURED 2026-08-21 on the client portal in light theme: the privacy toggle
   at klijent/dashboard.html:231 (the eye that hides every amount on the page)
   rendered `rgba(255,255,255,.78)` on an effective background of `#FFFFFF` —
   **1.0:1**, a functional control the client literally cannot see. Same class,
   same defect, at the bug-modal close (_base.html:389), je_editor's two
   remove-line buttons, intake_show's two PDF zoom controls, eracun_list's
   storno close and workers_neuron's modal close.
   The base rule now inherits the surface's own ink; the chrome re-asserts
   white for its own context. Zero template lines change. */
.alt2-body .alt2-masthead .alt2-iconbtn { color: rgba(255, 255, 255, .78); }
.alt2-body .alt2-masthead .alt2-iconbtn:hover {
  background: rgba(255, 255, 255, .14);
  color: #FFFFFF;
}

/* ── 4. TRAKA — the domain rail, directly on the field ────────────────
 * No card of its own. A rail with its own surface makes three surfaces where
 * two will do — that is the QuickBooks move and it is the right one.
 *
 * The rail carries DOMAINS; the carousel inside the sheet carries the SCREENS
 * of the active domain. That split is what makes twelve destinations
 * survivable.
 *
 * Persistent micro-labels, never icon-only: Nielsen Norman measured hidden
 * navigation used 27% of the time against 48–50% for visible, and desktop
 * tasks 39% slower.
 * ------------------------------------------------------------------- */
.alt2-rail {
  grid-area: rail;
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  padding: var(--sp-2) 0;
  overflow: visible;
}

/* AREAS — the tier ABOVE the domains (Radni prostor · Praksa · Admin).
   One rail shows one tree; this is how you change trees. It reads as a
   different register on purpose: the domains below are marked with a 2px
   left bar in FRESH, an area is marked with a filled pill and full-white
   ink, so two levels of "selected" can never be mistaken for each other.
   State is never colour-only — the pill is a shape change, and the weight
   moves with it. */
.alt2-areas {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 0 var(--sp-1) var(--sp-2);
  margin-bottom: var(--sp-2);
  border-bottom: 1px solid rgba(255, 255, 255, .18);
}

.alt2-body .alt2-area {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1px;
  padding: var(--sp-1) 2px;
  border-radius: var(--r-md);
  color: rgba(255, 255, 255, .62);
  transition: color var(--dur-1) var(--alt-ease-in),
              background var(--dur-1) var(--alt-ease-in);
}

.alt2-body .alt2-area:hover { color: #FFFFFF; background: rgba(255, 255, 255, .08); }

/* C39 — the strip's own caption. Without it the three items read as more
   rail destinations; with it they read as one question with three answers. */
.alt2-body .alt2-areas__cap,
.alt2-body .alt2-pins__cap {
  display: block;
  padding: var(--sp-1) 0 3px;
  color: rgba(255, 255, 255, .46);
  font-size: 9px;
  font-weight: 600;
  letter-spacing: .09em;
  text-align: center;
  text-transform: uppercase;
}

/* C39 — the ACTIVE mode is the single most load-bearing fact on the screen:
   it says whose money the next click touches. It was a 16 % white wash, the
   same treatment a hovered item gets, so "where am I" and "what is under the
   cursor" looked alike. The marker bar is what distinguishes them. */
.alt2-body .alt2-area--on {
  position: relative;
  color: #FFFFFF;
  background: rgba(255, 255, 255, .16);
  font-weight: 600;
}

/* The light-green 2px bar that used to sit here was removed on Daniel's
   instruction (2026-08-24): "remove the light green line — it is unnecessary
   and annoying". The selected area keeps TWO non-colour signals without it —
   the 16% white wash above and weight 600 — so state is still not hue-only. */

/* Caps, because an AREA is a category and a DOMAIN is a place. Rendered at
   1440x900 the two tiers were both icon-over-sentence-case and read as
   "three more domains at the top" — the hairline separated them but nothing
   said they were a different KIND of thing. Uredno's micro style (w500, caps,
   positive tracking — the only positive tracking in the system) is exactly the
   category label, so the distinction is the type ramp doing its job rather
   than a second colour or a heavier weight. */
.alt2-area__label {
  font-size: 9px;
  line-height: 11px;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.alt2-rail__item { position: relative; }

.alt2-body .alt2-rail__btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  width: 100%;
  padding: var(--sp-1) 2px;
  border: 0;
  background: transparent;
  color: rgba(255, 255, 255, .74);
  cursor: pointer;
  transition: color var(--dur-1) var(--alt-ease-in);
}

.alt2-body .alt2-rail__btn:hover { color: #FFFFFF; }

.alt2-rail__label {
  font-size: 9px;
  line-height: 11px;
  font-weight: 500;
  letter-spacing: 0.01em;
  text-align: center;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Selected rail item — the green marker bar was removed on Daniel's
   instruction (2026-08-24). State is still not colour-only: weight 600 plus a
   faint surface wash carry it, and neither depends on hue. */
.alt2-rail__item--on .alt2-rail__btn {
  color: var(--alt-ref-fresh);
  font-weight: 600;
  background: rgba(255, 255, 255, .10);
  border-radius: 8px;
}

/* ── UZORCI — the design-system gallery (C41 · Stage 5).
 *
 * The page these style is GENERATED from design-tokens.json + token-map.json
 * (design-system/emit_gallery.py). Each chip paints `var(--alt-…)`, so this
 * section deliberately sets no colour of its own: a swatch that took its fill
 * from here would show the gallery's opinion of the palette rather than the
 * stylesheet's, which is the exact two-owner defect the legacy `examples.html`
 * shipped with.
 * ------------------------------------------------------------------- */
.alt2-swatches {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: var(--sp-2);
}

.alt2-swatch {
  display: grid;
  grid-template-columns: 28px 1fr;
  grid-column-gap: var(--sp-2);
  align-items: center;
  padding: var(--sp-2);
  border: 1px solid var(--alt-line-soft, rgba(0, 0, 0, .10));
  border-radius: var(--r-sm, 6px);
  min-width: 0;
  align-content: start;
  grid-row-gap: 2px;
}

/* The chip is the only element on the page allowed an inline style, and the
   value is always `var(--alt-…)`, never a literal. */
.alt2-swatch__chip {
  /* Spans the rows but sits at the TOP of them: centred across a card whose
     height varies with the note length, the chip drifted to the middle and
     read as unaligned. */
  grid-row: 1 / span 4;
  align-self: start;
  width: 28px;
  height: 28px;
  border-radius: var(--r-xs, 4px);
  border: 1px solid var(--alt-line-soft, rgba(0, 0, 0, .12));
}

/* A token with no colour value still gets a slot, so the row count matches the
   token count and nothing looks omitted. */
.alt2-swatch__chip--none {
  background: repeating-linear-gradient(45deg,
    transparent, transparent 3px,
    var(--alt-line-soft, rgba(0, 0, 0, .12)) 3px,
    var(--alt-line-soft, rgba(0, 0, 0, .12)) 4px);
}

.alt2-swatch__name {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px;
  overflow-wrap: anywhere;
}

.alt2-swatch__val {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px;
  opacity: .74;
}

.alt2-swatch__note { font-size: 11px; opacity: .62; }

/* "Carried forward at its current value" is a real state of the token map and
   is labelled rather than hidden — 23 rows are in it. */
.alt2-swatch__gap { font-size: 10px; opacity: .70; font-style: italic; }

/* ── PRIBADAČE — the rail's pinned shortlist (C41 · ALT-950 / ALT-951).
 *
 * The item styling above (`.alt2-rail__item` / `__btn` / `__label` / `--on`)
 * was written for the deleted domain tier and has had NO markup owner since
 * C40. It is reused here rather than replaced: the tier that left the rail and
 * the tier that arrives in it are the same 78px column with the same 9px label
 * cap, so a second set of rules describing the same box would be two owners of
 * one look. This section adds only what the list itself needs.
 * ------------------------------------------------------------------- */
.alt2-pins {
  list-style: none;
  margin: var(--sp-2) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

/* A pin being DRAGGED. Reorder is a rearrangement, not a removal, so the row
   keeps its place in the flow and only loses contrast — a gap opening where the
   item was would read as "it is gone". */
.alt2-body .alt2-rail__item--dragging { opacity: .45; }

/* Where it would land. A 2px rule on the leading edge, the same weight and
   colour the selected marker uses, because both answer "this row, here". */
.alt2-body .alt2-rail__item--over { box-shadow: inset 0 2px 0 0 var(--alt-ref-fresh); }

/* Grab affordance only where dragging is actually wired. Without JS the rail is
   still a list of working links, which is the no-JS contract this shell keeps. */
.alt2-pins[data-alt2-pinlist] .alt2-rail__item { cursor: grab; }
.alt2-pins[data-alt2-pinlist] .alt2-rail__item--dragging { cursor: grabbing; }

/* "Could not be computed" is a different sentence from "nothing pinned", and it
   has to be readable as such — see shared/pinned_screens.py rule 3. */
.alt2-pins__err {
  margin: var(--sp-2) 4px 0;
  font-size: 9px;
  line-height: 11px;
  text-align: center;
  color: rgba(255, 255, 255, .62);
}

/* The toggle sits in the masthead utility cluster, so it inherits
   `.alt2-iconbtn`; the form is a wrapper with no box of its own. */
.alt2-pinform { display: contents; }

/* Pinned = the same champagne the rail's selected marker uses. State is never
   colour-only here either: the button also carries `aria-pressed`. */
.alt2-body .alt2-iconbtn--on { color: var(--alt-ref-fresh); }

/* The reorder form posts from script; it has no visual box. */
.alt2-pinorder { display: none; }

/* ── 5. LIST — the sheet, the working plane ───────────────────────────
 * radius 14 on the TOP-LEFT corner only; inset 12px from top and left;
 * bleeds off the right and bottom. `overflow: clip` so the parent clips that
 * corner and no child needs its own radius. Takes NO shadow: it is separated
 * by the field colour and 12px of space, and a shadow would break the
 * zero-shadow rule for nothing.
 * ------------------------------------------------------------------- */
.alt2-sheet {
  grid-area: sheet;
  /* WAS a grid with `grid-auto-rows: auto` plus `.alt2-scroll { grid-row: -1 }`.
     That combination is why the screen title rendered UNDER the content on every
     screen whose carousel is present — MEASURED in a browser 2026-08-14, not
     reasoned: `grid-row: -1` resolves against the EXPLICIT grid, and
     `grid-template-rows: auto` declares exactly ONE explicit row, so line -1 is
     line 2 and the scroller was pinned to row 2 no matter how many siblings
     preceded it. With two children (client portal, no carousel) the subhead
     landed in row 1 and looked right BY ACCIDENT; with three it was pushed to
     row 3, i.e. below the scroller, at the bottom of the viewport.
     Flex column expresses the real intent — "these three stack in DOM order and
     the scroller absorbs the rest" — and cannot be fooled by the child count,
     which is the property the grid version silently lacked. */
  display: flex;
  flex-direction: column;
  min-height: 0;            /* without this the inner scroller never shrinks */
  /* ALT-884. The vertical twin of the line above, and the actual cause of the
     carousel defect. `.alt2-sheet` is a GRID ITEM of `.alt2-shell`
     (grid-template-columns: var(--rail-w) 1fr). A grid item defaults to
     `min-width: auto`, i.e. "never shrink below your content", so a domain with
     enough carousel items made the sheet grow to its content width instead of
     being constrained to the 1fr track.
     MEASURED 2026-08-21 on /centrala/api-trosak at a 1440 viewport, before the
     fix: .alt2-carousel and .alt2-sheet both 1581px wide, right edge 1649 —
     209px past the viewport, which is exactly the figure in ALT-884's title.
     Because the carousel then never overflowed ITSELF (scrollWidth ==
     clientWidth == 1581) its own `overflow-x: auto` produced no scrollbar, and
     `.alt2-shell { overflow: hidden }` clipped the surplus: the band was
     unreachable by scroll, keyboard or drag.
     With min-width: 0 the sheet is held to the track (1440 - rail 56 - inset 12
     = 1372, which is what every non-overflowing screen already measured), the
     carousel's content genuinely overflows it, and the `overflow-x: auto` that
     was always there starts working. No markup and no other rule changes. */
  min-width: 0;
  margin: var(--sheet-inset) 0 0 var(--sheet-inset);
  border-radius: var(--sheet-radius) 0 0 0;
  background: var(--alt-bg-page);
  overflow: clip;
  box-shadow: var(--alt-e0);
}

/* ── 5a. KARUSEL — the screens of the active domain ─────────────────── */
/* ALT-884, the OPEN HALF (C29). C27 fixed REACHABILITY — `min-width: 0` on
   `.alt2-sheet` stopped the sheet growing past its 1fr grid track, so the
   carousel's existing `overflow-x: auto` started working. What was still
   missing is the AFFORDANCE: `shell2.js` had zero picker code, so the band
   scrolled by trackpad and by nothing else, and the last item rendered cut
   mid-word with no visible signal that more existed.

   Blueprint §3.3-§3.10 needs three boxes, not one, and the reason is
   structural rather than stylistic: the scroll controls must NOT live inside
   the scroll container (they would scroll away with the content), and the edge
   fades must be positioned against a box that does NOT scroll (an
   absolutely-positioned child of a scroller is laid out against the padding
   box, which moves). So:

     .alt2-carouselbar     §3.3 `.modulebar`  — the bar chrome + the controls
       .alt2-carousel__scroll--prev           — outside the track, §3.9
       .alt2-carousel__wrap §3.4 `.modwrap`   — the fade anchor, does not scroll
         .alt2-carousel    §3.4 `.modules`    — THE TRACK, unchanged identity
       .alt2-carousel__scroll--next

   `.alt2-carousel` keeps its name, its element (`<nav aria-label="Ekrani">`)
   and its role as the scroller, so every existing rule and every gate that
   keys on it (`_check_shell_v2_nav_ia.py:695`) is untouched. The bar chrome —
   height, padding, background, bottom hairline — MOVES UP to the new bar,
   because a scroller that paints its own background paints it at the scrolled
   position. */
.alt2-carouselbar { flex: 0 0 auto;
  position: relative;
  display: flex;
  align-items: center;
  /* §3.3: symmetric 12px on BOTH sides. A single trailing arrow makes the
     block read as right-weighted and the content as having drifted left. */
  gap: var(--sp-3);
  min-width: 0;
  height: var(--carouselbar-h);
  padding: 0 var(--sp-5);
  border-bottom: 1px solid var(--alt-line);
  background: var(--alt-bg-surface-1);
}

.alt2-carousel__wrap {
  position: relative;
  flex: 1 1 auto;
  /* The `min-width: auto` trap again, one level in. A flex ITEM refuses to
     shrink below its min-content width, so without this the wrap grows to the
     track's content width and hands the overflow straight back to the sheet —
     which is the exact defect DEC-10 measured at 209px. */
  min-width: 0;
  display: flex;
  align-items: center;
}

.alt2-carousel { flex: 1 1 auto;
  display: flex;
  align-items: center;
  /* ALT-884, belt and braces. The sheet's min-width: 0 is what actually fixes
     the overflow; this keeps the carousel honest if it is ever re-parented into
     another flex or grid ancestor, where it would inherit the same
     `min-width: auto` trap. Harmless where the parent already constrains it. */
  min-width: 0;
  gap: var(--sp-1);
  /* `overflow-x: auto` with `overflow-y: visible` computes overflow-y to
     `auto` as well, so the block axis clips too: a focus ring on a pill was
     shaved top and bottom. 3px of block padding gives it room inside the bar's
     fixed 64px, so nothing moves visually. */
  padding-block: 3px;
  overflow-x: auto;
  /* §3.4. Do not chain the scroll to the page: a trackpad flick that runs out
     of carousel must not start scrolling the sheet under it. */
  overscroll-behavior-inline: contain;
  /* §0.3 law 3. Reduced motion COLLAPSES, it does not substitute — and
     this declaration used to run unconditionally, so a user who had
     asked the OS for no motion still got an animated scroll every time
     the carousel moved. uredno.css collapses --dur-1/2/3 to 1ms, which
     catches every transition in the shell but cannot reach a
     `scroll-behavior` keyword. Gated on `no-preference` rather than
     overridden under `reduce`, so the default for a user who has
     expressed no preference is unchanged and the reduced-motion user
     never has to out-specify a rule. */
  /* §3.4. 28px == the fade width, so a pill reached by TAB never lands
     underneath the gradient that says "there is more". */
  scroll-padding-inline: 28px;
  scrollbar-width: none;
  /* §3.5, and `safe` is the whole point. When the pills fit, the row centres
     in the bar and reads as deliberate. When they overflow, `safe` degrades to
     `start`; bare `center` would push the FIRST pill into negative scroll
     space, where several engines make it unreachable by scrolling at all. */
  justify-content: safe center;
}

@media (prefers-reduced-motion: no-preference) {
  .alt2-body .alt2-carousel { scroll-behavior: smooth; }
}

.alt2-carousel::-webkit-scrollbar { display: none; }

/* §3.6 EDGE FADES — "there is more", without a scrollbar, and only on the side
   that actually has more. Bound to data-l / data-r, which §3.10 makes the
   picker's only writers.
   SURFACE, not canvas: the blueprint's gradient stop is `--surface-canvas`
   because it draws the fade sitting on the page. Here the bar paints
   `--alt-bg-surface-1`, so the fade must dissolve into THAT or it leaves a
   visible pale band on the sheet. Measuring a fade against the wrong surface
   is the same class of error as measuring contrast against the wrong one. */
.alt2-body .alt2-carousel__wrap::before,
.alt2-body .alt2-carousel__wrap::after {
  content: "";
  position: absolute;
  inset-block: 0;
  width: 28px;
  pointer-events: none;
  z-index: 2;
  opacity: 0;
  transition: opacity var(--dur-2) var(--alt-ease-in);
}
.alt2-body .alt2-carousel__wrap::before {
  inset-inline-start: 0;
  background: linear-gradient(90deg, var(--alt-bg-surface-1) 12%, transparent);
}
.alt2-body .alt2-carousel__wrap::after {
  inset-inline-end: 0;
  background: linear-gradient(270deg, var(--alt-bg-surface-1) 12%, transparent);
}
.alt2-body .alt2-carousel__wrap[data-l="1"]::before { opacity: 1; }
.alt2-body .alt2-carousel__wrap[data-r="1"]::after  { opacity: 1; }

/* §3.9 SCROLL CONTROL. One chevron symbol, mirrored — the sprite already
   carries both #i-chev-left and #i-chev-right, so no new symbol is authored
   and the black-coin var() trap (§4) cannot apply: tier-2 symbols paint
   `currentColor`, never a var(). */
.alt2-body .alt2-carousel__scroll {
  position: relative;
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: var(--control-h);
  height: var(--control-h);
  border-radius: var(--r-pill);
  background: var(--alt-bg-surface-1);
  border: 1px solid var(--alt-line-strong);
  color: var(--alt-text-2);
  cursor: pointer;
  transition: color var(--dur-1) var(--alt-ease-in),
              border-color var(--dur-1) var(--alt-ease-in),
              background var(--dur-1) var(--alt-ease-in),
              opacity var(--dur-2) var(--alt-ease-in);
}
.alt2-body .alt2-carousel__scroll .alt2-ico { width: 15px; height: 15px; }
/* §3.9: "one chevron symbol, mirrored". Both controls draw #i-chev-right; the
   leading one is rotated. That is what makes `--prev` a rule rather than a
   label, and it is why there is no `--next` modifier to pair with it. */
.alt2-body .alt2-carousel__scroll--prev .alt2-ico { transform: rotate(180deg); }
/* §0.3 hit target: 36px visual, 44px target. Grown with an overlay, never by
   growing the visual — the bar is 64px tall and a 44px disc would crowd it. */
.alt2-body .alt2-carousel__scroll::after {
  content: "";
  position: absolute;
  inset: -4px;
  border-radius: inherit;
}
.alt2-body .alt2-carousel__scroll:hover {
  color: var(--alt-text-1);
  border-color: var(--alt-action-bg);
}
.alt2-body .alt2-carousel__scroll:active { background: var(--alt-bg-surface-2); }
/* §0.3 disabled: 30%, no pointer feedback. At an end, not gone — the control
   still says which direction exists. */
/* §3.9: when the row FITS, the two controls leave layout AND the a11y tree.
   "A control that can never do anything is worse than no control."
   data-fits ships as "1" so a JS-off render is byte-for-byte today's row —
   the affordance is added, never a requirement. */
.alt2-body .alt2-carouselbar[data-fits="1"] .alt2-carousel__scroll:not(.alt2-carousel__all) { display: none; }
/* C40 / ALT-948 — THE "SVI EKRANI" TRIGGER NO LONGER OBEYS data-fits, and the
   comment that used to sit here said the opposite for a good reason that has
   since expired.

   While the bar carried SCREENS, the trigger was a convenience: a row that fit
   showed every screen already, so hiding the "all" button hid nothing. The bar
   now carries DOMAINS and the screens live only behind this button, so the old
   rule made the third tier unreachable the moment the pills fit — which is the
   common case (7 pills at 1280px).

   MEASURED on the running lab before the fix, operator on /centrala/:
     data-fits="1" · trigger display "none" · 11 screen links in the flyout.
   Eleven screens present in the DOM and reachable by nothing. That is DEC-52
   ("a link is not a door until you can reach the room it is in") re-introduced
   by the tier move, and no route gate could see it: every route is in the
   catalogue and answers 200; only the door was gone. */
.alt2-body .alt2-carousel__all { margin-inline-start: calc(var(--sp-3) * -1 + var(--sp-2)); }

.alt2-body .alt2-carousel__item {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  height: 34px;
  padding: 0 var(--sp-3);
  border-radius: var(--r-md);
  color: var(--alt-text-2);
  font-size: 13px;
  font-weight: 500;
  white-space: nowrap;
  transition: background var(--dur-2) var(--alt-ease-in),
              color var(--dur-2) var(--alt-ease-in);
}

.alt2-body .alt2-carousel__item:hover { background: var(--alt-bg-surface-2); color: var(--alt-text-1); }

/* The active screen stays permanently labelled — hidden labels are the single
   most-evidenced failure in this pattern. The 2px marker goes to the bottom
   edge here: the system specifies a LEFT rail, which does not survive going
   horizontal, but it stays a marker because state is never colour-only. */
/* SCOPED, and it was not — found by C29 by MEASURING the live page, in the
   component this pass was building.
   `.alt2-carousel__item--on` is (0,1,0). Its own base rule
   `.alt2-body .alt2-carousel__item` is (0,2,0), and `.alt2-body a` is (0,1,1).
   The modifier lost to BOTH, so the selected screen rendered at
   `--alt-text-2` / weight 500 — the same ink and the same weight as every
   unselected sibling, and at LOWER contrast than them because it sits on the
   mint fill. Measured on /centrala/api-trosak, both themes:
     light  on rgb(74,90,82) 6.09:1  ·  off rgb(74,90,82) 7.30:1  (identical ink)
     dark   on rgb(157,176,166) 5.87:1 · off rgb(157,176,166) 8.02:1
   This is the ALT-875 family — "the SELECTED item rendered less legibly than
   its unselected siblings" — still live on the carousel after C27 fixed
   `.alt2-area`. The 2px marker was carrying the state on its own. */
.alt2-body .alt2-carousel__item--on {
  background: var(--alt-selected);
  color: var(--alt-text-1);
  font-weight: 600;
  box-shadow: inset 0 -2px 0 var(--alt-selected-marker);
}

/* You are INSIDE this destination but not ON it — a drill-down (/coa/{code}),
   a tab the brief names but gives no href of its own (/centrala/vies), or the
   POST twin of a GET screen. It must read as less than --on or the two states
   collapse: no fill, one ink step up from rest, and a NEUTRAL marker instead
   of the selected-green one, so the green stays monosemic.
   Matching aria-current is "true", never "page". */
.alt2-body .alt2-carousel__item--within {
  color: var(--alt-text-1);
  box-shadow: inset 0 -2px 0 var(--alt-line-strong);
}

/* ── 5a-bis. MODULI — the domain tier, blueprint §3.7-§3.8 (C40 · ALT-948)
 *
 * The domains moved out of the 78px rail and into this row. Three things
 * follow from that move and none of them is decoration:
 *
 * 1. THE DISC IS NO LONGER ON CHROME. `--alt-chrome-disc` is scoped to
 *    `.alt2-masthead` / `.alt2-rail` and exists because a CORE plate on the
 *    CORE field is invisible (§4 "Chrome override"). Here the pill sits on the
 *    SHEET, so the plate resolves to `--alt-disc-fill` — the true deep brand
 *    plate — with no override needed and none added. The glyph keeps its
 *    family tone. This is the one place the tier-1 badge renders as designed.
 *
 * 2. THE LABEL IS THE FULL WORD. The rail forced `short` at 9px; a 44px pill
 *    carries `label` at 13px. That is the whole reason the tier moved.
 *
 * 3. HOVER BORROWS THE FAMILY ACCENT, not a generic grey (§3.7). Six families
 *    hover in six colours and that IS the point — the colour is teaching the
 *    map before the word is read. `--alt-fam-accent` is set by `.alt2-fam-*`
 *    on the SVG inside; it is re-declared on the pill itself below so the
 *    border can reach it, because a custom property set on a child does not
 *    cascade upward.
 *
 * `.alt2-mod` is unrelated to `.alt2-modal`. The dead-class gate matches whole
 * class tokens so they cannot collide, but do not shorten either name further.
 * ------------------------------------------------------------------- */
.alt2-body .alt2-mod {
  display: inline-flex;
  align-items: center;
  flex: 0 0 auto;
  gap: var(--sp-2);
  height: var(--row-h);
  /* §3.7 — the LEADING pad is DERIVED so the 30px disc is optically centred in
     the 44px cap: (44 - 30) / 2 = 7. Trailing is a full step. A hand-picked
     leading value here is what makes a pill row look subtly ragged. */
  padding-inline: 7px var(--sp-4);
  border-radius: var(--r-pill);
  background: var(--alt-bg-surface-1);
  border: 1px solid var(--alt-line);
  color: var(--alt-text-1);
  font-size: 13px;
  font-weight: 500;
  white-space: nowrap;
  transition: transform var(--dur-1) var(--alt-ease-in),
              border-color var(--dur-1) var(--alt-ease-in),
              background var(--dur-1) var(--alt-ease-in);
}

.alt2-body .alt2-mod__label { min-width: 0; }

/* Family accent, re-declared on the pill so the BORDER can read it. The
   `.alt2-fam-*` class sits on the inner <svg> (it has to — that is what tints
   the glyph), and a custom property set there is invisible to the parent. */
.alt2-body .alt2-mod:has(.alt2-fam-novac)     { --alt-mod-accent: var(--alt-accent-novac); }
.alt2-body .alt2-mod:has(.alt2-fam-dokumenti) { --alt-mod-accent: var(--alt-accent-dokumenti); }
.alt2-body .alt2-mod:has(.alt2-fam-drzava)    { --alt-mod-accent: var(--alt-accent-drzava); }
.alt2-body .alt2-mod:has(.alt2-fam-ljudi)     { --alt-mod-accent: var(--alt-accent-ljudi); }
.alt2-body .alt2-mod:has(.alt2-fam-banka)     { --alt-mod-accent: var(--alt-accent-banka); }
.alt2-body .alt2-mod:has(.alt2-fam-rizik)     { --alt-mod-accent: var(--alt-accent-rizik); }

.alt2-body .alt2-mod:hover {
  /* Falls back to the focus-ring accent for a domain with no `fam` — the same
     domain the macro renders with a line glyph instead of a disc. */
  border-color: var(--alt-mod-accent, var(--alt-accent));
  transform: translateY(-1px);
}
.alt2-body .alt2-mod:active {
  transform: translateY(0);
  background: var(--alt-bg-surface-2);
}

/* §3.7 selected — RING, not fill (Daniel, 2026-08-24).
   The previous treatment filled the pill with `--alt-selected` and set
   `border-color: transparent`, i.e. it DELETED the pill's frame on select and
   replaced it with a green block. Daniel's instruction is the inverse: the
   frame stays on the selection, no colour fill, no extra animation.

   ALT-875 is still satisfied. That rule says the selected item must not render
   LESS legibly than its siblings and must never be distinguished by hue alone.
   Here the state carries TWO non-colour signals — a 2px ring where siblings
   have a 1px one, and weight 600 where siblings are 500 — so it survives both
   greyscale and a colour-vision deficiency. Fill was never the load-bearing
   part; the marker was, and the ring replaces it.

   `transition` and `transform` are both neutralised on the selected pill: the
   frame must not fade in and the pill must not lift. */
.alt2-body .alt2-mod--on {
  background: transparent;
  border-color: var(--alt-mod-accent, var(--alt-accent));
  box-shadow: inset 0 0 0 1px var(--alt-mod-accent, var(--alt-accent));
  color: var(--alt-text-1);
  font-weight: 600;
  transition: none;
}
.alt2-body .alt2-mod--on:hover,
.alt2-body .alt2-mod--on:active {
  transform: none;
  background: transparent;
  border-color: var(--alt-mod-accent, var(--alt-accent));
}

/* ── 5b. PODNASLOV — screen name + the one primary action ─────────────
 *
 * `flex-wrap` is LOAD-BEARING, not cosmetic (C31, 2026-08-22). This row was
 * `display: flex` with the default `nowrap`, and the sheet it lives in is
 * `overflow-x: clip`. Those two together do not produce a scrollbar and do not
 * grow the document — they produce an element that is simply NOT THERE. The
 * C31 crawl measured it on the operator at 375px:
 *
 *     /                       .alt2-subhead__actions right edge 413px > 375px
 *     /centrala               .alt2-subhead__actions right edge 413px > 375px
 *     /centrala/freelanceri   .alt2-subhead__actions right edge 443px > 375px
 *
 * The right-most control in that row is the screen's ONE primary action, so on
 * three operator screens the primary action was 38-68px past the clip and
 * unreachable by touch, pointer or scroll. `wrap` drops the action group to its
 * own line instead; `row-gap` keeps the two lines from colliding. Note this is
 * exactly the class of defect the naive document-level overflow assertion
 * cannot see, which is why the proof measures per element. */
.alt2-subhead { flex: 0 0 auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2) var(--sp-4);
  min-height: var(--subhead-h);
  padding: var(--sp-2) var(--sp-5);
  border-bottom: 1px solid var(--alt-line);
  background: var(--alt-bg-surface-1);
}

/* The title group is the unnamed first child; without `min-width: 0` a long
   screen name refuses to shrink below its longest word and re-creates the
   overflow that `wrap` just removed. Element selector, so it is scoped under
   `.alt2-body` as the isolation gate requires. */
.alt2-body .alt2-subhead > :first-child { min-width: 0; }

.alt2-subhead__title {
  /* OUTFIT carries the message and the character (brand foundation p9).
     Never mixed with the work face inside one role — "NE MIJEŠATI UNUTAR
     ISTE ULOGE". Only 400 and 700 are vendored, so a declared 500/600
     resolves by CSS font matching to a REAL file, never a
     synthetic weight — but NOT both to 700. For a desired weight of 500 the
     algorithm checks weights below 500 in descending order first, so 500 -> the
     400 file (Regular); only 600 -> 700 (Bold). Corrected 21.08.2026; DEC-4 and
     four copies of this comment claimed "500/600 -> 700". Declared weights stay 400/500/600 per the Uredno rule
     the isolation gate enforces. */
  font-family: 'Outfit', system-ui, -apple-system, 'Segoe UI', sans-serif;
  font-size: 18px;
  line-height: 26px;
  font-weight: 600;
  letter-spacing: -0.014em;
  color: var(--alt-text-1);
}

.alt2-subhead__meta { color: var(--alt-text-2); font-size: 12px; line-height: 18px; }
.alt2-subhead__actions { display: flex; align-items: center; gap: var(--sp-2); }

/* ── 5c. The scroller. Only this scrolls; bounce stays inside the sheet
 * and scroll never chains to the field. */
.alt2-scroll {
  min-height: 0;
  flex: 1 1 auto;           /* absorbs the sheet's remaining height */
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--sp-5);
}

/* ── 6. Controls ──────────────────────────────────────────────────────
 * The CTA is maximum-contrast brand-tinted ink, NEVER green. Green must stay
 * monosemic: a green "Proknjiži" one row above a green "Proknjiženo" badge is
 * a genuine misread on a posting system.
 * ------------------------------------------------------------------- */

/* ═══════════════════════════════════════════════════════════════════════
 * SPECIFICITY: the component rules below are scoped under `.alt2-body`.
 *
 * NOT cosmetic, and not a style preference. The element reset at the top of
 * this file is written as `.alt2-body button, .alt2-body input, …` and
 * `.alt2-body h1 … h6, .alt2-body p` — specificity (0,1,1). Every component
 * rule here is a single class — (0,1,0). (0,1,1) wins, so the component's own
 * `font-size`, `font-weight`, `color` and `margin` NEVER APPLIED.
 *
 * MEASURED 2026-08-21 on a live v2 page (/centrala/klijenti, :8003), same
 * stylesheet, same page:
 *     a.alt2-btn        13px / 500   <- the specified values
 *     button.alt2-btn   14px / 400   <- the body's, because `font: inherit`
 *                                       out-specified `.alt2-btn`
 *     select.alt2-select 14px / 400  <- same
 * i.e. an anchor and a button wearing the SAME class rendered at different
 * sizes and weights beside each other in the same toolbar, and ~715 form
 * controls ignored their own type scale.
 *
 * `.alt2-body .alt2-btn--primary` twenty lines below already carried this fix
 * and its own comment describing the identical trap, found the same way — by
 * rendering it. This generalises that fix to the rest of the family instead of
 * leaving it as a one-off.
 *
 * The reset itself is deliberately NOT rewritten with :where(). That would
 * zero its specificity globally and let EVERY class rule beat it at once, a
 * blast radius across 244 templates that nothing here has measured. Raising
 * the components to (0,2,0) changes only the rules named.
 * ═══════════════════════════════════════════════════════════════════════ */
.alt2-body .alt2-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  height: var(--control-h);
  padding: 0 var(--sp-4);
  border: 1px solid var(--alt-action-quiet-line);
  border-radius: var(--r-md);
  background: var(--alt-action-quiet-bg);
  color: var(--alt-action-quiet-fg);
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  transition: background var(--dur-1) var(--alt-ease-in);
}

.alt2-body .alt2-btn:hover { background: var(--alt-bg-surface-2); }

/* `.alt2-body a { color: inherit }` in the reset has specificity (0,1,1) and
   would beat a bare `.alt2-btn--primary` (0,1,0) — an anchor styled as the
   primary button then rendered dark ink on the dark action fill, i.e. an
   invisible CTA. Scoping these under .alt2-body raises them to (0,2,0). Found
   by rendering it; the rule itself was correct and unreachable. */
.alt2-body .alt2-btn--primary {
  border-color: var(--alt-action-bg);
  background: var(--alt-action-bg);
  color: var(--alt-action-fg);
}

.alt2-body .alt2-btn--primary:hover  { background: var(--alt-action-bg-hover); }
.alt2-body .alt2-btn--primary:active { background: var(--alt-action-bg-active); }

/* ALT-790. `.alt2-btn--ghost` had NO rule at all, so all 68 markup call sites
   across 36 files (MEASURED 2026-08-21; the count agrees with the pin in
   _check_shell_v2_dead_classes.KNOWN_DEAD_CALLSITES) rendered as a plain
   `.alt2-btn`. That entry records three roles, and only two of them are a
   naming gap:
     (a) secondary buttons / filter resets  — cosmetic
     (b) back-links in the subhead row      — a nav link at full button weight
     (c) DESTRUCTIVE submits sitting beside a plain save, where "renders
         pixel-identical" means a reader cannot tell "Ukloni" (deletes a bank
         account, bank_accounts_maintenance.html:227) from "Spremi" next to it.
   Ghost is the quiet role: no border, secondary ink. That alone makes (a), (b)
   and (c) visually distinct from a plain button, which is the defect. It is NOT
   the whole fix for (c) — a destructive action needs a danger signal, not just
   a quieter one; see `--danger` below and ALT-796. Blueprint §4 defines ghost
   as `background: transparent; color: text-secondary`, ported here verbatim. */
.alt2-body .alt2-btn--ghost {
  border-color: transparent;
  background: transparent;
  color: var(--alt-text-2);
}
.alt2-body .alt2-btn--ghost:hover {
  background: var(--alt-bg-surface-2);
  color: var(--alt-text-1);
}

/* ALT-796. The v2 shell had no destructive variant AT ALL, so every
   irreversible action borrowed `--ghost` (role (c) above) or a plain button.
   component-blueprints.md §4 does not define one either — it ships primary /
   secondary / ghost / on-backdrop only — so this is an ADDITION to the design
   system, recorded in DECISIONS.md, not a port of an existing blueprint rule.
   Outlined rather than filled on purpose: a filled red button competes with the
   primary and would break "one decision per screen", and a destructive action
   should be legible, not inviting. The word still carries the state — the badge
   rule ("state is never colour-only") applies to buttons too.
   NOTE: this variant is defined but not yet WORN by any template. Phase 1
   freezes templates/v2/**; migrating the role-(c) call sites from `--ghost` to
   `--danger` is a template change and is tracked separately. */
.alt2-body .alt2-btn--danger {
  border-color: var(--alt-negative-fill);
  background: transparent;
  color: var(--alt-negative-text);
}
.alt2-body .alt2-btn--danger:hover { background: var(--alt-negative-quiet); }

.alt2-body .alt2-input, .alt2-body .alt2-select, .alt2-body .alt2-textarea {
  width: 100%;
  height: var(--control-h);
  padding: 0 var(--sp-3);
  border: 1px solid var(--alt-line-strong);
  border-radius: var(--r-md);
  background: var(--alt-bg-surface-1);
  color: var(--alt-text-1);
  font-size: 13px;
}

.alt2-textarea { height: auto; padding: var(--sp-2) var(--sp-3); }
.alt2-select { width: auto; }

/* Text inputs keep `:focus` rather than `:focus-visible` deliberately: a
   caret sitting in a field is a focus the user should see however they got
   there, including by mouse. It is the same RING, though — §0.3 law 1 is
   about there being one ring, not about one trigger. */
.alt2-input:focus, .alt2-select:focus, .alt2-textarea:focus {
  outline: 2px solid var(--alt-focus-ring);
  outline-offset: 2px;
}

.alt2-label {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
  font-size: 12px;
  line-height: 18px;
  font-weight: 500;
  color: var(--alt-text-2);
}

.alt2-required { color: var(--alt-negative-text); }

/* ── 7. Tables — the hero of a financial product ──────────────────────
 * Hairline, never shadow. Every figure tabular, right-aligned, decimal
 * aligned down the column. Colour never lands on a digit.
 * ------------------------------------------------------------------- */
.alt2-tablewrap {
  border: 1px solid var(--alt-line);
  border-radius: var(--r-lg);
  background: var(--alt-bg-surface-1);
  overflow-x: auto;
}

/* SEEN at 375x812 on 2026-08-14, not reasoned: every cell is `nowrap`, so a
   four-column table always overflows a phone — and macOS/iOS draw an OVERLAY
   scrollbar that is invisible until you already scroll. The money column and
   the total row sat off-screen with nothing on the page saying so, on a
   product whose whole premise is a legible column of money.
   The fix is the platform's own affordance made permanent, not a gradient
   fade: Uredno forbids gradients on surfaces, and a scrollbar is a CONTROL
   rather than decoration. Kept to touch widths so the desktop overlay
   behaviour is untouched. The deeper question — whether a wide financial
   table should be a table at all at 375px — is filed, not answered here. */
@media (max-width: 767.98px) {
  .alt2-tablewrap {
    scrollbar-width: thin;
    scrollbar-color: var(--alt-line-strong) transparent;
  }
  .alt2-tablewrap::-webkit-scrollbar { height: 6px; }
  .alt2-tablewrap::-webkit-scrollbar-track { background: transparent; }
  .alt2-tablewrap::-webkit-scrollbar-thumb {
    background: var(--alt-line-strong);
    border-radius: var(--r-pill);
  }
}

.alt2-table th, .alt2-table td {
  height: var(--row-h);
  padding: 0 var(--sp-4);
  border-bottom: 1px solid var(--alt-line);
  white-space: nowrap;
}

/* ALT-805. `text-align` lives here, at ZERO specificity, and NOT in the rule
   above. It used to sit inside `.alt2-table th, .alt2-table td` — specificity
   (0,1,1) — where it beat `.alt2-t--right` / `--center` / `--num` (0,1,0) no
   matter what order the file was in. Every money column in the tree rendered
   LEFT-aligned, which is a regression against legacy (`altoria-operations.css`
   wins the same fight with `:where(th.ops-right, td.ops-right)`), and it kills
   the first of Uredno's six craft signals: the straightness of a column of
   money. `:where()` contributes no specificity at all, so this is a true
   default that ANY modifier overrides — including modifiers added later, which
   is why this beats bolting on three higher-specificity overrides. */
:where(.alt2-table th, .alt2-table td) { text-align: left; }

.alt2-table thead th {
  height: var(--row-h-head);
  background: var(--alt-bg-surface-2);
  color: var(--alt-text-2);
  font-size: 11px;
  line-height: 16px;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  position: sticky;
  top: 0;
}

.alt2-table tbody tr:last-child td { border-bottom: 0; }
.alt2-table tbody tr:hover { background: var(--alt-bg-surface-2); }

.alt2-t--left   { text-align: left; }
.alt2-t--right  { text-align: right; }
.alt2-t--center { text-align: center; }

.alt2-body .alt2-t--num {
  text-align: right;
  font-variant-numeric: tabular-nums;
  color: var(--alt-text-1);
}

/* Totals reconcile with their parts on the same screen — one of the six
   things the entire premium budget buys. Weight 600, never 700. */
.alt2-total td {
  font-weight: 600;
  border-top: 1px solid var(--alt-line-strong);
  background: var(--alt-bg-surface-2);
}

.alt2-body .alt2-link { color: var(--alt-accent); text-decoration: underline; text-underline-offset: 2px; }
.alt2-rowactions { white-space: nowrap; }

/* `0,00 €` and `–` are different facts and must never collapse: zero is a
   measured zero in muted ink, the en-dash is absence in the empty token. */
.alt2-empty-dash { color: var(--alt-text-empty); }

/* ── 8. Badges — STANJE = oznaka + IKONA + kontekst ───────────────────
 *
 * The blueprint's §6 is unambiguous: "State is label + icon + context. Colour
 * alone never carries meaning." This component held only the LABEL half of
 * that, and so did the gate: `_check_shell_v2_uredno.py` rule 5 asserts a badge
 * carries a word, and nothing asserted it carries a glyph. MEASURED on the C31
 * tree: 611 `.alt2-badge` call sites, 393 of them state-bearing, and 3 with an
 * icon. State was label + colour.
 *
 * Two things had to change before a single call site could be fixed. This is
 * the first: the component could not RENDER an icon correctly — no `gap`, so a
 * glyph would butt against its word, and `.alt2-ico`'s own 20px rule would size
 * it to nearly the badge's whole 22px height. `.alt2-badge .alt2-ico` already
 * outranks the bare `.alt2-ico` on specificity (two classes to one), so the
 * `.alt2-body` prefix here is the house rule rather than the fix — and the size
 * was confirmed by getComputedStyle on the live page, not by reading the
 * cascade (DEC-20). The second is the `alt2_badge()` macro in v2/_badges.html,
 * which is what puts the right glyph on the right state in ONE place.
 *
 * 12px is the blueprint's `--size-icon-xs`; the badge is 22px tall against the
 * blueprint's 24px, which is §3.13 drift and deliberately NOT corrected here. */
.alt2-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  height: 22px;
  padding: 0 var(--sp-2);
  border-radius: var(--r-pill);
  background: var(--alt-bg-surface-2);
  color: var(--alt-text-2);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.02em;
}

.alt2-badge--ok      { background: var(--alt-positive-quiet); color: var(--alt-positive-text); }
.alt2-body .alt2-badge--overdue { background: var(--alt-negative-quiet); color: var(--alt-negative-text); }
.alt2-badge--soon    { background: var(--alt-warning-quiet);  color: var(--alt-warning-text); }
.alt2-body .alt2-badge--notice  { background: var(--alt-notice-quiet);   color: var(--alt-notice-text); }

.alt2-body .alt2-badge .alt2-ico { width: 12px; height: 12px; }

/* ── 9. Empty state — one Croatian sentence of ≤12 words naming what is
 * empty and why, plus exactly one action. No illustration. Human-written
 * empty states are one of the six things the premium budget buys, so
 * `Nema podataka.` is a defect, not a placeholder.
 * ------------------------------------------------------------------- */
.alt2-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-12) var(--sp-5);
  border: 1px solid var(--alt-line);
  border-radius: var(--r-lg);
  background: var(--alt-bg-surface-1);
  color: var(--alt-text-2);
  text-align: center;
}

.alt2-empty__icon { color: var(--alt-text-3); }

/* ── 9b. OBITELJI + ZNAČKA — family scoping and the tier-1 icon badge ──
 *
 * Blueprint §0.2 + §4. Two tiers of icon, and the conflict that looked like a
 * contradiction is dead: TIER 2 is the 24-grid line icon carrying
 * `currentColor` — the existing 42-symbol sprite in `templates/_icons.html`,
 * which STAYS and is `.alt2-ico`. TIER 1 is the brand's filled disc, authored
 * on a 100 grid at stroke 8.5, and it is `.alt2-iconwrap`.
 *
 * WHY THE LOCALS ARE `--alt-fam-*` AND NOT `--accent` / `--glyph` / `--disc`.
 * The blueprint names the three locals `--disc`, `--glyph`, `--accent`.
 * `--alt-accent` ALREADY EXISTS in this shell's 77-name API with a different
 * job — focus rings (.alt2-btn, .alt2-select, .info-tip) and link ink, four
 * consumers. A family class that set `--alt-accent` would silently retint
 * every focus ring inside that subtree, which is a colour change nobody asked
 * for and no gate would see. The three locals are therefore namespaced, and
 * the blueprint's rule is kept exactly: a family class sets THESE THREE and
 * nothing else in the system may set them.
 *
 * `--alt-fam-disc` is identical for all six BY DESIGN (§0.2): the plate is the
 * brand, the glyph is the family. `--alt-fam-glyph` is loud and NEVER carries
 * text; `--alt-fam-accent` is the READABLE tone and carries headings, spines and
 * rules. Its contrast claim is SURFACE-QUALIFIED, and an earlier version of this
 * comment was not — it said ">= 4.5:1 both themes" flat. Measured WCAG, all six
 * light accents: 4.50-4.56:1 on `--alt-bg-surface-1` #FFFFFF (the card, which is
 * where the spine actually renders) but 4.38-4.43:1 on surface-3, 4.17-4.22:1 on
 * surface-2 and 4.07-4.11:1 on the page canvas #F1F4F1. So the guarantee holds on
 * the surface it ships on and NOT on the canvas; do not move an accent onto the
 * page background on the strength of this line. They are not substitutes — swapping them breaks
 * the contrast guarantee in opposite directions. */

/* The defaults. A badge with no family class must not render BLACK: an
   unresolved var() inside an SVG presentation attribute computes to the
   initial value, which IS black, with no console error and no fallback — the
   "row of black coins" the design system's own proof run caught. Declaring the
   three locals on `.alt2-body` means they always resolve, and because custom
   properties resolve on the NEAREST ancestor that sets them, any
   `.alt2-fam-*` class still wins regardless of specificity.
   FRESH is the neutral glyph: it is theme-constant (uredno deliberately leaves
   the brand reference tones un-re-derived in dark) and #BAFAC0 on the #003320
   plate measures 11.73:1 — DEC-2's figure of record. */
.alt2-body {
  --alt-fam-disc: var(--alt-disc-fill);
  --alt-fam-glyph: var(--alt-ref-fresh);
  --alt-fam-accent: var(--alt-accent);
  /* NOT a family local — the ring varies by SURFACE, never by family, so it
     is set here and overridden in the chrome. §0.2's "a family class sets
     THESE THREE and nothing else may set them" is kept exactly. */
  --alt-fam-ring: var(--alt-disc-ring);
}

.alt2-body .alt2-fam-novac {
  --alt-fam-disc: var(--alt-disc-fill);
  --alt-fam-glyph: var(--alt-glyph-novac);
  --alt-fam-accent: var(--alt-accent-novac);
}
.alt2-body .alt2-fam-dokumenti {
  --alt-fam-disc: var(--alt-disc-fill);
  --alt-fam-glyph: var(--alt-glyph-dokumenti);
  --alt-fam-accent: var(--alt-accent-dokumenti);
}
.alt2-body .alt2-fam-drzava {
  --alt-fam-disc: var(--alt-disc-fill);
  --alt-fam-glyph: var(--alt-glyph-drzava);
  --alt-fam-accent: var(--alt-accent-drzava);
}
.alt2-body .alt2-fam-ljudi {
  --alt-fam-disc: var(--alt-disc-fill);
  --alt-fam-glyph: var(--alt-glyph-ljudi);
  --alt-fam-accent: var(--alt-accent-ljudi);
}
.alt2-body .alt2-fam-banka {
  --alt-fam-disc: var(--alt-disc-fill);
  --alt-fam-glyph: var(--alt-glyph-banka);
  --alt-fam-accent: var(--alt-accent-banka);
}
.alt2-body .alt2-fam-rizik {
  --alt-fam-disc: var(--alt-disc-fill);
  --alt-fam-glyph: var(--alt-glyph-rizik);
  --alt-fam-accent: var(--alt-accent-rizik);
}

/* §4 — the badge. A CONTAINER around a glyph, never a redraw of one.
   THE RING IS DRAWN BY THE SYMBOL, not by CSS, and that is a deliberate
   departure from the blueprint's `box-shadow: 0 0 0 1px var(--disc-ring)`:
   `_check_shell_v2_isolation.py` allows a box-shadow only on the overlay layer
   (submenu, modal) plus the one named carousel marker, and it cannot tell a
   1px spread ring from an elevation — the very thing its message says
   everything else must be. Weakening a shipped gate to land a ring would be a
   bad trade, and an `outline` on an <svg> box is a worse one. A `<circle
   r="49">` inside the symbol is exact by construction, scales with the badge
   at every size, and needs no CSS at all. */
.alt2-body .alt2-iconwrap {
  display: block;
  flex: 0 0 auto;
  aspect-ratio: 1;
  inline-size: 30px;                    /* size.icon.disc */
  block-size: 30px;
  border-radius: 50%;
}
.alt2-body .alt2-iconwrap--sm { inline-size: 25px; block-size: 25px; }
.alt2-body .alt2-iconwrap--lg { inline-size: 34px; block-size: 34px; }
.alt2-body .alt2-iconwrap--xl { inline-size: 46px; block-size: 46px; }

/* §4 "Chrome override" — MANDATORY, and the only permitted change to the
   plate colour: a CORE plate on the CORE field is invisible, because they are
   the same colour. This is DEC-15's surface-affinity lesson applied before it
   bites rather than after: `.alt2-iconbtn` shipped white-on-white at 1.0:1 on
   the client portal because ONE class served both the chrome and the sheet.
   Bind by SURFACE. */
.alt2-body .alt2-masthead .alt2-iconwrap,
.alt2-body .alt2-rail .alt2-iconwrap {
  --alt-fam-disc: var(--alt-chrome-disc);
  --alt-fam-ring: var(--alt-chrome-disc-ring);
}

/* §4 "Glyph override" — C47, and it is the SAME surface-affinity lesson one
   layer down. `--alt-fam-glyph` is documented above as "loud and NEVER carries
   text", and its figure of record is DEC-2's 11.73:1 — measured ON THE #003320
   PLATE. That guarantee was owned by the plate, not by the glyph.

   C46 then adopted Daniel's monoline set, whose README rejects the plate
   outright ("no disc, no fat border"). Every `a-*` symbol now ships
   `fill="none"` with no `<circle r="384">`, which `_check_icon_source_of_truth`
   check 4e actively ENFORCES. So the plate is gone by design — and the loud
   glyph it was measured against landed straight on the white sheet:

       novac  #67FCA7  10.75:1 on the plate  ->  1.31:1 on #FFFFFF
       drzava #FCBC2F   8.28:1               ->  1.70:1
       ljudi  #E9B9FD   8.58:1               ->  1.64:1
       banka  #21C3AC   6.33:1               ->  2.22:1
       dokum. #78A3FB   5.64:1               ->  2.49:1
       rizik  #FB786B   5.35:1               ->  2.62:1

   All six BELOW the 3.0:1 AA non-text floor; novac at 1.31:1 is invisible.
   Daniel reported it as "icons missing" and he was reading the screen right.

   The fix uses the tone the system ALREADY designates readable rather than
   inventing one: `--alt-fam-accent` measures 4.50-4.56:1 on `--alt-bg-surface-1`
   and 4.07-4.11:1 on the page canvas — above the floor on both, and still
   per-family, so the family signal survives. §0.2's law is kept exactly: a
   family class still sets THOSE THREE and nothing else; this rule re-points one
   local BY SURFACE, which is what the chrome block above already does.

   TWO scopes, both deliberate.

   `.alt2-sheet` and not `.alt2-iconwrap`: the chrome is dark, and there the loud
   tone is the CORRECT one (5.35-10.75:1 on #003320); an unscoped rule would drag
   the badge down to the accent, which measures only 3.08-3.12:1 against the
   chrome — a downgrade on the one surface that was never broken.

   `:root:not([data-theme='dark'])` for the same reason one level out. In DARK the
   sheet's own pill is #0C1712, which is itself plate-like, so the original
   contract still holds there and the loud tone measures 6.98-14.00:1 — better
   than the accent's 4.51-4.53:1. Only the LIGHT sheet lost its dark backdrop, so
   only the light sheet is re-pointed. Written as `:not(dark)` rather than a
   `[data-theme='light']` rule because `:root` IS light (uredno.css:62) and an
   explicit light attribute is never set; and as a scope rather than a second
   `--alt-fam-glyph-loud` local because §0.2 says a family class sets THOSE THREE
   and nothing else may add to them.

   Measured on live :8003, transitions disabled (`.alt2-mod` animates its
   background, so a naive getComputedStyle reads a mid-transition colour and
   reports the wrong surface — the first pass of this measurement did exactly
   that). Worst family, light pill #FFFFFF: loud 1.31:1 -> accent 4.50:1. */
:root:not([data-theme='dark']) .alt2-body .alt2-sheet .alt2-iconwrap {
  --alt-fam-glyph: var(--alt-fam-accent);
}

/* ── 10. Cards, key-values, flash ─────────────────────────────────────── */
.alt2-card {
  border: 1px solid var(--alt-line);
  border-radius: var(--r-lg);
  background: var(--alt-bg-surface-1);
  padding: var(--sp-5);
}

/* ALT-875. Same defect, same cause and same remedy as `.alt2-btn--primary`
   twenty lines up — recorded again because it was found independently and the
   pair is the argument for the idiom.
   `.alt2-body h1 … h6 { margin: 0 }` (shell2.css:56-58) is specificity (0,1,1);
   a bare `.alt2-card__title` is (0,1,0). `.alt2-card__title` is written on a
   heading element, so the reset won and `margin-bottom` never applied: every
   card rendered its title hard against the first row of content.
   MEASURED 2026-08-21 via getComputedStyle on a live :8003 v2 page —
   marginBottom resolved to 0px on /centrala, /centrala/porez-tools,
   /centrala/place and /centrala/api-trosak, in BOTH themes.
   Scoping under .alt2-body raises this to (0,2,0) and it wins. The reset is not
   touched: rewriting it with :where() would zero its specificity globally and
   unmask every other override across 244 templates, which is a much larger
   blast radius than the defect. */
.alt2-body .alt2-card__title {
  /* 2 of the 753 call sites are <span>; a vertical margin does not apply to an
     inline box, so they measured a 2px line-box gap while the 751 heading sites
     measured 0. block makes the margin real for all of them. */
  display: block;
  /* OUTFIT carries the message and the character (brand foundation p9).
     Never mixed with the work face inside one role — "NE MIJEŠATI UNUTAR
     ISTE ULOGE". Only 400 and 700 are vendored, so a declared 500/600
     resolves by CSS font matching to a REAL file, never a
     synthetic weight — but NOT both to 700. For a desired weight of 500 the
     algorithm checks weights below 500 in descending order first, so 500 -> the
     400 file (Regular); only 600 -> 700 (Bold). Corrected 21.08.2026; DEC-4 and
     four copies of this comment claimed "500/600 -> 700". Declared weights stay 400/500/600 per the Uredno rule
     the isolation gate enforces. */
  font-family: 'Outfit', system-ui, -apple-system, 'Segoe UI', sans-serif;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin-bottom: var(--sp-3);
}

.alt2-kv {
  display: grid;
  grid-template-columns: minmax(140px, max-content) 1fr;
  gap: var(--sp-2) var(--sp-5);
  font-size: 13px;
}

.alt2-kv__k { color: var(--alt-text-2); }
.alt2-kv__v { color: var(--alt-text-1); font-variant-numeric: tabular-nums; }

/* ALT-805, second component — NOT a CSS defect, recorded here so nobody "fixes"
   it again. `.alt2-kv__v` sets no `text-align`, but it does not need to: a cell
   carrying `alt2-t--num` already resolves to right (measured — that rule is the
   only one setting alignment on it, so there is nothing to lose a cascade
   against). The real gap is in the TEMPLATES — of 644 `.alt2-kv__v` cells, 201
   pipe `| eur` and only 4 carry the modifier. Adding a CSS rule here would be an
   unearned element that changes nothing; the 201 cells need the class. */

/* Generation-neutral flash markup, shared with _flash_html() in main.py.
   Measured: the legacy `flash err` renders identical to body copy in this
   shell — same ink, no border, no background. An error that reads as page
   prose is one a user skims past believing the post succeeded. */
.alt2-flash {
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--alt-line);
  border-radius: var(--r-md);
  background: var(--alt-bg-surface-2);
  margin-bottom: var(--sp-4);
  font-size: 13px;
  line-height: 20px;
}

.alt2-flash strong { font-weight: 600; color: inherit; }
.alt2-flash a { color: inherit; text-decoration: underline; }

.alt2-flash--err  { border-color: #E7C4BA; background: var(--alt-negative-quiet); color: var(--alt-negative-text); }
.alt2-flash--warn { border-color: #EBDCB6; background: var(--alt-warning-quiet);  color: var(--alt-warning-text); }
.alt2-flash--info { border-color: #C9DAE8; background: var(--alt-notice-quiet);   color: var(--alt-notice-text); }
.alt2-flash--ok   { border-color: #C4E3C8; background: var(--alt-positive-quiet); color: var(--alt-positive-text); }

.alt2-msgblock { display: flex; gap: var(--sp-3); align-items: flex-start; }
.alt2-msgblock__mark {
  flex: 0 0 auto;
  width: 32px; height: 32px;
  border-radius: var(--r-pill);
  display: flex; align-items: center; justify-content: center;
  font-weight: 600;
  background: var(--alt-warning-mark);
  color: #FFFFFF;
}
.alt2-msgblock__body { flex: 1 1 auto; min-width: 0; }
.alt2-msgblock__heading { font-weight: 600; font-size: 13px; }
.alt2-msgblock__text { font-size: 13px; margin-top: var(--sp-1); }
.alt2-msgblock__matches { font-size: 12px; margin-top: var(--sp-2); color: var(--alt-text-2); }

.alt2-body .alt2-tag {
  display: inline-block;
  padding: 1px var(--sp-2);
  border: 1px solid var(--alt-line-strong);
  border-radius: var(--r-pill);
  font-size: 11px;
  margin-right: var(--sp-1);
}

/* ── 10b. Card head, meta and the family spine — blueprint §5 (C29) ────
 *
 * ADAPTED, not transcribed, and the difference is load-bearing. The
 * blueprint's `.card` carries NO padding: its `__head` and `__body` supply
 * `16 24 0` and `24` themselves. `.alt2-card` DOES carry padding
 * (var(--sp-5) = 20) and 780 markup call sites depend on it, so porting those
 * absolute paddings verbatim would double-pad every card that adopted a head.
 * The parts therefore carry RHYTHM inside the card's inset, not the inset.
 *
 * `alt2-card__body` (written without the leading dot ON PURPOSE — this gate
 * counts any `.name` token in this file, comments included, as a DEFINITION,
 * and a class defined by a sentence about it is exactly the silent no-op the
 * tree keeps finding) is deliberately NOT given a rule here. It is in
 * `_check_shell_v2_dead_classes.py`'s KNOWN_DEAD with the reason ".alt2-card
 * has padding; the inner element currently adds nothing" — and that reason is
 * still true under this block: the head owns the gap below itself, so the body
 * needs nothing. Inventing a rule to close a checklist item would be the
 * `.alt2-fields` mistake in reverse. The ratchet entry stays.
 * ------------------------------------------------------------------- */
.alt2-body .alt2-card__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  margin-bottom: var(--sp-4);
}
/* The title's own bottom margin (ALT-875) is the gap when it stands alone.
   Inside a head, the HEAD owns that gap — otherwise they add up. */
.alt2-body .alt2-card__head .alt2-card__title { margin-bottom: 0; }

.alt2-body .alt2-card__meta {
  color: var(--alt-text-3);
  font-size: 12px;
  font-weight: 500;
  white-space: nowrap;
}

/* §5 + §0.2 place 3 of 4: the spine and the header label of an overview card.
   Both take `--alt-fam-accent` — the READABLE family tone — and never
   `--alt-fam-glyph`, which is the loud one and never carries text. One family
   per card, never two. */
.alt2-body .alt2-card--spine {
  position: relative;
  overflow: hidden;
  padding-inline-start: calc(var(--sp-5) + 3px);
}
.alt2-body .alt2-card--spine::before {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  width: 3px;                            /* border.spine */
  background: var(--alt-fam-accent);
}
.alt2-body .alt2-card--spine .alt2-card__title { color: var(--alt-fam-accent); }

/* ── 10c. Table row-open affordance — blueprint §9 (C29) ───────────────
 *
 * MEASURED FIRST: all 54 `.alt2-rowactions` cells in the v2 tree carry TEXT,
 * none is icon-only. §9 wants the brand chevron, icon-only, "never the word" —
 * and names two carve-outs that keep their label (navigation cards where the
 * words carry the destination, and server-driven labels that vary per row).
 * Deciding which of the 54 fall under a carve-out is a per-cell reading of 49
 * templates, so the CONVERSION is filed, not done unattended. What ships here
 * is the capability plus the one thing that is live today:
 *
 *   ·  `.alt2-rowactions` had exactly `white-space: nowrap` and no layout, so
 *      two actions in one cell sat wherever the whitespace between the tags
 *      put them. It gets a real one — LIVE across all 54 cells.
 *   ·  `.alt2-row-open` is the icon-only control §9 specifies, ready for the
 *      conversion. It has no emitter today and that is stated rather than
 *      hidden. Its hit target is grown to 44px with an overlay, never by
 *      growing the 14px glyph (§0.3).
 * ------------------------------------------------------------------- */
.alt2-body .alt2-rowactions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--sp-3);
  white-space: nowrap;
}

.alt2-body .alt2-row-open {
  position: relative;
  display: inline-grid;
  place-items: center;
  inline-size: 28px;
  block-size: 28px;
  border-radius: var(--r-md);
  color: var(--alt-text-3);
  transition: color var(--dur-1) var(--alt-ease-in),
              background var(--dur-1) var(--alt-ease-in);
}
.alt2-body .alt2-row-open .alt2-ico { width: 14px; height: 14px; }
.alt2-body .alt2-row-open::after {
  content: "";
  position: absolute;
  inset: -8px;
  border-radius: inherit;
}
/* Hover is never the only channel (§0.3): the control is present and
   focusable at rest, the row hover only raises its ink. */
.alt2-body .alt2-table tbody tr:hover .alt2-row-open { color: var(--alt-text-1); }
.alt2-body .alt2-row-open:hover { background: var(--alt-bg-surface-2); color: var(--alt-text-1); }

/* ── 11. Overlays — the ONLY layer permitted a shadow ────────────────── */
/* THE FLYOUT — blueprint §3.11, and C29's answer to "wire it or delete it".
   These rules shipped complete, with a working mechanism in shell2.js, and
   ZERO emitters (measured: 0 across 255 v2 templates). They are now the
   picker's "Svi ekrani" list — see the reasoning at the emitter in
   v2/_base.html and DEC-17.
   The geometry MOVED: `top: 0; left: 100%` opened this to the RIGHT of its
   trigger, which is a rail flyout. §3.11 anchors it UNDER the bar, offset
   past the leading scroll control, so that is where it opens now. Nothing
   else could have depended on the old position — nothing emitted it. */
.alt2-submenu {
  position: absolute;
  /* Directly under the bar. The blueprint writes this as
     `calc(pill + space-2)` because its bar is pill-height; ours is a real
     element with `position: relative`, so 100% is the same number without
     restating a height in two places. */
  inset-block-start: 100%;
  /* §3.11 clears the leading control: bar padding + control + gap.
     C41 / ALT-963 — that constant is now only the FALLBACK. It was correct
     while one shared panel existed; with one panel per domain, every panel
     resolved the same constant against the same ancestor and the seventh
     pill's menu opened under the first. `shell2.js` writes `--alt2-fly-x`
     from the trigger's measured position on open and on scroll. The constant
     stays so the menu still lands somewhere sane with scripting off — the
     pills are ordinary links either way. */
  inset-inline-start: var(--alt2-fly-x, calc(var(--sp-5) + var(--control-h) + var(--sp-3)));
  z-index: var(--z-popover);
  width: 258px;                          /* size.layout.flyout-width */
  max-height: 60vh;
  overflow-y: auto;
  padding: var(--sp-2);
  border: 1px solid var(--alt-line);
  border-radius: var(--r-lg);            /* 20 */
  background: var(--alt-bg-surface-3);
  box-shadow: var(--alt-e1);
}

.alt2-submenu[hidden] { display: none; }

/* §3.11. 280ms is the design system's "change" duration; the reduced-motion
   override in uredno.css collapses --dur-3 to 1ms, so this disappears rather
   than being replaced by something else. */
.alt2-submenu:not([hidden]) { animation: alt2-fly-in var(--dur-3) var(--alt-ease-in); }
/* Stops are written 0%/100%, not from/to. `_check_shell_v2_isolation.py`
   parses every `sel {` in this file and fails a bare lowercase word as an
   unscoped element selector that would restyle the legacy tree — `from` and
   `to` look exactly like one. Percentages say the same thing and cannot be
   mistaken for an element. */
@keyframes alt2-fly-in {
  0%   { opacity: 0; transform: translateY(-5px); }
  100% { opacity: 1; transform: none; }
}

.alt2-submenu__title {
  padding: var(--sp-2) var(--sp-3) var(--sp-1);
  color: var(--alt-text-3);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* §3.11 row: 12px padding, 12px radius. Scoped, because `.alt2-body a` is
   (0,1,1) and a bare `.alt2-submenu__link` is (0,1,0) — the rule that has now
   cost this tree three separate rounds. */
.alt2-body .alt2-submenu__link {
  display: block;
  padding: var(--sp-3);
  border-radius: var(--r-md);
  color: var(--alt-text-1);
  font-size: 13px;
  transition: background var(--dur-1) var(--alt-ease-in);
}

.alt2-body .alt2-submenu__link:hover { background: var(--alt-bg-surface-2); }
.alt2-body .alt2-submenu__link--on   { background: var(--alt-selected); font-weight: 600; }

.alt2-modal {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-5);
  background: var(--alt-bg-scrim);
}

.alt2-modal[hidden] { display: none; }

.alt2-modal__card {
  width: min(520px, 100%);
  max-height: 90dvh;
  overflow-y: auto;
  padding: var(--sp-5);
  border-radius: var(--r-xl);
  background: var(--alt-bg-surface-1);
  box-shadow: var(--alt-e2);
}

.alt2-modal__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--sp-4);
  font-weight: 600;
}

.alt2-modal .alt2-iconbtn { color: var(--alt-text-2); }
.alt2-modal .alt2-iconbtn:hover { background: var(--alt-bg-surface-2); color: var(--alt-text-1); }

/* ── 12. Forms, filters, misc ─────────────────────────────────────────── */
.alt2-formscreen { max-width: 760px; }
/* `min-width: 0` is load-bearing, not tidiness. A grid item defaults to
   `min-width: auto`, i.e. it refuses to shrink below its content's min-content
   width — so a wide table inside a card inside .alt2-fields pushes the COLUMN
   wider instead of scrolling inside its own `.alt2-tablewrap { overflow-x:
   auto }`. MEASURED 2026-08-14 on /centrala/audit-log: the grid column resolved
   to 2564px against a 1440px viewport, dragging the cards and their headings
   off-screen with it. Same family as the `min-height: 0` the sheet already
   needs for its vertical scroller — the horizontal axis needed the twin and
   did not have it. */
.alt2-fields { display: grid; gap: var(--sp-4); min-width: 0; }
.alt2-fields > * { min-width: 0; }
.alt2-field { display: flex; flex-direction: column; gap: var(--sp-1); }

.alt2-formbar {
  display: flex;
  justify-content: flex-end;
  gap: var(--sp-2);
  margin-top: var(--sp-6);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--alt-line);
}

.alt2-list__toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  margin-bottom: var(--sp-4);
  flex-wrap: wrap;
}

.alt2-list__filters, .alt2-list__actions {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex-wrap: wrap;
}

.alt2-inlineform { display: flex; align-items: center; gap: var(--sp-2); margin: 0; }
.alt2-filterlinks { display: flex; gap: var(--sp-2); flex-wrap: wrap; }

.alt2-body .alt2-chip {
  display: inline-flex;
  align-items: center;
  height: 28px;
  padding: 0 var(--sp-3);
  border: 1px solid var(--alt-line);
  border-radius: var(--r-pill);
  color: var(--alt-text-2);
  font-size: 12px;
}

.alt2-body .alt2-chip--on {
  background: var(--alt-selected);
  border-color: var(--alt-selected-marker);
  color: var(--alt-text-1);
  font-weight: 600;
}

/* ── Business Feed — ALT-945 ──────────────────────────────────────────
   Three cards at the top of a role's home answering ONE question: "what
   needs me today". Each is icon + title + one sentence + one link.

   WHY A NEW GRID INSTEAD OF REUSE. Measured before writing this:
   `grid-template-columns` appears in this file only at :208/:223 (shell
   chrome), :1270 (.alt2-kv) and :1713 (mobile shell). The v2 tree has NO
   multi-column CONTENT grid — `.alt2-fields` (:1552) is a single column.
   Three cards across therefore cannot be had by reuse.

   It is NOT the carousel and must never read as one. The carousel carries
   the SCREENS of the active domain; the feed carries WORK. */
.alt2-feed {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--sp-4);
  margin-bottom: var(--sp-5);
}
.alt2-feed > * { min-width: 0; }

@media (max-width: 900px) {
  .alt2-feed { grid-template-columns: 1fr; }
}

.alt2-body .alt2-feed__title {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}

/* ── Quick actions — ALT-946 ──────────────────────────────────────────
   One action = one click, no dropdowns.

   DELIBERATELY A THIRD SHAPE. `.alt2-carousel__item` (:688) is a bare 34px
   <a> with NO border on a transparent ground — it means "go somewhere".
   `.alt2-chip` (:1584) is the FILTER idiom — it means "narrow what you
   see". An action is neither, so it gets its own shape: bordered pill with
   a leading glyph. Collapsing any two of the three is precisely the defect
   the QBO analysis names in Altoria today ("sve iste težine") — the reader
   loses the difference between navigating and doing.

   NOT `.alt2-btn--primary`: `_check_shell_v2_uredno.py:103-106` allows one
   primary per template ("one decision per screen"), and a ROW of primaries
   would mean none of them is the decision. */
.alt2-quickacts {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin-bottom: var(--sp-5);
}

.alt2-body .alt2-quickact {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  height: 32px;
  padding: 0 var(--sp-3);
  border: 1px solid var(--alt-line);
  border-radius: var(--r-pill);
  background: var(--alt-bg-surface-1);
  color: var(--alt-text-1);
  font-size: 13px;
  text-decoration: none;
}

.alt2-body .alt2-quickact:hover { border-color: var(--alt-accent); }

.alt2-body .alt2-quickact .alt2-ico { width: 14px; height: 14px; }

.alt2-body .alt2-lede { color: var(--alt-text-2); font-size: 13px; margin-bottom: var(--sp-4); }
.alt2-body .alt2-hint { color: var(--alt-text-2); font-size: 12px; }
.alt2-body .alt2-mono { font-family: ui-monospace, 'JetBrains Mono', Menlo, monospace; }

/* Free text a HUMAN typed, where the line breaks are part of the datum.
   The v2 tree carried no white-space rule at all, so a note typed across six
   lines of a textarea rendered as one unbroken run — a capability the legacy
   tree had (`white-space: pre-wrap`) and the migration dropped. Contract
   parity cannot catch this: it compares FORM contracts, not CSS.
   MEASURED 2026-08-14, before adding this: of the five migrated screens whose
   legacy twin used pre-wrap, only one loses anything. `nightly` renders its
   traceback in <pre> (already preserved), `agent_examples` snippets come from
   json.dumps with no indent, all 30 taxonomy `posting_hint` values are single
   line, and biljeske's `_default_body` emits none. So this is for the one real
   case — and for the next screen that renders a textarea's contents.
   Use it ONLY for human free text; machine identifiers stay .alt2-mono. */
.alt2-prose { white-space: pre-wrap; overflow-wrap: anywhere; }
.alt2-upload { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; margin: 0; }
.alt2-upload .alt2-input[type='file'] { width: auto; }

.alt2-ico { width: 20px; height: 20px; stroke: currentColor; fill: none; flex: 0 0 auto; }

.alt2-sr {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ALT-912 (C32) — the screen-reader label was scrolling the DOCUMENT.
 *
 * `/centrala/pr-ras` scrolled horizontally to exactly 941px at BOTH 375px and
 * 768px. A constant width across two viewports means a fixed-width child, so
 * the search went looking for one — and there is none. The chain from the wide
 * `<table>` up to `<body>` is entirely well behaved: `.alt2-tablewrap` scrolls
 * (width 301, scrollWidth 945), every ancestor measures the viewport, and
 * `body.scrollWidth` is 375. Only `<html>` read 941.
 *
 * MEASURED, not reasoned: hiding `.alt2-sr` dropped `html.scrollWidth` from
 * 941 to 375, and the last of the nine spans sits at `right = 940.8`. That is
 * the 941.
 *
 * The mechanism. The rule above takes the span out of flow with
 * `position: absolute` but never says WHERE, so `left`/`top` stay `auto` and
 * the box resolves to its STATIC position — which, for a label inside a 945px
 * table, is up to 940px from the left. Worse, `offsetParent` for eight of the
 * nine is `BODY`: nothing between the span and the body establishes a
 * containing block, so `.alt2-tablewrap { overflow-x: auto }` does NOT clip
 * them. An out-of-flow box is clipped by its containing-block chain, and the
 * scroller is not on it. The table is contained; its labels are not, and they
 * drag the document the table itself could never drag.
 *
 * Pinning to the containing block's origin removes the only variable. The span
 * stays 1x1, still clipped to nothing, still read in DOM order — assistive
 * technology follows the DOM, never the box — and can no longer report a
 * position 940px to the right of a viewport 375px wide. `clip-path` is added
 * beside the legacy `clip` because `clip` is deprecated and ignored by some
 * engines, which would leave a 1px artefact at the origin.
 *
 * Scoped `.alt2-body .alt2-sr` per DEC-20: the base `.alt2-sr` rule above is
 * shared with surfaces outside the v2 shell, and a modifier that loses to its
 * own base rule is exactly the trap 981f123e cost a session. Higher
 * specificity, v2 only, and the cascade is MEASURED on the live page rather
 * than asserted by a static gate that cannot see it. */
.alt2-body .alt2-sr {
  left: 0;
  top: 0;
  clip-path: inset(50%);
}

/* Info tip — the EXISTING global component (CLAUDE.md), restated here only
   because portal.css is not loaded in this tree. Outline circled "i",
   currentColor, transparent fill — never a filled badge. */
.alt2-body .info-tip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px; height: 16px;
  border: 1.5px solid currentColor;
  border-radius: var(--r-pill);
  background: transparent;
  color: var(--alt-text-3);
  font-size: 10px;
  font-style: italic;
  font-weight: 600;
  cursor: help;
  flex: 0 0 auto;
}


.alt2-tabbar { display: none; }

.alt2-body .alt2-fab {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px; height: 48px;
  border-radius: var(--r-pill);
  background: var(--alt-action-bg);
  color: var(--alt-action-fg);
}

/* ── 13. Below 768px the layering goes away entirely ──────────────────
 * Field colour off, sheet radius 0, inset 0, rail off-canvas. The stack is a
 * desktop affordance; keeping it on a 390px viewport is pure cost.
 * ------------------------------------------------------------------- */
@media (max-width: 768px) {
  .alt2-shell {
    grid-template-columns: 1fr;
    grid-template-areas: 'head' 'sheet';
    background: var(--alt-bg-page);
  }

  .alt2-masthead { background: var(--alt-ref-logo); }
  .alt2-masthead__title { display: none; }
  .alt2-rail { display: none; }

  .alt2-sheet { margin: 0; border-radius: 0; }
  .alt2-scroll { padding: var(--sp-4); }
  .alt2-carouselbar, .alt2-subhead { padding-left: var(--sp-4); padding-right: var(--sp-4); }
  .alt2-formscreen { max-width: none; }

  /* The client shell is THREE bands below 768px, and until C31 it said so
     nowhere. `.alt2-shell--tabbar` is emitted on every `client_user` page from
     `v2/_base.html:193` and carried ZERO css rules — its C4 rule
     (`.alt2-shell--tabbar .alt2-rail { display: none }`) was dropped in the C6
     Uredno rewrite, which hides the rail for EVERY role at this width, making
     that exact rule redundant. Restoring it verbatim would have been a no-op.
     MEASURED instead (client_user, 375x812): grid-template-rows resolved to
     `60px 687px 65px` against grid-template-areas of only `"head" "sheet"` —
     the tab bar was landing in an IMPLICIT third row. It renders correctly, by
     accident: nothing declares that row, so a fourth child of `.alt2-shell`, or
     any later `grid-template-rows` override, silently relocates the whole
     navigation. The modifier now declares the band it is named for. */
  .alt2-body .alt2-shell--tabbar {
    grid-template-areas: 'head' 'sheet' 'tabs';
    grid-template-rows: var(--masthead-h) 1fr auto;
  }
  .alt2-body .alt2-shell--tabbar > .alt2-tabbar { grid-area: tabs; }

  /* Bottom tab bar replaces the rail on the client portal. */
  .alt2-tabbar {
    position: sticky;
    bottom: 0;
    z-index: var(--z-masthead);
    display: flex;
    align-items: center;
    justify-content: space-around;
    gap: var(--sp-2);
    padding: var(--sp-2) var(--sp-3);
    border-top: 1px solid var(--alt-line);
    background: var(--alt-bg-surface-1);
  }

.alt2-body .alt2-tabbar__item {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    font-size: 10px;
    color: var(--alt-text-2);
  }

.alt2-body .alt2-tabbar__item--on { color: var(--alt-positive-text); font-weight: 600; }
}


/* ── 14. §0.3 LAW 2 — disabled, LAST so it beats every component default ──
 * See the note in §1b. This block is identical to the one §0.3 specifies; only
 * its POSITION is load-bearing, and the position was chosen by measurement
 * rather than by reading the cascade. */
/* LAW 2 — disabled: 30% opacity, no motion, no pointer feedback.
 *
 * `aria-disabled` is covered alongside `[disabled]` because the two are not
 * interchangeable: `[disabled]` removes the control from the tab order and
 * from the accessibility tree's interactive set, `aria-disabled` KEEPS it
 * focusable and announced. `pointer-events: none` suppresses only pointer
 * hit-testing, so an aria-disabled control stays keyboard-reachable and
 * screen-reader-announced exactly as intended — which is the whole reason a
 * component would choose aria-disabled over disabled. */
.alt2-body :where(button, a, input, select, textarea, [tabindex])[disabled],
.alt2-body :where(button, a, input, select, textarea, [tabindex])[aria-disabled="true"] {
  opacity: var(--alt-opacity-disabled);
  cursor: default;
  transform: none;
  pointer-events: none;
}

/* ── Document embeds (C37e, ALT-942 follow-on) ─────────────────────────
   `klijent/document_show` shows the original inline so the client can always
   LOOK at the document without downloading it. Two shapes, one rule each.
   These exist as CLASSES rather than inline styles because
   `_check_shell_v2_render` rejects inline `style=` in the v2 tree — and a
   class with no rule is caught by the dead-class ratchet, so the rule has to
   be here, not implied. */
.alt2-frame {
  width: 100%;
  height: 720px;
  border: 0;
  border-radius: var(--alt-radius-md, 10px);
  background: var(--alt-surface-quiet, transparent);
}
.alt2-preview {
  max-width: 100%;
  max-height: 80vh;
  display: block;
  margin: 0 auto;
  border-radius: var(--alt-radius-md, 10px);
}

/* ══ GENERATED by design-system/emit_gallery.py — swatch chips ══ START */
/* 49 chip rules, one per colour token in design-system/token-map.json.
   GENERATED by design-system/emit_gallery.py — do not hand-edit this
   region; edit the token map and re-run the emitter. Inline styles are
   not an option here (_check_shell_v2_render.py rejects them) and a
   separate stylesheet is not either (_check_shell_v2_dead_classes.py
   only reads shell2.css and uredno.css). */
.alt2-swatch__chip--alt-accent { background: var(--alt-accent); }
.alt2-swatch__chip--alt-accent-banka { background: var(--alt-accent-banka); }
.alt2-swatch__chip--alt-accent-dokumenti { background: var(--alt-accent-dokumenti); }
.alt2-swatch__chip--alt-accent-drzava { background: var(--alt-accent-drzava); }
.alt2-swatch__chip--alt-accent-ljudi { background: var(--alt-accent-ljudi); }
.alt2-swatch__chip--alt-accent-novac { background: var(--alt-accent-novac); }
.alt2-swatch__chip--alt-accent-rizik { background: var(--alt-accent-rizik); }
.alt2-swatch__chip--alt-action-bg { background: var(--alt-action-bg); }
.alt2-swatch__chip--alt-action-bg-hover { background: var(--alt-action-bg-hover); }
.alt2-swatch__chip--alt-action-fg { background: var(--alt-action-fg); }
.alt2-swatch__chip--alt-action-quiet-fg { background: var(--alt-action-quiet-fg); }
.alt2-swatch__chip--alt-action-quiet-line { background: var(--alt-action-quiet-line); }
.alt2-swatch__chip--alt-bg-page { background: var(--alt-bg-page); }
.alt2-swatch__chip--alt-bg-surface-1 { background: var(--alt-bg-surface-1); }
.alt2-swatch__chip--alt-bg-surface-2 { background: var(--alt-bg-surface-2); }
.alt2-swatch__chip--alt-bg-surface-3 { background: var(--alt-bg-surface-3); }
.alt2-swatch__chip--alt-chrome-disc { background: var(--alt-chrome-disc); }
.alt2-swatch__chip--alt-chrome-disc-ring { background: var(--alt-chrome-disc-ring); }
.alt2-swatch__chip--alt-disc-fill { background: var(--alt-disc-fill); }
.alt2-swatch__chip--alt-disc-ring { background: var(--alt-disc-ring); }
.alt2-swatch__chip--alt-focus-ring { background: var(--alt-focus-ring); }
.alt2-swatch__chip--alt-focus-ring-chrome { background: var(--alt-focus-ring-chrome); }
.alt2-swatch__chip--alt-glyph-banka { background: var(--alt-glyph-banka); }
.alt2-swatch__chip--alt-glyph-dokumenti { background: var(--alt-glyph-dokumenti); }
.alt2-swatch__chip--alt-glyph-drzava { background: var(--alt-glyph-drzava); }
.alt2-swatch__chip--alt-glyph-ljudi { background: var(--alt-glyph-ljudi); }
.alt2-swatch__chip--alt-glyph-novac { background: var(--alt-glyph-novac); }
.alt2-swatch__chip--alt-glyph-rizik { background: var(--alt-glyph-rizik); }
.alt2-swatch__chip--alt-line { background: var(--alt-line); }
.alt2-swatch__chip--alt-line-strong { background: var(--alt-line-strong); }
.alt2-swatch__chip--alt-negative-fill { background: var(--alt-negative-fill); }
.alt2-swatch__chip--alt-negative-text { background: var(--alt-negative-text); }
.alt2-swatch__chip--alt-notice-text { background: var(--alt-notice-text); }
.alt2-swatch__chip--alt-positive-fill { background: var(--alt-positive-fill); }
.alt2-swatch__chip--alt-positive-mark { background: var(--alt-positive-mark); }
.alt2-swatch__chip--alt-positive-text { background: var(--alt-positive-text); }
.alt2-swatch__chip--alt-ref-depth { background: var(--alt-ref-depth); }
.alt2-swatch__chip--alt-ref-forest { background: var(--alt-ref-forest); }
.alt2-swatch__chip--alt-ref-fresh { background: var(--alt-ref-fresh); }
.alt2-swatch__chip--alt-ref-leaf { background: var(--alt-ref-leaf); }
.alt2-swatch__chip--alt-ref-logo { background: var(--alt-ref-logo); }
.alt2-swatch__chip--alt-selected { background: var(--alt-selected); }
.alt2-swatch__chip--alt-selected-marker { background: var(--alt-selected-marker); }
.alt2-swatch__chip--alt-text-1 { background: var(--alt-text-1); }
.alt2-swatch__chip--alt-text-2 { background: var(--alt-text-2); }
.alt2-swatch__chip--alt-text-3 { background: var(--alt-text-3); }
.alt2-swatch__chip--alt-text-empty { background: var(--alt-text-empty); }
.alt2-swatch__chip--alt-warning-mark { background: var(--alt-warning-mark); }
.alt2-swatch__chip--alt-warning-text { background: var(--alt-warning-text); }
/* ══ GENERATED by design-system/emit_gallery.py — swatch chips ══ END */


/* ── C44 · ACCOUNT SWITCHER ────────────────────────────────────────────
   The masthead control that chooses which company the workspace operates on.
   Own books is the first row; every other row is a client. No `!important`,
   every class `alt2-`-prefixed, element selectors only under `.alt2-body` —
   the isolation gate's four rules. */
.alt2-body .alt2-acct { position: relative; }

.alt2-body .alt2-acct--live .alt2-client { cursor: pointer; }

.alt2-body .alt2-acct__caret {
  width: 14px; height: 14px;
  transform: rotate(90deg);
  opacity: .55;
}

.alt2-body .alt2-acct__menu {
  position: absolute;
  inset-inline-start: 0;
  top: calc(100% + 6px);
  /* Same overlay contract as the domain fly-out (`.alt2-submenu`): this IS a
     popover, so it is entitled to e1 — and only to e1. The isolation gate
     rejected a hand-rolled shadow here, correctly. */
  z-index: var(--z-popover);
  min-width: 280px;
  max-width: 380px;
  max-height: 60vh;
  overflow-y: auto;
  padding: var(--sp-2);
  background: var(--alt-bg-surface-3);
  border: 1px solid var(--alt-line);
  border-radius: var(--r-lg);
  box-shadow: var(--alt-e1);
}

.alt2-body .alt2-acct__head {
  margin: 4px 8px 6px;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--alt-text-2);
}

.alt2-body .alt2-acct__row { margin: 0; }

.alt2-body .alt2-acct__btn {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  width: 100%;
  padding: 8px 10px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--r-1);
  color: var(--alt-text-1);
  font-size: 13px;
  text-align: left;
  cursor: pointer;
}

.alt2-body .alt2-acct__btn:hover { background: var(--alt-bg-surface-2); }

/* Selected uses the RING, matching the module pill after Daniel's 2026-08-24
   instruction — frame, weight, no fill. */
.alt2-body .alt2-acct__btn--on {
  border-color: var(--alt-accent);
  font-weight: 600;
}

.alt2-body .alt2-acct__name {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.alt2-body .alt2-acct__tag {
  flex: none;
  padding: 1px 6px;
  border: 1px solid var(--alt-line-strong);
  border-radius: var(--r-pill);
  font-size: 10px;
  letter-spacing: .03em;
  text-transform: uppercase;
  color: var(--alt-text-2);
}


/* ── ALT-322 — „Pregledaj kao" izlazna značka ──────────────────────────────
   Blizanac legacy `.altoria-impersonation-badge` (portal.css). Postoji jer
   v2 stranice ne učitavaju portal.css, pa bi include legacy partiala dao
   značku bez ijednog stila. Kolapsirana je crvena pilula gore desno; hover,
   fokus i klik je šire u punu značku s gumbom za izlaz.

   z-index 997 — isti kao legacy: ispod dropdowna iz zaglavlja, iznad lista. */
.alt2-body .alt2-imp {
  position: fixed;
  top: 10px;
  right: 12px;
  z-index: 997;
  display: flex;
  align-items: flex-start;
  gap: 8px;
  border-radius: var(--r-pill);
  outline: none;
}

.alt2-body .alt2-imp__pill {
  flex: none;
  border: 1px solid var(--alt-negative-text);
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: var(--r-pill);
  background: var(--alt-negative-fill);
  color: #fff;
  font-weight: 600;
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
}

/* Kolapsirano po defaultu — panel se otvara na hover / focus / focus-within,
   tako da radi i mišem i tipkovnicom (Tab). */
.alt2-body .alt2-imp__panel {
  display: none;
  max-width: 320px;
  padding: 10px 12px;
  border: 1px solid var(--alt-negative-fill);
  border-radius: var(--alt-radius-md);
  background: var(--alt-bg-surface-1);
}

.alt2-body .alt2-imp:hover .alt2-imp__panel,
.alt2-body .alt2-imp:focus .alt2-imp__panel,
.alt2-body .alt2-imp:focus-within .alt2-imp__panel {
  display: block;
}

.alt2-body .alt2-imp__title {
  font-size: 11px;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--alt-negative-text);
}

.alt2-body .alt2-imp__role {
  color: var(--alt-text-2);
  text-transform: none;
  letter-spacing: 0;
}

.alt2-body .alt2-imp__meta {
  margin-top: 4px;
  font-size: 12px;
  color: var(--alt-text-2);
}

.alt2-body .alt2-imp__form {
  margin-top: 8px;
}

.alt2-body .alt2-imp__exit {
  width: 100%;
  padding: 6px 10px;
  border: 1px solid var(--alt-negative-fill);
  border-radius: var(--alt-radius-md);
  background: var(--alt-negative-fill);
  color: #fff;
  font: inherit;
  font-size: 13px;
  cursor: pointer;
}

.alt2-body .alt2-imp__exit:hover {
  background: var(--alt-negative-text);
  border-color: var(--alt-negative-text);
}
