/* ============================================================================================
   OKIS 2026 — ONE ordered stylesheet.

   Replaces, in their former AppAsset load order:
       web/css/okis-2026.css        the designer's canonical layer
       web/css/okis-2026-home.css   the home (Uvod) companion
       web/css/okis-2026-fixes.css  the app-wiring layer

   ORDER IS THE CONTRACT.  Sections run tokens -> base -> components -> page areas, and inside a
   section the rules keep the relative order they had in the sources.

   * `!important` here is AUDITED, not pruned: 170 declarations, each justified at its own block.
     Dropping one is a cascade change that has to be measured on its own.
   * NEVER write a star-slash pair inside a comment (a shell glob in a path does it) — it closes
     the comment early and silently kills the rules that follow.  scripts/check-css-comments.php
     scans this file for exactly that; run it after every edit.

   Sections
     1  TOKENS ................ the single :root registry (Figma 1:1)
     1b FONTS ................. self-hosted Inter
     2  BASE ................... type, form controls, select2, buttons, boxes, tables, chrome
     3  COMPONENTS ............. the shared patterns + the canonical @layer classes
     4  AREAS .................. what is genuinely page-specific, grouped by area
   ============================================================================================ */


/* ============================================================================================
   1. TOKENS — the design-token registry for this layer, mirroring the Figma variable registry
   1:1 (Figma `group/name` -> CSS `--group-name`).  Figma stays the human-readable registry of
   record; this is its CSS projection, and the ONLY :root block in this file.

   * okis-2026.css was frozen when this file was assembled, so where a Figma name and an older
     token mean the same value the new name is an ALIAS (`var(--old)`): one computed value, two
     vocabularies, either may be used.
   * Custom properties resolve at computed-value time, so the position of a :root declaration
     relative to the rules that read it is irrelevant.
   ============================================================================================ */
:root {
  /* Retuned legacy tokens */
  --main-bg-color: #F4FFFB;  /* was #F5F5FA Cool Grey — dropped from 2026 manual */
  --border-radius: 6px;  /* was 3px */
  --opacity: 1;  /* retire the opacity-hover hack; real hover shades below */

  /* ---------- 2026 additions ---------- */
  --ok-green: #005046;
  --ok-green-dark: #003B33;
  --ok-mint: #AECCC5;
  --ok-orange: #FF6A42;
  --ok-orange-dark: #E85835;
  --ok-orange-light: #FFBFAC;
  --ok-gold: #F5B82E;
  --ok-lavender: #D4C5F0;
  --ok-blush: #F5D5D0;
  --ok-cream: #F8E6A0;
  --ok-sky: #CEDAF6;  /* RGB 206/218/246 per client; manual HEX misprint */
  --radius-sm: 4px;
  --radius-control: 6px;
  --radius-modal: 12px;
  --surface-tint: #EDF7F2;
  --border-default: #DCE9E4;
  --border-strong: #B7CFC8;
  --ring-focus: 0 0 0 3px rgba(0, 80, 70, .14);
  --shadow-box: 0 1px 2px rgba(0, 60, 50, .06), 0 2px 8px rgba(0, 60, 50, .05);
  --shadow-dropdown: 0 4px 16px rgba(0, 60, 50, .12);
  --radius-box: 12px;
  accent-color: var(--ok-green);

  /* ---------- Brand ---------- */
  --brand-green:        var(--ok-green);  /* #005046 */
  --brand-green-dark:   var(--ok-green-dark);  /* #003B33 */
  --brand-mint:         var(--ok-mint);  /* #AECCC5 */
  --brand-mint-bg:      #DDEBE6;  /* the mint FILL: hover/selected tints, bands, chips */
  --brand-orange:       var(--ok-orange);  /* #FF6A42 — the CTA family */
  --brand-orange-dark:  var(--ok-orange-dark);  /* #E85835 */
  --brand-orange-light: var(--ok-orange-light);  /* #FFBFAC */
  --brand-gold:         var(--ok-gold);  /* #F5B82E */
  --brand-gold-dark:    #E3A417;

  /* ---------- Pastels ---------- */
  --pastel-lavender:    var(--ok-lavender);  /* #D4C5F0 */
  --pastel-blush:       var(--ok-blush);  /* #F5D5D0 */
  --pastel-blush-hover: #EFC2BA;  /* one step darker: the blush family's hover fill */
  --pastel-cream:       var(--ok-cream);  /* #F8E6A0 */
  --pastel-cream-hover: #F3DC85;  /* Figma only — no call site in this layer yet */
  --pastel-sky:         var(--ok-sky);  /* #CEDAF6 */
  --pastel-sky-light:   #E9F0FB;  /* info panel, unread row tint, dialog icon disc */
  --pastel-sky-light-hover: #DFEAF8;  /* one step darker: the unread row's hover */
  --pastel-sky-text:    #2C4270;  /* the sky family's ink */

  /* ---------- Surfaces ---------- */
  --surface-page:       var(--main-bg-color);  /* #F4FFFB */
  --surface-card:       #FFFFFF;
  --surface-input:      #FAFDFB;
  --surface-disabled:   #F3F7F5;  /* the small disabled marks: checkbox, radio, ghost button */
  --surface-disabled-field: #E9EDEB;  /* a FULL-SIZE disabled/readonly control. Deliberately darker than
                                         --surface-disabled: 3 points off white is cue enough on a 24px
                                         checkbox, not on a 34x168 field. REGISTRY GAP: no Figma name. */
  --surface-row-hover:  #F5F8F7;  /* the read notification row's hover — deliberately lighter than --surface-tint */
  --surface-inactive-row:       #DFE5E2;  /* a grid row whose record is no longer live; the ramp is derived
                                             at the inactive-row block in 3e. REGISTRY GAP: no Figma name. */
  --surface-inactive-row-hover: #D5DBD8;
  --overlay-backdrop:   #002A25;  /* the modal backdrop, used at 45% opacity */

  /* ---------- Ink ---------- */
  --text-body:          #1F2A28;
  --text-label:         #33413D;
  --text-muted:         #5E6E6A;
  --text-placeholder:   #93A6A1;  /* also the disabled-control ink */
  --text-not-set:       #9CBFB6;
  --text-inverse:       #FFFFFF;

  /* ---------- Borders ---------- */
  --border-focus:       var(--ok-green);  /* #005046 */

  /* ---------- Status ---------- */
  --status-success:     var(--ok-green);  /* #005046. NOTE: this name once held #00A65A, which is the
                                             risk-card edge and now lives under --status-risk-edge. */
  --status-warning:     var(--ok-gold);  /* #F5B82E */
  --status-danger:      #D93025;
  --status-danger-text: #B3261E;  /* the deeper danger: destructive ink + hover fills */
  --status-danger-muted:#B3401F;  /* alarm ink on the light-orange chips */
  --status-danger-border:#E4B5B0;  /* the tinted border of the quiet destructive button */
  --status-danger-wash: #FBEDEB;  /* its hover fill */
  --status-risk-edge:   #00A65A;  /* the risk-card left edge, and nothing else */

  /* ---------- Tinted state panels ---------- (the alert/callout anatomy, and the risk cards' skin) */
  --panel-success-bg:     #DDEBE6;
  --panel-success-border: #B7D4CA;
  --panel-warning-bg:     #FFF7E0;
  --panel-warning-border: #EDDFB3;
  --panel-warning-text:   #8A6A00;
  --panel-danger-bg:      #FFF6F4;
  --panel-danger-border:  #F0D6D0;
  --panel-danger-text:    #7A2E17;
  --panel-danger-row-bg:  #FFE3D9;  /* the light-orange alarm chip fill */
  --panel-info-bg:        var(--pastel-sky-light);  /* #E9F0FB — completes the success/warning/danger */
  --panel-info-border:    #C4D4F0;  /* family with the Sky Blue info panel */
  --panel-info-text:      var(--pastel-sky-text);  /* #2C4270 */

  /* ---------- Spacing ---------- (the compact vertical rhythm) */
  --spacing-form-group-gap:  10px;
  --spacing-label-gap:       3px;
  --spacing-box-gap:         16px;
  --spacing-inline-gap:      6px;  /* the gap between adjacent controls in a button row */
  --spacing-section-gap:     14px;  /* Figma; no unambiguous call site in this file yet */
  --spacing-cell-pad-y:      10px;  /* Figma; the grid cell padding is stated in 3e */
  --spacing-kv-row-pad-y:    9px;
  --spacing-box-body-x:      18px;
  --spacing-box-body-top:    12px;
  --spacing-box-body-bottom: 14px;
  --spacing-box-header-y:    8px;  /* Figma; as built the box header takes a single 8px on ALL FOUR sides,
                                      so the `-y` name would misdescribe the rule — left unapplied */
  --spacing-content-x:       24px;
  --spacing-content-y:       14px;

  /* ---------- Radius ---------- */
  --radius-dropdown: 8px;
  --radius-box-2026: var(--radius-box);  /* = 12px — the Figma name for the box radius */
  --radius-pill:     999px;

  /* ---------- Size ---------- */
  --control-height:         34px;  /* inputs, selects, the whole select2 metric chain and the input-group
                                      buttons are expressed in it, or in calc() off it */
  --size-control-height:    var(--control-height);  /* the Figma name for the same token (34px) */
  --size-btn-height:        36px;  /* the BLESSED free-standing button height. Named rather than left a
                                      literal for the same reason --size-toolbar-icon-tile is: plain `.btn`
                                      is deliberately OFF --control-height, so a bare 36 would drift the day
                                      that token moves again. See the height ladder in 3h. */
  --size-checkbox-form:     28px;
  --size-checkbox-grid:     20px;
  --size-radio-form:        20px;  /* deliberately NOT --size-checkbox-form: the client asked for the
                                      bigger box on checkboxes only */
  --size-boxheader-icon-btn: 28px;  /* the box-header / sub-section icon tile in body.toolbar-icons */
  --size-grid-action-btn:   28px;
  --size-filter-reset-btn:  28px;  /* Figma; as built the filter-reset tile rides --control-height, so this has no call site here */
  --size-title-trio-btn:    34px;
  --size-chip-add-btn:      28px;
  --size-input-addon:       40px;  /* ONE width for every icon-only input-group addon or button. Not a
                                      Figma variable and deliberately not --control-height: a 34px square
                                      would shrink the 43px icon buttons by 9px, and 40 is an as-built
                                      value already. */
  --size-toolbar-icon-tile: 36px;  /* NOT a Figma variable — the designer's toolbar spec, and the reason
                                      this token exists at all: plain `.btn` is deliberately OFF
                                      --control-height, so every icon-mode tile and the attached entity "+"
                                      segment used to carry a bare literal 36 and silently drifted the day
                                      the control token moved 36 -> 34. One name, five call sites. */
}

/* ============================================================================================
   1b. FONTS — Inter, self-hosted (no CDN — OKIS-3253 precedent)
   ============================================================================================ */
@font-face { font-family: "Inter"; font-weight: 400; font-style: normal; font-display: swap;
  src: url("font/inter-regular.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-weight: 500; font-style: normal; font-display: swap;
  src: url("font/inter-medium.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-weight: 600; font-style: normal; font-display: swap;
  src: url("font/inter-semibold.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-weight: 700; font-style: normal; font-display: swap;
  src: url("font/inter-bold.woff2") format("woff2"); }

/* ============================================================================================
   2a. BASE / type
   ============================================================================================ */
/* Compact vertical rhythm.  The control height is a TOKEN, so re-declaring it is enough: inputs,
   selects, the select2 selection/arrow/chip metrics, input-group buttons and the datepicker addons
   are all expressed in it (or in `calc()` off it) and follow by themselves.  Plain `.btn` is
   deliberately NOT keyed to the token (okis-2026.css pinned it via `line-height: 20px`) and stays
   at 36px: a toolbar is a row of buttons only, and 36px is the designer's toolbar-tile spec. */
body { color: var(--text-body); line-height: 1.4; }
hr { border-color: var(--border-default); }
/* "(není zadáno)" — `app\components\Formatter::asNotSet` plus five views wrap the placeholder in
   `.not-set`.  Quiet mint italic, and never bold: declared on `.not-set` ITSELF rather than scoped
   to `.kv-grid`, because a direct declaration beats inheritance from any ancestor, so this one line
   settles every context the placeholder can land in (in a Přehled row it would otherwise inherit
   `.kv-grid__value`'s 600). */
.not-set { color: var(--text-not-set); font-style: italic; font-weight: 400; }

/* ============================================================================================
   2b. BASE / form controls
   ============================================================================================ */
/* ---------- Controls: one geometry for everything ---------- */
.form-control, select.form-control {
  height: var(--control-height);
  border-radius: var(--radius-control);
  border-color: var(--border-default);
  box-shadow: none;
  transition: border-color 120ms, box-shadow 120ms;
}
.input-group-addon {
  border-radius: var(--radius-control);
  border-color: var(--border-default);
  background-color: var(--surface-tint);
  color: var(--ok-green);
}
.form-group.required label:after { color: var(--status-danger); }
/* THE SAME ASTERISK, kartik's address for it.  The rule above only reaches a label that kartik did NOT
   render: on a `has-star` label activeform.css:286
   (`.required .has-star:not(.custom-control-label):not(.custom-file-label)::after`, (0,4,0)) supplies
   both the glyph and `color: tomato`, and out-specifies the (0,2,1) above — so every required marker on
   a kartik field was rgb(255,99,71) beside a #D93025 label.  Repeating kartik's shape with the element
   it actually lands on makes this (0,4,1). */
.required label.has-star:not(.custom-control-label):not(.custom-file-label)::after { color: var(--status-danger); }
.input-group-btn .btn, .navbar-custom-menu .input-group .input-group-btn .btn { height: var(--control-height); }
.label, .badge { border-radius: var(--radius-sm); font-weight: 600; }
.navbar-custom-menu .form-group .input-group { border-radius: var(--radius-control); }
.navbar-custom-menu .form-control { border-radius: var(--radius-control) 0 0 var(--radius-control); }
.navbar-custom-menu .input-group .input-group-btn .btn { border-radius: 0 var(--radius-control) var(--radius-control) 0; }
.form-group { margin-bottom: 18px; }
label.control-label { font-weight: 400; color: var(--text-label); }
.form-control:focus { border-color: var(--ok-green); box-shadow: var(--ring-focus); background: var(--surface-card); }
/* Inputs: calm placeholder, smooth focus */
.form-control::placeholder { color: var(--text-placeholder); }
/* Input-group buttons: square inner edge, rounded outer edge, tinted like addons */
.input-group .form-control:first-child { border-top-right-radius: 0; border-bottom-right-radius: 0; }
.input-group .form-control:last-child { border-top-left-radius: 0; border-bottom-left-radius: 0; }
/* Checkboxes: bigger, rounded, tinted like inputs (accent-color keeps them green when checked) */
input[type="checkbox"], input[type="radio"] { width: 20px; height: 20px; margin: 0; vertical-align: middle; }
.checkbox input[type="checkbox"], .form-group input[type="checkbox"] {
  appearance: none; -webkit-appearance: none;
  position: static; margin: 0; /* overrides skin.css absolute hack + BS3 -20px margin-left */
  width: 28px; height: 28px; margin: 4px 0; cursor: pointer;
  background: var(--surface-input); border: 1px solid var(--border-default); border-radius: var(--radius-sm);
  transition: border-color 120ms, box-shadow 120ms, background-color 120ms;
  display: inline-grid; place-content: center;
}
.checkbox input[type="checkbox"]:hover, .form-group input[type="checkbox"]:hover { border-color: var(--border-strong); }
.checkbox input[type="checkbox"]:focus-visible, .form-group input[type="checkbox"]:focus-visible { outline: none; border-color: var(--ok-green); box-shadow: var(--ring-focus); }
.checkbox input[type="checkbox"]:checked, .form-group input[type="checkbox"]:checked { background: var(--ok-green); border-color: var(--ok-green); }
.checkbox input[type="checkbox"]:checked::before, .form-group input[type="checkbox"]:checked::before {
  content: ""; width: 14px; height: 14px;
  clip-path: polygon(14% 44%, 0 65%, 40% 100%, 100% 16%, 84% 0%, 38% 68%);
  background: var(--text-inverse);
}
.input-group.date .input-group-addon + .form-control { border-radius: 0 var(--radius-control) var(--radius-control) 0; }
/* okis-2026.css resets checkbox positioning via `.checkbox input[type=checkbox]` (0,2,1),
   but adminlte.css:288 positions it via `.checkbox label input[type=checkbox]` (0,2,2),
   and Yii2/BS3 nests the input INSIDE the label — so the reset loses.  Re-assert at (0,2,2): */
.checkbox label input[type="checkbox"],
.checkbox-inline input[type="checkbox"] {
  position: static;
  left: auto; top: auto;
  margin: 4px 0;
}
.radio input[type="radio"]:hover, .form-group input[type="radio"]:hover { border-color: var(--border-strong); }
.radio input[type="radio"]:focus-visible, .form-group input[type="radio"]:focus-visible {
  outline: none; border-color: var(--ok-green); box-shadow: var(--ring-focus);
}
.radio input[type="radio"]:checked, .form-group input[type="radio"]:checked,
.radio label input[type="radio"]:checked {
  background: var(--ok-green); border-color: var(--ok-green);
}
.radio input[type="radio"]:checked::before, .form-group input[type="radio"]:checked::before,
.radio label input[type="radio"]:checked::before { content: ""; border-radius: 50%; background: var(--text-inverse); width: 9px; height: 9px; }
/* APPROVED visual change: `#eee` -> --surface-disabled (#F3F7F5), a slightly greener, lighter
   disabled grey, so the three legacy disabled fills (this radio, the inline checkbox below, the
   disabled select2) agree with the token every other disabled surface in this layer uses. */
.radio input[type="radio"]:disabled, .form-group input[type="radio"]:disabled { background: var(--surface-disabled); cursor: not-allowed; }
/* Addon restyle lost to vendored `.input-group .input-group-addon { border-radius:0; border-color:#d2d6de;
   background-color:#fff; }` at (0,2,0), same specificity as this rule — tie resolves in our favor by load order. */
.input-group .input-group-addon {
  border-color: var(--border-default);
  background-color: var(--surface-tint);
  color: var(--ok-green);
}
/* Checkbox polish: a crisp SVG check instead of clip-path (which rendered ragged on some
   displays), plus full state coverage for the -inline and label.form-label variants. */
.checkbox input[type="checkbox"], .form-group input[type="checkbox"],
.checkbox label input[type="checkbox"], .checkbox-inline input[type="checkbox"] {
  width: 24px; height: 24px;
}
.checkbox input[type="checkbox"]:checked, .form-group input[type="checkbox"]:checked,
.checkbox label input[type="checkbox"]:checked, .checkbox-inline input[type="checkbox"]:checked {
  background: var(--ok-green) url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%23fff' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round' d='M3.5 8.5l3 3 6-7'/%3E%3C/svg%3E") center/70% no-repeat;
  border-color: var(--ok-green);
}
.checkbox input[type="checkbox"]:checked::before, .form-group input[type="checkbox"]:checked::before,
.checkbox label input[type="checkbox"]:checked::before, .checkbox-inline input[type="checkbox"]:checked::before {
  display: none;
}
.checkbox-inline input[type="checkbox"]:hover { border-color: var(--border-strong); }
.checkbox-inline input[type="checkbox"]:focus-visible { outline: none; border-color: var(--ok-green); box-shadow: var(--ring-focus); }
/* `#eee` -> --surface-disabled.  See the radio note above. */
.checkbox-inline input[type="checkbox"]:disabled { background: var(--surface-disabled); cursor: not-allowed; }
label:has(> input[type="checkbox"]) {
  display: inline-flex; align-items: center; gap: 8px;
}

/* ---------- Custom radio ----------
   20px, not the checkbox's 28: 24/28px read oversized next to the 13px type, and 20 matches the
   native 20px grid row-select.  The client asked for the bigger box on checkboxes only. */
.radio input[type="radio"], .form-group input[type="radio"],
.radio label input[type="radio"], .radio-inline input[type="radio"] {
  appearance: none;
  -webkit-appearance: none;
  position: static;
  margin: 4px 0;
  cursor: pointer;
  background: var(--surface-input);
  border: 1px solid var(--border-default);
  border-radius: 50%;
  transition: border-color 120ms, box-shadow 120ms, background-color 120ms;
  display: inline-grid;
  place-content: center;
  vertical-align: middle;
  width: var(--size-radio-form);
  height: var(--size-radio-form);
}
/* Block checkboxes (Yii `->checkbox()` in vertical forms, e.g. Cizinec): restore the
   label-above-box layout — the original look came from the removed absolute-position hack.
   Inline variants (.checkbox-inline, contract's label.form-label) keep the row layout.
   Default is the classic inline row — box left, sentence label right, one line (the checkbox DOM
   is normalized input-first via container.php's checkboxTemplate). */
.checkbox label:has(> input[type="checkbox"]) {
  display: inline-flex;
  flex-direction: row;
  align-items: center;
  gap: 8px;
}
/* Two legacy leftovers stacked up between a checkbox and the field under it: skin.css's
   `.form-group .checkbox { margin-bottom: 30px }` and adminlte.css:258's `.checkbox label
   { margin-bottom: 15px }` (15px of dead space INSIDE the checkbox row).  Both existed to
   compensate for the absolutely-positioned checkbox hack that okis-2026.css removed, so they are
   now pure padding.  Zero them and let the form-group's own margin govern the rhythm. */
.form-group .checkbox { margin-bottom: 0; }
.checkbox label { margin-bottom: 0; }
/* Form checkboxes are 28px, the canonical size, with `margin: 4px 0` centring them on the control
   line.  Grid checkboxes are a separate canonical rule (`.kv-grid-table input[type=checkbox]`,
   20px) and are out of reach here — no grid checkbox sits inside a `.form-group` or a `.checkbox`.
   Radios stay at 20px: the client asked about checkboxes only. */
.checkbox input[type="checkbox"], .form-group input[type="checkbox"],
.checkbox label input[type="checkbox"], .checkbox-inline input[type="checkbox"] {
  width: var(--size-checkbox-form); height: var(--size-checkbox-form);
}
/* Block checkbox (Cizinec): centre the box on the control line of its row. */
.checkbox label:has(> input[type="checkbox"]) > input[type="checkbox"] { margin: 4px 0; }
/* OKIS-3342 composer upgrade: yii2-widget-activeform 1.6.4 renders kartik field labels
   as .form-label (BS5 vocabulary) even in BS3 mode — canonical label.control-label rules
   stopped matching, labels fell back to bootstrap's bold + inherited green.  Alias them. */
label.form-label {
  font-weight: 400;
  color: var(--text-label);
}
/* THE SAME ALIAS for the label of a checkbox or a radio.  `label.control-label` is what carries the
   canonical weight and ink, and the label a Yii checkbox is wrapped in never gets that class — so the
   only rule it matched was bootstrap.css's base `label { font-weight: 700 }`, and its colour fell
   through to whatever the surrounding box inherits (`--ok-green` inside `.content-wrapper`).  On the
   same form that put a bold dark-green "Požadované datum" beside a regular "Název".
   Three shapes, because the app emits three: the bare `<label><input></label>` of
   yii\widgets\ActiveField, the `.checkbox` / `.radio` div of container.php's bootstrap checkboxTemplate,
   and BS3's own inline variants.  `:has()` is the only way to reach the bare one — it carries no class
   at all — and it is kept inside `.form-group` so a labelled checkbox outside a form (a grid's
   select-all, say) keeps whatever its own context gives it. */
.checkbox label,
.radio label,
.checkbox-inline,
.radio-inline,
.form-group label:has(> input[type="checkbox"]),
.form-group label:has(> input[type="radio"]) {
  font-weight: 400;
  color: var(--text-label);
}
/* Hidden value carriers must not reserve vertical space.  Each `hiddenInput()` field is a block
   `.form-group`: zero height, but its own bottom margin, so a run of them inserts a dead gap before
   the next section heading.  Listed explicitly rather than matched structurally — these are the only
   hidden-only field wrappers on the page, and `:has()` guesswork would also catch the (visible)
   `hidden`-class premium fields. */
.field-subject-api_data,
.field-subject-insurance_premium_hidden,
.field-subject-insurance_premium_term_hidden,
.field-subject-payment_frequency_month_count,
.field-subjectvehicle-notset_id_hidden,
.field-subjectvehicle-vehicle_brand_detail_jine_id_hidden,
.field-subjectvehicle-show_description,
.field-subjectrisc-risc_ids_hidden {
  margin-bottom: 0;
}
.list-filter-bar__field {
  margin: 0;
  flex: 1 1 200px;
  min-width: 200px;
}
.form-group { margin-bottom: var(--spacing-form-group-gap); }
label { margin-bottom: var(--spacing-label-gap); }
/* A checkbox / radio box is centred on the control line, so its centring margin is
   (control-height - box) / 2 — 3px at the 34px control height.  Four selector families, all the
   same arithmetic. */
.checkbox label input[type="checkbox"],
.checkbox-inline input[type="checkbox"],
.checkbox label:has(> input[type="checkbox"]) > input[type="checkbox"],
.radio input[type="radio"], .form-group input[type="radio"],
.radio label input[type="radio"], .radio-inline input[type="radio"] {
  margin: 3px 0;
}
/* ---------- Validation success state ----------
   Brand green with no glow, and the addon quiet instead of AdminLTE's solid green fill.
   SPECIFICITY: AdminLTE.min.css states the whole state as `.form-group.has-success X` (0,3,0), so
   `.has-success X` alone (0,2,0) loses to it — every selector below repeats AdminLTE's shape and
   wins the tie on load order. */
.form-group.has-success .form-control,
.form-group.has-success .form-control:focus,
.has-success .form-control, .has-success .form-control:focus {
  border-color: var(--ok-green);
  box-shadow: none;
}
/* The addon keeps its RESTING fill and glyph and moves only its border, exactly as the error and
   warning twins below do — one philosophy for all three states.  It used to carry
   `--panel-success-bg`, which made success the only state that also repainted the addon's fill.
   (0,4,0) for the same two reasons the error twin needs it: it has to clear kartik's
   `.has-success.highlight-addon .input-group-addon` (0,3,0) AND the date picker's own
   `.input-group.date .input-group-addon` (0,3,0), stated LATER in this file — at (0,3,0) the
   calendar addon of a valid date field kept a pale border while the input went green. */
.form-group.has-success .input-group .input-group-addon {
  background-color: var(--surface-tint);
  border-color: var(--ok-green);
  color: var(--ok-green);
}
.form-group.has-success .input-group-addon,
.has-success .input-group .input-group-addon {
  border-color: var(--ok-green);
}
/* The state must not repaint the label or the hint — the border is the whole signal. */
.form-group.has-success label, .form-group.has-success label.form-label,
.has-success .control-label { color: var(--text-label); }
.form-group.has-success .help-block, .has-success .help-block { color: var(--text-muted); }
/* ---------- The error twin of the success state — quiet validation, in the 2026 red ----------
   ROOT CAUSE of the last legacy red on screen: the error state was painted by AdminLTE.min.css, a
   VENDORED file that cannot be edited (`.form-group.has-error` on the label, the control's border and the
   help-block, all #dd4b39).  The whole state now sits on --status-danger.

   SPECIFICITY: AdminLTE states it as `.form-group.has-error X`, so every selector here repeats that shape
   and wins the tie on load order, exactly as the success block above does.  `.has-error X` is added
   alongside for the cases where the state lands on something that is not a `.form-group`.

   THE ADDON IS NOT A VALIDATION SURFACE — user ruling, same philosophy as the tinted success addon and the
   quiet clipboard button: the field's own border and message carry the state.  The addon keeps its resting
   fill and glyph, with only its border moving to the danger colour so the ring is one continuous colour.

   ITS FILL AND INK HAVE TO BE STATED, not just left alone.  Two vendored rules wait underneath with
   bootstrap's pink error skin, and one of them out-specifies the resting 2026 rule —

     bootstrap.css      .has-error .input-group-addon                      (0,2,0)
     activeform.css     .has-error.highlight-addon .input-group-addon      (0,3,0)   <- wins
         both: color #A94442; background-color #F2DEDE; border-color #A94442
     this file          .input-group .input-group-addon                   (0,2,0)   resting tint

   `highlight-addon` is on EVERY field that has an addon (kartik ActiveField:1247), so without the two
   lines below an errored addon swaps AdminLTE's red for kartik's pink.  And
   `.form-group.has-error .input-group .input-group-addon` is (0,4,0) deliberately: it has to clear
   activeform's (0,3,0) AND the date picker's own `.input-group.date .input-group-addon` (0,3,0), stated
   LATER in this file — a (0,3,0) here would lose to both and leave every errored date field with a green
   border on its calendar.  The two shorter selector lists are for the shapes (0,4,0) cannot match. */
.form-group.has-error label, .form-group.has-error label.form-label,
.has-error .control-label { color: var(--status-danger); }
.form-group.has-error .help-block, .has-error .help-block { color: var(--status-danger); }
.form-group.has-error .form-control,
.form-group.has-error .form-control:focus,
.has-error .form-control, .has-error .form-control:focus {
  border-color: var(--status-danger);
  box-shadow: none;
}
.form-group.has-error .input-group .input-group-addon {
  background-color: var(--surface-tint);
  border-color: var(--status-danger);
  color: var(--ok-green);
}
.form-group.has-error .input-group-addon,
.has-error .input-group .input-group-addon {
  border-color: var(--status-danger);
}
/* ---------- The warning twin — the third validation state, same philosophy ----------
   `web/js/modules.js` puts `has-warning` on eight field groups (a VIN or a number plate that is
   already on another record, an IČO the ARES/OKK lookup could not confirm, an unverified data-box
   id): a soft "check this" that must not read as a hard error.  Before this block the state was
   AdminLTE's #F39C12 on the label, the control border and the hint, plus a SOLID #F39C12 addon with
   white ink — the last solid-fill validation addon in the app.

   THE ADDON IS NOT A VALIDATION SURFACE, exactly as in the success and error twins above: resting
   fill and glyph, border on the state colour.  (0,4,0) for the same two reasons, and bootstrap waits
   underneath here too (`.has-warning .input-group-addon` (0,2,0), #fcf8e3 fill / #8a6d3b ink), so the
   fill and the ink have to be stated rather than left alone.

   TWO WARNING TOKENS, NOT ONE.  `--status-warning` (#F5B82E) is a FILL/BORDER gold: on white it
   measures ~1.9:1, so a label or a message written in it would be unreadable.  The ink is therefore
   `--panel-warning-text` (#8A6A00, ~4.9:1), the same ink the warning alert/callout anatomy uses.
   The label and the hint DO carry the ink — a warning always arrives with a message, so this state
   follows the error twin here rather than the success one. */
.form-group.has-warning label, .form-group.has-warning label.form-label,
.has-warning .control-label { color: var(--panel-warning-text); }
.form-group.has-warning .help-block, .has-warning .help-block { color: var(--panel-warning-text); }
.form-group.has-warning .form-control,
.form-group.has-warning .form-control:focus,
.has-warning .form-control, .has-warning .form-control:focus {
  border-color: var(--status-warning);
  box-shadow: none;
}
.form-group.has-warning .input-group .input-group-addon {
  background-color: var(--surface-tint);
  border-color: var(--status-warning);
  color: var(--ok-green);
}
.form-group.has-warning .input-group-addon,
.has-warning .input-group .input-group-addon {
  border-color: var(--status-warning);
}
/* ---------- A custom checkbox must never shrink ----------
   Where a label is `display: inline-flex` the box beside it is a flex item: its 28px is only a
   BASIS and `flex-shrink: 1` is the initial value, so beside a two-line label the row is
   over-constrained and the box gives way first — it reads as a dented rectangle.  `flex: none`
   restores "28px, non-negotiable"; the label wraps instead, which it was already doing.  Written
   across the same selector list as the rule that sets the 28px so the two cannot drift apart, and
   inert wherever the container is not a flex container. */
.checkbox input[type="checkbox"], .form-group input[type="checkbox"],
.checkbox label input[type="checkbox"], .checkbox-inline input[type="checkbox"],
label > input[type="checkbox"] {
  flex: none;
}
/* ---------- The navbar search field's focus state ----------
   skin.css paints the field mint on both axes — `.navbar-custom-menu form input[type="text"]
   { background-color: var(--main-color-light); border-color: var(--main-color-light) }` — and at
   (0,2,2) that outranks `.form-control:focus` (0,2,0).  So the border never changed on focus: the
   field kept its mint edge, and the green ring underneath it (`--ring-focus`, an 8%-alpha green) is
   all but invisible against the dark green navbar.  The rule below pins all three parts of the
   state: the UA/legacy ring off, the border to the focus green, the standard ring.  Specificity is
   skin.css's selector plus `.form-control` and `:focus`, so it wins on both count and order.
   The mint FILL is left alone on purpose — the border is what carries the state everywhere else. */
.navbar-custom-menu form input[type="text"].form-control:focus {
  outline: none;
  border-color: var(--ok-green);
  box-shadow: var(--ring-focus);
}

/* ---------- A lone .form-control in an .input-group keeps its corners ----------
   ROOT CAUSE of the square read-only fields on the dashboard, and of every other square field that
   sits alone inside an `.input-group`.  Bootstrap flattens the side of a control that ABUTS a
   neighbour:

     .input-group .form-control:first-child { border-top-right-radius: 0; border-bottom-…: 0 }
     .input-group .form-control:last-child  { border-top-left-radius: 0;  border-bottom-…: 0 }

   An only child is both `:first-child` and `:last-child`, so BOTH rules fire and all four corners
   go to 0 — a perfectly square field next to 6px-rounded ones.  The pair is written for a control
   that has an addon or a button beside it; with nothing to abut there is nothing to flatten.
   `:first-child:last-child` is the whole condition and matches nothing else, so every group with an
   addon, a button or a second control keeps its joined-corner geometry exactly.  (0,3,0) against
   their (0,2,0), so it needs no `!important`. */
.input-group > .form-control:first-child:last-child {
  border-radius: var(--radius-control);
}
/* ---------- An addon BUTTON stays quiet while the field validates ----------
   A STATE, not the resting look.  At rest these buttons render as the quiet addon; kartik repaints them
   the moment its client validation lands a class on the field wrapper:

     vendor/kartik-v/yii2-widget-activeform/src/assets/css/activeform.css:177 / :189
     .has-success.highlight-addon .input-group-btn .btn:not(:disabled):not(.disabled)
         { color: #fff; background-color: #449d44; border-color: #398439 }
     .has-error.highlight-addon   .input-group-btn .btn:not(:disabled):not(.disabled)
         { color: #fff; background-color: #c9302c; border-color: #ac2925 }

   `highlight-addon` is put on the field wrapper by kartik's ActiveField (src/ActiveField.php:1247) for
   every field that has an addon; the state class arrives from the ajax/client validation or from one of
   `web/js/modules.js`'s own toggles.  The three state blocks above address `.input-group-addon` — the
   SPAN — and never see `.input-group-btn .btn`, kartik's separate address for the same state.  (Worth
   knowing when measuring this: `.btn` carries a 120ms background transition, so a getComputedStyle taken
   right after the class lands still reads the OLD fill.)

   ALL addon buttons, not just the copy-to-clipboard one: an errored field could otherwise show a calm
   calendar or copy addon next to a blood-red "search in API" button in the same input group.  The values
   below ARE the resting look of an addon button (`.input-group-btn:last-child > .btn` in 2g, and its
   `:hover` twin), so the button keeps what it had and the field's own border carries the state.
   `has-warning` is in the list because the three states are one rule, not because kartik paints it —
   nothing does, which is why a warning already left these buttons alone.

   Specificity: kartik's is (0,6,0) resting and (0,7,0) on hover; the `:root` prefix repeats its shape
   one class higher, so each of ours wins outright. */
:root .has-success.highlight-addon .input-group-btn .btn:not(:disabled):not(.disabled),
:root .has-error.highlight-addon .input-group-btn .btn:not(:disabled):not(.disabled),
:root .has-warning.highlight-addon .input-group-btn .btn:not(:disabled):not(.disabled) {
  background: var(--surface-tint);
  border-color: var(--border-default);
  color: var(--ok-green);
}
:root .has-success.highlight-addon .input-group-btn .btn:not(:disabled):not(.disabled):hover,
:root .has-success.highlight-addon .input-group-btn .btn:not(:disabled):not(.disabled):focus,
:root .has-error.highlight-addon .input-group-btn .btn:not(:disabled):not(.disabled):hover,
:root .has-error.highlight-addon .input-group-btn .btn:not(:disabled):not(.disabled):focus,
:root .has-warning.highlight-addon .input-group-btn .btn:not(:disabled):not(.disabled):hover,
:root .has-warning.highlight-addon .input-group-btn .btn:not(:disabled):not(.disabled):focus {
  background: var(--brand-mint-bg);
  border-color: var(--border-strong);
  color: var(--ok-green);
}
/* The addon overlaps the input by -1px and both sit at z-index 2, so at rest the LATER node —
   the addon — paints its pale left border over the input's coloured right border, and the
   error/success ring visibly loses its fourth side the moment focus (z-index 3) leaves.
   While the field carries a validation state, the input stays one step above its addon; focus
   still outranks everything at 3. */
.has-error .input-group .form-control,
.has-success .input-group .form-control {
  z-index: 3;
}
/* ---------- A field hint gets air under its control ----------
   Both hint containers sit 5px below the control: `.hint-block` (site.css, which is what kartik's
   ActiveField writes) and `.help-block` (bootstrap's `margin: 5px 0 10px`, which is what plain Yii
   uses and where an inline validation message lands).  5px is closer than the control is to its own
   LABEL once the line-box leading is counted, so the hint read as sitting ON the input.

   8px, and the number is bounded on both sides rather than picked: it has to stay BELOW the 10px
   `--spacing-form-group-gap` that separates this field from the next, or the hint stops obviously
   belonging to the control above it; and above 5, or nothing changes.  8 is the largest value that
   satisfies both.

   `.form-group` keeps it to a field's own hint: `.help-block` is also used outside form groups
   (the login page's blocks, the filter bar's empty ones, which are hidden elsewhere).  A DESCENDANT
   and not a child, because a checkbox field puts both its control and its hint inside a `.checkbox`
   div (container.php's checkboxTemplate), so a child combinator reached the hint of every field
   EXCEPT a checkbox's — the one shape whose hint is furthest from what it describes. */
.form-group .hint-block,
.form-group .help-block {
  margin-top: 8px;
}
/* THE SAME AIR once the field is in a dialog.  kartik's activeform.css states
   `.kv-form-bs3 .hint-block { margin-top: -5px }` at the same (0,2,0) as the pair above, and a
   bsdialog loads its body over AJAX, which appends that stylesheet AFTER this file — so inside a
   dialog the vendor rule won the tie on load order and the hint sat ON the control it belongs to.
   Restated one class deeper, so the outcome stops depending on when the dialog was opened.
   The group-assign popup further down keeps its own 4px: a select2 carries more slack than an
   input, and that rule is later in this file, so it still decides its own case. */
.bsdialog .form-group .hint-block,
.bsdialog .form-group .help-block {
  margin-top: 8px;
}
/* ---------- A DISABLED checkbox stops looking like a live one ----------
   A checked AND disabled checkbox came out in full brand green with a white tick, indistinguishable
   from the live ones beside it, so the one control the user cannot change was the loudest on the
   form.  Nothing in the checkbox block covered `:disabled` except `.checkbox-inline`, and the
   `:checked` fill outranked even that.  Both disabled states, drawn as one family:

     unchecked  --surface-disabled fill on --border-default   (the same pair the disabled radio and
                .checkbox-inline already use, so nothing new)
     checked    --brand-mint-bg fill, --brand-mint border, and the SAME check glyph re-inked to
                --text-muted.  Mint at reduced saturation rather than a grey box, because a disabled
                checkbox still has to answer "is it on?" at a glance; #5E6E6A on #DDEBE6 is ~5:1,
                whereas the white tick would have been ~1.9:1 on that fill.

   The glyph is the live data-URI with `stroke='%235E6E6A'` in place of `%23fff` — same path, same
   70% sizing, so the tick cannot drift from the live one.  `cursor: not-allowed` on the box AND on
   its label: the label is the bigger hit target and is what a user actually clicks at.

   Specificity: the fill to beat is `.checkbox label input[type="checkbox"]:checked` (0,3,2).  The
   `:disabled` in each selector below takes the same shapes to (0,4,1)/(0,4,2)/(0,5,2), so every one
   of them wins on count and none needs an `!important`. */
:is(.checkbox, .form-group, .checkbox-inline) input[type="checkbox"]:disabled,
.checkbox label input[type="checkbox"]:disabled,
label > input[type="checkbox"]:disabled {
  background-color: var(--surface-disabled);
  border-color: var(--border-default);
  cursor: not-allowed;
}
label:has(> input[type="checkbox"]:disabled) { cursor: not-allowed; }
/* WARNING — do not re-add a corner fix for the "Číslo bankovního účtu a IBAN" addon here.  A pair of
   `.input-group-btn:last-child > .btn:has(+ .btn:last-child[style*="display:none"])` rules used to
   live at this spot; the markup fix replaced them.  The sometimes-hidden 🗑 is now rendered BEFORE
   the always-visible ✎ in both writers of that addon (BankAccountNumberWithIban::run() and
   widgets/views/bank-account-fields/_create.php), so bootstrap's `:not(:last-child)` never lands on
   a button the user can see and the corners are correct with no CSS at all.  The ordering comment in
   those two files is the one place the constraint is stated. */
/* ---------- One width for every icon-only input-group addon ----------
   The icon-only addons came in five widths (a 22px DatePicker calendar, 43/41/40px icon buttons, a
   34px "Search In API"), so an "addon column" that ought to read as one repeated tile read as three
   sizes.

   40px, and the reasons in order: it is inside the range the ruling names (38-40); it is an as-built
   value, not an invention — two of the five families already computed it; and it is the choice that
   moves the fewest pixels overall.  --control-height (34) was the other candidate and was rejected:
   it would be a true square against the control line but would shrink the app's most common addon
   button by 9px.  Named --size-input-addon so the value cannot drift.

   Text addons ("kg", "kW", "cm3", 38-92px, whose width IS their content), dropdown togglers, which
   carry a caret as a second child, and labelled buttons are all excluded and untouched.

   `:has(> .fa:only-child)` is what "icon-only" means in this markup: every one of these buttons
   renders a single `<i class="fa …">` and nothing else, while a labelled button carries a text node
   beside its icon and a toggler carries a `.caret` as a second ELEMENT child.  The calendar addon is
   addressed by its own class because its glyph is a `.glyphicon`, not a `.fa`.
   Scoped to `.content-wrapper` so the header's global-search group — a labelled "Vyhledat" plus a
   caret toggle — is out of reach by construction. */
.content-wrapper .input-group > .input-group-addon.kv-date-picker,
.content-wrapper .input-group > .input-group-btn > .btn:has(> .fa:only-child) {
  width: var(--size-input-addon);
  min-width: var(--size-input-addon);
  padding-left: 0;
  padding-right: 0;
  text-align: center;
}
/* ---------- A date picker fills its field, in a filter, a form or a dialog ----------
   ONE ROOT CAUSE, THREE REPORTS.  kartik's DatePicker renders `<div class="input-group date">`, and
   bootstrap 3 gives `.input-group` `display: table` with NO width.  A table box shrinks to fit, so
   the control is as wide as its input's default size plus the 40px addon and IGNORES the column it
   sits in — 214px inside a 272px `col-md-3`, ~300px inside a full-width form row — while the selects
   and text inputs around it (plain `.form-control`, `width: 100%`) fill theirs.  It showed up in a
   filter panel, in a create form and in a bsdialog.

   SCOPED TO `.input-group.date` ON PURPOSE — `date` is kartik's own marker class on the picker and
   nothing else in the app uses it.  Widening every `.input-group` would also widen the ones that are
   deliberately content-sized (the bank-account prefix/number pair, amount + currency), so the rule
   names the control that is wrong rather than the box class it happens to use.  `.form-group` keeps
   it to a rendered field. */
.form-group .input-group.date { width: 100%; }

/* ---------- One disabled treatment for every full-size control ----------
   Two disabled fills stood side by side on the same form: bootstrap's own `#EEEEEE` on a native
   `select.form-control[disabled]`, which no rule in this layer had ever restated, and
   `--surface-disabled` on a select2 — a token sized for a 24px checkbox.  12 points apart; one read
   as disabled, one did not.  Both now take --surface-disabled-field, so a disabled input, select,
   textarea and select2 are one surface.  The ink is --text-muted (was bootstrap's off-palette #555)
   and the cursor is not-allowed on all of them.

   `[readonly]` is in the list because a readonly field makes the reader the same promise a disabled
   one does, and because bootstrap already paints the two together — keeping them apart would
   re-create the split this closes.  It reaches nothing today, so it is a guard, not a change.

   NOT TOUCHED, on purpose: the disabled CHECKBOX / RADIO and the disabled BUTTON (`.btn.disabled`).
   They keep --surface-disabled — a 24px mark and a ghost tile do not need the heavier fill, and the
   checkbox's checked-disabled state has its own mint answer that a grey fill would undo.

   Specificity: (0,2,0) for the native half, which beats bootstrap's own (0,2,0) on order and the
   base `.form-control` background (0,1,0) outright.  The select2 half is stated in 2c itself, on the
   rule that already owned that fill, rather than as a competitor. */
.form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control {
  background-color: var(--surface-disabled-field);
  color: var(--text-muted);
  cursor: not-allowed;
  opacity: 1;
}

/* ============================================================================================
   2c. BASE / select2
   ============================================================================================ */

/* ---------- Select2: revive the 13 dead krajee overrides.
   v2.2.5 renders .select2-container--krajee-bs3; old rules targeted --krajee.
   [class*=] matches bs3/bs4/bs5. ---------- */
[class*="select2-container--krajee"] .select2-selection {
  height: var(--control-height);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-control);
  box-shadow: none;
}
[class*="select2-container--krajee"] .select2-selection--single .select2-selection__arrow {
  height: calc(var(--control-height) - 2px);
}
[class*="select2-container--krajee"].select2-container--focus .select2-selection,
[class*="select2-container--krajee"].select2-container--open .select2-selection {
  border-color: var(--ok-green);
  box-shadow: var(--ring-focus);
}
.select2-dropdown {
  border-color: var(--ok-green);
  border-radius: var(--radius-control);
  box-shadow: var(--shadow-dropdown);
}
.has-error [class*="select2-container--krajee"] .select2-selection { border-color: var(--status-danger); }
.has-success [class*="select2-container--krajee"] .select2-selection { border-color: #00A65A; }
.form-control, select.form-control, [class*="select2-container--krajee"] .select2-selection { background: var(--surface-input); }
/* Select2 dropdown: brand states (selected = tint, highlighted = green already set) */
.select2-results__option[aria-selected="true"] { background: var(--surface-tint); color: var(--ok-green); }
.select2-results__option { padding: 7px 12px; }
.select2-search--dropdown .select2-search__field { border: 1px solid var(--border-default); border-radius: var(--radius-sm); }
.select2-search--dropdown .select2-search__field:focus { outline: none; border-color: var(--ok-green); box-shadow: var(--ring-focus); }
[class*="select2-container--krajee"] .select2-selection__clear { color: var(--text-placeholder); }
[class*="select2-container--krajee"] .select2-selection__clear:hover { color: var(--status-danger-text); }
/* Form grid: never let a select truncate — inputs fill their column */
.form-group .form-control, .form-group .select2-container { min-width: 0; max-width: 100%; }
[class*="select2-container--krajee"] .select2-selection--single .select2-selection__clear {
  position: absolute; right: 26px; left: auto; top: 50%;
  transform: translateY(-50%); margin: 0; padding: 0 4px;
  font-size: 15px; font-weight: 700; line-height: 1; color: var(--text-placeholder);
}
[class*="select2-container--krajee"] .select2-selection--single .select2-selection__clear:hover { color: var(--status-danger-text); }
/* Select2 single geometry: pin the clear ✕ to the right, vertically centred (site.css's legacy rule
   floated it above), and undo krajee's 6px vertical padding, which pushed the text line 7px down. */
[class*="select2-container--krajee"] .select2-selection--single { position: relative; padding: 0 24px 0 12px; }
[class*="select2-container--krajee"] .select2-selection--single .select2-selection__rendered { padding: 0 24px 0 0; line-height: calc(var(--control-height) - 2px); }
[class*="select2-container--krajee"] .select2-selection--multiple .select2-selection__choice__remove {
  float: none; margin: 0; order: 2;
  font-size: 14px; line-height: 1;
}
[class*="select2-container--krajee"] .select2-selection--multiple .select2-search--inline .select2-search__field { margin: 0; height: calc(var(--control-height) - 6px); }
/* The MULTI placeholder is a floated span (krajee-bs3:343) — it wrapped to two lines inside the
   flexified selection.  Single line, ellipsized, vertically centred. */
[class*="select2-container--krajee"] .select2-selection--multiple .select2-selection__placeholder {
  float: none; margin: 0; max-width: 100%;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  line-height: calc(var(--control-height) - 4px);
}
/* Multiselect chips: text + ✕ centred on one line, and one chip row must not exceed the control
   height (it was ~38px). */
[class*="select2-container--krajee"] .select2-selection--multiple .select2-selection__choice {
  border-radius: var(--radius-sm);
  background: var(--surface-tint);
  border: 1px solid var(--border-default);
  color: var(--ok-green);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  line-height: 1.4;
  float: none;
  margin: 3px 4px 3px 0;
  padding: 1px 8px;
}
/* Client ruling, overriding the designer's documented intent: the solid dark-green dropdown
   highlight band reads too heavy — soften to mint. */
[class*="select2-container--krajee"] .select2-results__option--highlighted[aria-selected] { background-color: var(--brand-mint-bg); color: var(--ok-green); }
/* A multi-select must GROW instead of holding a fixed height, or wrapped chips break it — and the
   root cause of both "one chip makes it a two-liner" and "a long placeholder is still a two-liner"
   is a select2 VERSION difference.  The app ships select2 4.1, whose multi-select markup is

       .select2-selection--multiple
         > ul.select2-selection__rendered        (the chips, li.select2-selection__choice)
         > span.select2-search--inline
             > textarea.select2-search__field    (carries the PLACEHOLDER as an attribute)

   i.e. the search box is a SIBLING of the chip list, not an item inside it, and there is no
   `li.select2-selection__placeholder` element at all.  Two consequences:

   (a) a `…__rendered { display: flex; width: 100% }` written for the 4.0 markup (where the search
       really was inside the ul) makes the chip list claim the full row, so the sibling search span
       is pushed onto a second line the moment a single chip exists;
   (b) the search field is a <textarea> that select2 leaves at its intrinsic cols=20 width with
       `white-space: pre-wrap`, so a long placeholder wraps and gets clipped.

   Fix: hoist the chips into the selection's own flex context with `display: contents` so chips and
   the search share one wrapping row, let the search span take the remaining width, and make the
   textarea behave like a single-line input. */
[class*="select2-container--krajee"] .select2-selection--multiple {
  height: auto;
  min-height: var(--control-height);
  padding: 1px 6px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
}
/* …and the rendered UL itself must be a flex row, or the un-floated placeholder/search items stack
   vertically. */
[class*="select2-container--krajee"] .select2-selection--multiple .select2-selection__rendered {
  padding: 0;
  line-height: normal;
  flex-wrap: wrap;
  align-items: center;
  width: 100%;
  display: contents;  /* supersedes the earlier flex/width:100% on this element */
}
[class*="select2-container--krajee"] .select2-selection--multiple .select2-search--inline {
  float: none;
  display: inline-flex;
  align-items: center;
  flex: 1 1 65px;  /* 65px = select2's own min-width for the field */
  min-width: 0;
}
[class*="select2-container--krajee"] .select2-selection--multiple .select2-search__field {
  width: 100% !important;   /* beats the inline width select2's JS writes on the textarea */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  resize: none;
}
/* Select2 inside an AJAX-loaded dialog looked foreign, for two reasons.
   (a) The arrow was never actually restyled: only its HEIGHT was re-set, so the rest still came from
       select2-krajee-bs3.css:71-94 — `border-left: 1px solid #aaa` plus right-side border radii (the
       boxed "segment") and a solid CSS-triangle `b` in #888.  Every other dropdown in OKIS is a
       native <select>, which the browser draws as a thin chevron in the control's own text colour;
       that is why this one stood out.  Reshaped below to the same thing: no segment, no divider, a
       1.5px chevron in currentColor.
   (b) THE WHOLE WIDGET reverts to vendor styling inside a dialog, and this cannot be fixed by load
       order.  A form loaded by AJAX into a bsdialog registers its asset bundles for the first time
       THERE, so select2.css / select2-addl.css / select2-krajee-bs3.css / kv-widgets.css are
       appended into the modal body — i.e. AFTER every stylesheet in <head>.  Document order then
       favours the vendor and every override of ours that merely TIED on specificity silently lost.
       The select2 layer is therefore restated ONE class level higher via a `:root ` prefix: a
       pseudo-class counts as class-level specificity, and `:root X` matches exactly what `X`
       matched, so ties become wins and the widget renders identically whenever the vendor sheet
       loads. */
:root [class*="select2-container--krajee"] .select2-selection {
  border-color: var(--border-default);
  border-radius: var(--radius-control);
  box-shadow: none;
  background: var(--surface-input);
  font-size: 13px;
}
:root [class*="select2-container--krajee"] .select2-selection--single {
  height: var(--control-height);
  padding: 0 24px 0 12px;
}
:root [class*="select2-container--krajee"] .select2-selection--single .select2-selection__rendered {
  padding: 0 24px 0 0;
  line-height: calc(var(--control-height) - 2px);
}
:root [class*="select2-container--krajee"] .select2-selection--multiple {
  height: auto;
  min-height: var(--control-height);
  padding: 1px 6px;
}
:root [class*="select2-container--krajee"] .select2-selection--single .select2-selection__arrow {
  border: none;
  border-radius: 0;
  background: transparent;
  width: 22px;
  right: 1px;
  height: calc(var(--control-height) - 2px);
}
:root [class*="select2-container--krajee"] .select2-selection--single .select2-selection__arrow b {
  border: solid currentColor;
  border-width: 0 0 1.5px 1.5px;
  border-radius: 1px;
  width: 7px;
  height: 7px;
  margin: 0;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -70%) rotate(-45deg);
}
:root [class*="select2-container--krajee"].select2-container--open .select2-selection--single .select2-selection__arrow b {
  border-width: 0 0 1.5px 1.5px;
  transform: translate(-50%, -20%) rotate(135deg);
}
/* State rules must stay ABOVE the base block's new specificity, so they are prefixed too. */
:root [class*="select2-container--krajee"].select2-container--focus .select2-selection,
:root [class*="select2-container--krajee"].select2-container--open .select2-selection {
  border-color: var(--ok-green);
  box-shadow: var(--ring-focus);
}
/* A disabled select2 is a full-size control, so it takes --surface-disabled-field and the muted ink
   and matches the disabled native select beside it — see the disabled block at the end of
   `2b. BASE / form controls`. */
:root [class*="select2-container--krajee"].select2-container--disabled .select2-selection { background-color: var(--surface-disabled-field); cursor: not-allowed; }
:root [class*="select2-container--krajee"].select2-container--disabled .select2-selection__rendered { color: var(--text-muted); }
:root .has-error [class*="select2-container--krajee"] .select2-selection { border-color: var(--status-danger); }
:root .select2-dropdown {
  border-color: var(--ok-green);
  border-radius: var(--radius-control);
  box-shadow: var(--shadow-dropdown);
}
:root .select2-results__option { padding: 7px 12px; }
:root .select2-results__option[aria-selected="true"] { background: var(--surface-tint); color: var(--ok-green); }
:root [class*="select2-container--krajee"] .select2-results__option--highlighted[aria-selected] {
  background-color: var(--brand-mint-bg);   /* client decision: mint, not solid green */
  color: var(--ok-green);
}
/* Select2 in a Bootstrap `.input-group` read as two controls: the field kept all four 6px corners
   while the appended button kept its own `0 6px 6px 0`, so the rounded right edge of the field pushed
   into the square left edge of the tinted addon.  ROOT CAUSE: every corner-flattening rule in the
   input-group system keys off `.form-control`, but krajee renders the visible control as
   `span.select2-selection` and leaves the real `.form-control` (the source <select>) hidden at 1px —
   so nothing ever flattened the widget's corners.  The geometry was already right; the radius was the
   whole artifact. */
:root .input-group > [class*="select2-container--krajee"]:not(:last-child) .select2-selection {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}
/* Symmetric case (prepended addon). No live instance found to measure — the hidden <select>
   always precedes the widget, so the prepend has to be matched on the group, not the widget. */
:root .input-group > .input-group-addon:first-child ~ [class*="select2-container--krajee"] .select2-selection,
:root .input-group > .input-group-btn:first-child ~ [class*="select2-container--krajee"] .select2-selection {
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
}
:root .has-success [class*="select2-container--krajee"] .select2-selection { border-color: var(--ok-green); }
/* ---------- A multi-select's inline search draws no box of its own ----------
   With the container wearing the focus ring, a SECOND green rectangle sat 3px inside it: the inline
   search input.  Two concentric green boxes for one control, from a stack of three stylesheets nobody
   meant to combine — select2's own CSS gives the inline field `border: none`; AdminLTE.min.css puts it
   back (`.select2-dropdown .select2-search__field, .select2-search--inline .select2-search__field
   { border: 1px solid #D2D6DE }` with a #3C8DBC focus variant); skin.css then recolours THAT focus
   border to `--main-color`, so the app's own brand green is what draws the inner box.

   The DROPDOWN half of AdminLTE's pair is deliberately left alone: in a single-select's dropdown that
   input is a real field standing on white, and its box is the only thing that says so.  Only the
   INLINE half is wrong, because there the container is already the field.
   (0,3,0) / (0,4,0) against AdminLTE's (0,2,0) / (0,3,0) and skin.css's (0,3,0), and later than all
   three. */
[class*="select2-container--krajee"] .select2-search--inline .select2-search__field,
[class*="select2-container--krajee"] .select2-search--inline .select2-search__field:focus {
  border: 0;
  outline: none;
  box-shadow: none;
  background: transparent;
}

/* ============================================================================================
   2d. BASE / buttons - geometry, states and the paint families
   ============================================================================================ */
/* Consistent height, real hover shades */
.btn {
  border-radius: var(--radius-control);
  padding: 7px 14px;
  line-height: 20px;
  transition: background-color 120ms, border-color 120ms, transform 80ms, box-shadow 120ms;
}
.btn-xs { padding: 2px 8px; line-height: 18px; }
.btn-sm { padding: 4px 10px; line-height: 18px; }
/* The login page's two large submits, back to the height they had.  `.btn-lg` is a no-op in this
   app: the canonical `.btn` above restates padding AND line-height at the same (0,1,0) and loads
   later — the very reason `--xs` and `--sm` are restated two lines up — and on top of that the
   `.btn-cta` these buttons also carry pins a 36px height in the layer below.  Both submits
   therefore came out 36px, the height of a regular button, against the 46px they used to be.
   Scoped and not restated globally: the only other SIZE_LARGE in the tree sits in a box header,
   where adminlte's `.box-header-buttons a { padding: 3px 6px }` (0,1,1) governs the box and a
   global `.btn-lg` would change nothing but the line-height — breaking the one-height header row
   (measured 28px -> 25px, beside a 26px sibling).  Bootstrap's own large padding and its 24px line
   box at the 18px `.login-box .btn` size; `height: auto` hands the box back to them.  Not the 6px
   radius bootstrap also gives `.btn-lg` — radii belong to the design system now. */
.login-box .btn-lg {
  padding: 10px 16px;
  line-height: 24px;
  height: auto;
}
.btn-default { color: var(--ok-green); border-color: var(--border-strong); background-color: var(--surface-card); }
.btn-default:hover, .btn-default:focus { background-color: var(--brand-mint-bg); border-color: var(--border-strong); color: var(--ok-green); }
.btn-primary:hover, .btn-primary:focus, .btn-primary:active, .btn-primary:active:focus {
  background-color: var(--ok-orange-dark) !important;  /* the `!important` is load-bearing:
      `.content-wrapper .btn-primary { background: #fff !important }` is the same (0,2,0) WITH
      importance, so only importance plus later order keeps this one ahead of it. */
  border-color: var(--ok-orange-dark);
  opacity: 1;
}
.btn-success:hover, .btn-success:focus, .btn-success:active, .btn-success:active:focus {
  background-color: var(--ok-green-dark) !important;
  border-color: var(--ok-green-dark);
  opacity: 1;
}
.btn-box-tool { color: var(--ok-green); }
.btn-danger { background: var(--surface-card) !important; border-color: var(--status-danger-border); color: var(--status-danger-text); }
.btn-danger:hover { opacity: 1; background: var(--status-danger-wash) !important; border-color: var(--status-danger-text); color: var(--status-danger-text); }
.btn-group:has(> .btn-gold) { display: inline-flex; align-items: center; }
.btn-group > .btn-gold + .btn-success:hover { background: var(--ok-orange-dark) !important; border-color: var(--ok-orange-dark); color: var(--text-inverse); }
.btn-group > .btn-gold { border-radius: var(--radius-control) 0 0 var(--radius-control) !important; }
.btn:active { transform: translateY(1px); }
/* Box-header collapse tool rotates */
.btn-box-tool .fa { transition: transform 200ms; }
.collapsed-box .btn-box-tool .fa-plus { transform: rotate(0deg); }
/* Focus visible everywhere (keyboard users) */
a:focus-visible, .btn:focus-visible { outline: none; box-shadow: var(--ring-focus); }
.btn.disabled:active, .btn[disabled]:active { transform: none; }
/* Navbar search: quiet ghost — bell/user/logout stay orange, search recedes */
.navbar-custom-menu .input-group-btn .btn {
  background: var(--surface-card) !important; border-color: var(--border-strong) !important; color: var(--ok-green) !important;
}
/* ---------- Toolbar entity "+" segment ----------
   The attached "+" beside Smlouvy / Obchodní případ / Pojistné události / Předměty, in brand green:
   it is not a page CTA but one segment of a navigation tile, it repeats three or four times in the
   same row, and at that count orange stops meaning "the one action here".  Green is also what makes
   the segment read as part of the `.btn-gold` tile it is attached to.  (The orange CTA ruling covers
   the title-row Uložit disc and the page-level "Nový X" actions, which are the only orange left.)

   THE BLOCK MUST STAY, even though it looks like a plain restatement: three earlier variants of this
   segment (a detached round green dot, a gold one, and an orange `!important` one) all share this
   exact selector in the merged sources, so the LAST declaration in the cascade decides and it has to
   be this one.  The selector is repeated verbatim so the scope cannot widen, and it wins the tie on
   load order. */
.btn-group > .btn-gold + .btn-success {
  align-self: center;
  margin-left: -1px;
  height: auto;
  padding: 7px 10px;
  border-radius: 0 var(--radius-control) var(--radius-control) 0 !important;
  line-height: 20px;
  background: var(--brand-green) !important;
  border-color: var(--brand-green);
  color: var(--text-inverse);
  /* ONE size in both toolbar modes (user ruling).  Text mode sized the segment from `.btn` padding
     (~33px) while icon mode pins the 36px tile, so once the segment gained a `title` it flipped
     between the two.  Pinned to the icon-mode tile. */
  width: var(--size-toolbar-icon-tile);
  padding-left: 0;
  padding-right: 0;
  text-align: center;
}
.btn-group > .btn-gold + .btn-success:hover,
.btn-group > .btn-gold + .btn-success:focus,
.btn-group > .btn-gold + .btn-success:active {
  background: var(--brand-green-dark) !important;
  border-color: var(--brand-green-dark);
  color: var(--text-inverse);
}

/* ============================================================================================
   2e. BASE / boxes and surfaces
   ============================================================================================ */
.popover { border-radius: var(--radius-box); }
/* Tabs: quiet text on page bg, active = green with gold underline (pairs with title bar) */
.nav-tabs-custom { background: transparent; box-shadow: none; border-radius: 0; }
.nav-tabs-custom > .nav-tabs, .nav-tabs { border-bottom: 1px solid var(--border-default); }
.nav-tabs > li { margin-right: 26px; margin-bottom: -1px; }
.nav-tabs > li > a, .nav-tabs-custom > .nav-tabs > li > a {
  border: none !important; border-bottom: 3px solid transparent !important;
  border-radius: 0; background: transparent !important; color: var(--text-muted); padding: 10px 2px; margin: 0;
}
.nav-tabs > li > a:hover { color: var(--ok-green); }
.nav-tabs > li.active > a, .nav-tabs > li.active > a:hover, .nav-tabs > li.active > a:focus,
.nav-tabs-custom > .nav-tabs > li.active > a {
  border-bottom-color: var(--ok-gold) !important; color: var(--ok-green); font-weight: 600;
}
.nav-tabs-custom > .tab-content { background: transparent; padding: 16px 0 0; border-radius: 0; }
/* Dropdowns fade in */
.dropdown-menu {
  border-radius: var(--radius-dropdown);
  box-shadow: var(--shadow-dropdown);
  border-color: var(--border-default);
  animation: ok-pop 140ms cubic-bezier(.2,.6,.3,1);
  transform-origin: top;
}

/* ============================================================================================
   2f. BASE / tables and pagination
   ============================================================================================ */
/* ---------- Grid / tables / pagination (kills stock-BS3 blue leak) ---------- */
.table > thead > tr > th { border-bottom-color: var(--border-strong); }
.table-hover > tbody > tr:hover { background-color: var(--surface-tint); }
.table > thead > tr > th, .table > tbody > tr > td { border-color: var(--border-default); }
.table-bordered, .table-bordered > thead > tr > th, .table-bordered > tbody > tr > td { border-color: var(--border-default); border-left: none; border-right: none; }
.table > thead > tr > th { border-bottom: 2px solid var(--border-default); }
/* Row states in grids: success = mint, danger = orange light */
.table > tbody > tr.success > td { background-color: var(--panel-success-bg) !important; color: var(--ok-green); }
.table-hover > tbody > tr.success:hover > td { background-color: var(--ok-mint) !important; }
.table > tbody > tr.danger > td { background-color: #FFDDD2 !important; color: var(--panel-danger-text); }
.table-hover > tbody > tr.danger:hover > td { background-color: var(--ok-orange-light) !important; }
/* The zebra kill used to stand here; it is now stated above the hover rule — see that note. */
.table > tbody > tr { transition: background-color 120ms; }
.table > tbody > tr > td { padding-top: 10px; padding-bottom: 10px; }
.table-bordered { border: none; }
.table-bordered > thead > tr > th, .table-bordered > tbody > tr > td { border-left: none; border-right: none; }

/* ============================================================================================
   2g. BASE / layout chrome
   ============================================================================================ */
.main-header .navbar .btn-primary:hover { background-color: var(--ok-orange-dark) !important; }
/* ---------- Chrome ---------- */
.main-header .logo .logo-lg img { image-rendering: auto; }
.progress, .progress-bar { border-radius: var(--radius-pill); }
.main-footer { border-top: none; }
/* Quiet buttons: btn-primary becomes ghost in the content area; header search stays orange */
.content-wrapper .btn-primary {
  background: var(--surface-card) !important;
  border-color: var(--border-strong);
  color: var(--ok-green);
}
.content-wrapper .btn-primary:hover, .content-wrapper .btn-primary:focus,
.content-wrapper .btn-primary:active, .content-wrapper .btn-primary:active:focus {
  background: var(--surface-tint) !important;
  border-color: var(--ok-green);
  color: var(--ok-green);
}
.skin-blue .main-sidebar .sidebar .sidebar-menu > li:hover > a { background: var(--surface-tint); border-left-color: transparent; color: var(--ok-green) !important; }
.skin-blue .main-sidebar .sidebar .sidebar-menu > li.active > a { background: var(--surface-tint); border-left-color: var(--ok-orange); color: var(--ok-green) !important; font-weight: 600; }
.main-header { box-shadow: 0 1px 4px rgba(0,40,35,.18); }
/* The sidebar keeps the brand mint, so the left edge stays recognisably OKIS. */
.skin-blue .wrapper, .skin-blue .main-sidebar, .skin-blue .left-side { background: var(--brand-mint-bg); }
.main-sidebar { border-right: none; }
.skin-blue .main-sidebar .sidebar .sidebar-menu > li > a { border-left: 3px solid transparent; background: transparent; color: var(--ok-green); }
.skin-blue .sidebar-menu > li > a:link, .skin-blue .sidebar-menu > li > a:visited { color: var(--ok-green); }
.skin-blue .main-sidebar .sidebar .sidebar-menu > li:hover > a { background: rgba(255,255,255,.55); color: var(--ok-green) !important; }
.skin-blue .main-sidebar .sidebar .sidebar-menu > li.active > a { background: var(--surface-card); border-left-color: var(--ok-orange); color: var(--ok-green) !important; }
.content-wrapper .btn-danger { background: var(--status-danger) !important; border-color: var(--status-danger); color: var(--text-inverse); }
.content-wrapper .btn-danger:hover { background: var(--status-danger-text) !important; border-color: var(--status-danger-text); color: var(--text-inverse); }
.content-wrapper .btn.btn-star { background: var(--surface-card) !important; border-color: var(--border-strong); color: var(--ok-gold); font-weight: 700; }
.content-wrapper .btn.btn-star:hover { background: var(--surface-tint) !important; border-color: var(--ok-gold); color: var(--brand-gold-dark); }
.content-wrapper .btn.btn-gold:hover, .content-wrapper .btn.btn-gold:focus,
.content-wrapper .btn.btn-gold:active { background: var(--ok-mint) !important; border-color: var(--ok-mint); color: var(--ok-green); }
/* Entity toolbar buttons are quiet white ghosts. */
.content-wrapper .btn.btn-gold {
  background: var(--surface-card) !important;
  border-color: var(--border-strong);
  color: var(--ok-green);
  font-weight: 400;
}
.content-wrapper .btn.btn-gold:hover { background: var(--brand-mint-bg) !important; border-color: var(--border-strong); color: var(--ok-green); }
.main-header .btn-user { background: var(--ok-gold) !important; border-color: var(--ok-gold); color: var(--ok-green); font-weight: 600; }
.main-header .btn-primary .badge { background: var(--surface-card) !important; color: var(--ok-orange) !important; }
.main-header .btn-logout { background: var(--ok-mint) !important; border-color: var(--ok-mint); color: var(--ok-green); }
.main-header .navbar .btn-primary.btn-user, .main-header .btn-user { background: var(--ok-orange) !important; border-color: var(--ok-orange); color: var(--text-inverse); font-weight: 400; }
.main-header .navbar .btn-primary.btn-user:hover { background: var(--ok-orange-dark) !important; border-color: var(--ok-orange-dark); color: var(--text-inverse); }
.main-header .navbar .btn-primary.btn-logout, .main-header .btn-logout { background: var(--ok-orange) !important; border-color: var(--ok-orange); color: var(--text-inverse); }
.main-header .navbar .btn-primary.btn-logout:hover { background: var(--ok-orange-dark) !important; border-color: var(--ok-orange-dark); color: var(--text-inverse); }
/* Active sidebar item matches page bg */
.skin-blue .main-sidebar .sidebar .sidebar-menu > li.active > a { background: var(--main-bg-color) !important; }
::selection { background: var(--ok-mint); color: var(--ok-green); }
/* Slim brand scrollbars */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: var(--radius-pill); border: 2px solid transparent; background-clip: content-box; }
::-webkit-scrollbar-thumb:hover { background-color: var(--ok-mint); }
::-webkit-scrollbar-track { background: transparent; }
/* Sidebar: icons align, active item slides */
.sidebar-menu > li > a { transition: background-color 150ms, border-color 150ms, padding-left 150ms; }
.sidebar-menu > li:hover > a { padding-left: 18px; }
.sidebar-menu > li > a > .fa { width: 22px; }
/* Notification badge: subtle pulse ring on load */
.main-header .badge { position: relative; }
.input-group-btn:last-child > .btn { border-radius: 0 var(--radius-control) var(--radius-control) 0; height: var(--control-height); background: var(--surface-tint); border-color: var(--border-default); color: var(--ok-green); }
.input-group-btn:last-child > .btn:hover { background: var(--brand-mint-bg); border-color: var(--border-strong); color: var(--ok-green); }
.input-group-btn:first-child > .btn { border-radius: var(--radius-control) 0 0 var(--radius-control); height: var(--control-height); }
/* Navbar search hover: keep white text on orange (dark-green leak fix) */
.main-header .navbar .btn-primary:hover, .main-header .navbar .btn-primary:focus,
.navbar-custom-menu .input-group-btn .btn:hover { background: var(--ok-orange-dark) !important; border-color: var(--ok-orange-dark); color: var(--text-inverse) !important; }
.navbar-custom-menu .input-group-btn .btn:hover, .navbar-custom-menu .input-group-btn .btn:focus {
  background: var(--brand-mint-bg) !important; border-color: var(--border-strong) !important; color: var(--ok-green) !important;
}
/* Submenu (treeview): stays light — no dark slab. Slightly recessed mint panel,
   indented items, active = white pill + orange dot; parent keeps its open state */
.skin-blue .sidebar-menu > li.treeview.menu-open > a,
.skin-blue .main-sidebar .sidebar .sidebar-menu > li.active.treeview > a { background: rgba(255,255,255,.55); color: var(--ok-green) !important; }
.skin-blue .sidebar-menu > li > .treeview-menu, .skin-blue .sidebar-menu .treeview-menu { background: rgba(0,80,70,.07) !important; padding: 4px 0; margin: 0; }
.skin-blue .sidebar-menu > li > .treeview-menu > li > a, .skin-blue .sidebar-menu .treeview-menu > li > a {
  color: var(--text-label); padding: 7px 5px 7px 38px; font-size: 13px;
  border-left: 3px solid transparent; transition: background-color 120ms, color 120ms;
}
.skin-blue .sidebar-menu .treeview-menu > li > a:hover { color: var(--ok-green) !important; background: rgba(255,255,255,.7); }
.skin-blue .sidebar-menu > li > .treeview-menu > li.active > a, .skin-blue .sidebar-menu .treeview-menu > li.active > a {
  color: var(--ok-green) !important; font-weight: 600; background: var(--surface-card) !important; border-left-color: transparent;
}
.skin-blue .sidebar-menu .treeview-menu > li > a > .fa { width: 16px; font-size: 7px; vertical-align: 2px; color: var(--ok-mint); }
.skin-blue .sidebar-menu .treeview-menu > li.active > a > .fa { color: var(--ok-orange); }
.skin-blue .sidebar-menu .treeview-menu > li.active > a > .fa:before { content: "\f111"; }
/* skin.css's `.navbar-custom-menu li > .btn` and `.sso-btn{height:34px!important}` fight the
   new 36px control height — unify the navbar: */
.navbar-custom-menu .btn { height: var(--control-height); }
.navbar-custom-menu .btn.sso-btn { height: var(--control-height) !important; } /* beats skin.css !important (later file, same weight) */
/* ---------- Type ----------
   The legacy metrics, by client decision, overriding the design manual's Inter 14px.  Same selector
   list as the designer's type rule; later file wins.  The Inter @font-face blocks above stay (an
   unreferenced font is never downloaded); delete them together with web/css/font/inter-*.woff2 if
   Inter is permanently off. */
body, .form-control, .btn, [class*="select2-container--krajee"] .select2-selection,
.dropdown-menu, .sidebar-menu .treeview-menu > li > a, .input-group-addon {
  font-family: "Inter", Helvetica, sans-serif;
  font-size: 13px;  /* the legacy size, by client decision; the family stays Inter */
}
/* The headings need their own rule because the one above also carries the 13px, and a heading's SIZE
   is not the body's.  `adminlte.css:40` lists `body, h1 … .h6` together on `Helvetica, sans-serif`, so
   the line above only ever recaptured the `body` half of it and every record title, box title and modal
   title still computed Helvetica while the app around them was Inter.  Same element/class selectors as
   that rule, so this wins on load order, and family only — the sizes stay wherever they are set. */
h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 {
  font-family: "Inter", Helvetica, sans-serif;
}
/* U5) Dropdown-toggle open state rendered vendored white-on-pale text (Export button). */
.content-wrapper .open > .dropdown-toggle.btn-primary,
.content-wrapper .open > .dropdown-toggle.btn-default,
.content-wrapper .open > .dropdown-toggle.btn-primary:hover,
.content-wrapper .open > .dropdown-toggle.btn-primary:focus {
  background: var(--surface-tint) !important;
  border-color: var(--ok-green);
  color: var(--ok-green) !important;
}
/* Production sidebar markup renders submenu parents WITHOUT the .treeview class the canonical
   selectors expect (the li carries only menu-open/active), so the open/hover parent state was
   silently dead.  Re-stated structurally via `:has(.treeview-menu)`. */
.skin-blue .main-sidebar .sidebar .sidebar-menu > li.menu-open > a,
.skin-blue .main-sidebar .sidebar .sidebar-menu > li.active:has(> .treeview-menu) > a {
  background: rgba(255, 255, 255, .55);
  color: var(--ok-green) !important;
}
.content { padding: var(--spacing-content-y) var(--spacing-content-x); }
.main-header .navbar .navbar-nav > li > .btn:hover,
.main-header .navbar .navbar-nav > li > .btn:focus,
.main-header .navbar .btn-primary.btn-user:hover, .main-header .btn-user:hover {
  background: var(--brand-mint-bg) !important;
  border-color: var(--border-strong) !important;
  color: var(--ok-green-dark) !important;
}
/* Unread count: a bold green number, no chip. `.badge` brings bootstrap's grey pill plus
   AdminLTE's palette !important, so all three of fill / radius / padding have to go. */
.main-header .navbar .badge, .main-header .btn .badge {
  background: transparent !important;
  background-color: transparent !important;
  color: var(--ok-green) !important;
  font-weight: 700;
  padding: 0 0 0 4px;
  border-radius: 0;
  box-shadow: none;
  min-width: 0;
}
/* ---------- The navbar bell with nothing unread ----------
   Client ruling: at zero the bell is not a button at all, just a white glyph and a white "0" on the
   green bar — the logout treatment — and the white chip is the signal that something is waiting.

   State by class, not by duplicated markup: views/layouts/header.php always emits
   `btn-notification` and adds `btn-notification--unread` only when the count is non-zero, so `:not()`
   on the modifier is what makes one selector cover both states.  The white-navbar block is (0,4,1)
   with its `> li >` chain, so the same chain plus these two classes lands at (0,6,1) and wins
   outright; `!important` throughout because that block declares it. */
.main-header .navbar .navbar-nav > li > .btn.btn-notification:not(.btn-notification--unread),
.main-header .navbar .btn-notification:not(.btn-notification--unread) {
  background: transparent !important;
  border-color: transparent !important;
  color: var(--text-inverse) !important;
  box-shadow: none;
}
.main-header .navbar .navbar-nav > li > .btn.btn-notification:not(.btn-notification--unread):hover,
.main-header .navbar .navbar-nav > li > .btn.btn-notification:not(.btn-notification--unread):focus,
.main-header .navbar .btn-notification:not(.btn-notification--unread):hover {
  background: rgba(255, 255, 255, .15) !important;
  border-color: transparent !important;
  color: var(--text-inverse) !important;
}
/* The count rides along: the navbar block above paints every `.badge` brand green, which would be
   invisible on the green bar. (0,5,0) against its (0,3,0). */
.main-header .navbar .btn-notification:not(.btn-notification--unread) .badge {
  color: var(--text-inverse) !important;
}
/* THE FIRST TOOLBAR BUTTON.  `p.pull-left` opens with `<span class="separator"></span>` on the
   contract / subject / incident update pages — an empty inline span whose entire effect is skin.css's
   `.separator { margin-right: 25px }`.  As the FIRST thing in the row it separates nothing and simply
   indents the toolbar 25px past every other row on the page.  `:first-child` is the whole condition:
   the same span used BETWEEN two groups keeps its 25px. */
.content p.pull-left > .separator:first-child { margin-right: 0; }

/* ============================================================================================
   2h. BASE / global polish
   ============================================================================================ */
@keyframes ok-pop { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }

/* ============================================================================================
   3b. COMPONENTS / chips
   ============================================================================================ */

/* ---------- Úkoly "Status" chips ----------
   The three states (from Comment::getCommentStatus) used to be a bare Font Awesome glyph in the raw
   system colours, inline-styled in the model; they are tinted chips in the 2026 palette now, reusing
   the shared chip metrics so the app has one chip shape.

   SCOPE — deliberately narrow.  The repaint targets `.comment-status` only, and the Bootstrap
   `.label-*` classes are left alone app-wide: their two real consumers carry unrelated meaning (the
   `label-info` "Kontakt" chip in the digital-sign envelope form, the `label-danger` "document
   deleted" chip built in web/js/modules.js), and repainting those would make "orange" mean two
   different things.  The comment grids' bootstrap row tints (tr.success / tr.info, from
   Comment::$color) are a separate, user-chosen colour and are NOT touched. */
.comment-status-cell {
  text-align: center;
}
/* success -> mint; the same "quiet positive" fill selected states use. */
.comment-status--done { background: var(--panel-success-bg); color: var(--ok-green); }
/* warning -> cream: still inside the due date, so it is a notice, not a problem. */
.comment-status--pending { background: var(--ok-cream); color: var(--panel-warning-text); }
/* danger -> light orange. The 2026 palette has no saturated red for content; overdue reads as
   the same alarm tint the "documents missing" pill uses below. */
.comment-status--overdue { background: var(--panel-danger-row-bg); color: var(--status-danger-muted); }
/* ---------- One entity chip for every list ----------
   The Entita column exists on both Avíza and Úkoly and used to render two different things: a mint
   chip on one, a bare full-height 34px LinkButton on the other — wide enough to read as a control
   rather than a label.  Both views now emit `search-chip entity-chip`, so the two cannot drift and
   any further list that grows an entity column inherits the look.

   The chip WRAPS the LinkButton rather than replacing it, so the link — and on Avíza the "mark as
   read on click" behaviour riding on it — is untouched; only the button's own chrome is stripped,
   leaving the chip's border as the single frame.  `.search-chip` supplies the pill, the border and
   the inline-flex; everything here is the list-cell fit.

   The chip is 26px like the rest of the chip family (2 + 18 + 4 plus the 1px border on each edge),
   but the RADIUS deliberately stays the pill and the type stays 13px: the shared metric is the SIZE,
   and the pill plus the mint tag glyph is what makes a chip read as a label rather than as a button.
   The left inset stays 2px wider than the right (12 vs 10) because the chip leads with the tag glyph
   and a pill needs more room on the side its corner cuts into; the two insets add up to the same 22px
   the base spends, so only their distribution differs.  Truncation is untouched — the inner `.btn`
   keeps nowrap + hidden + ellipsis and the chip keeps `max-width: 100%`.

   THE SELECTOR NEEDS BOTH CLASSES: `.search-chip`'s own `padding` shorthand is declared later in this
   file, so a single-class rule here loses the tie and the chip inherits the base's 5/5 — which is why
   it used to measure 30px.  Every emission point writes `search-chip entity-chip` together
   (notification/_grid.php, comment-duedate/_grid.php), so the compound selector always matches.

   THE VERTICAL PADDING IS 2/4, NOT 3/3 — the same optical compensation the state pill carries, see
   `.kv-grid__value > .kv-pill`.  Measured here with that rule's own reference strings: ink centre
   1.382px below the chip's at 3/3, 0.382px at 2/4.  The height stays 26. */
.search-chip.entity-chip {
  max-width: 100%;
  padding: 2px 10px 4px 12px;
  font-size: 13px;
  line-height: 18px;
  gap: 4px;
}
.entity-chip > .fa-tag {
  color: var(--ok-mint);
  flex: none;
}
.entity-chip > .btn {
  min-width: 0;
  max-width: 100%;
  height: auto;
  padding: 0;
  border: 0;
  background: none;
  box-shadow: none;
  color: var(--ok-green);
  font-size: 13px;
  line-height: 18px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* ---------- The Úkoly status chip is a square ----------
   Built from chip metrics meant for a chip holding a WORD (`min-width: 26px; padding: 3px 8px;
   font-size: 12px; line-height: 16px`), this chip holds a single 12px glyph — and those metrics then
   produce a flat pill whose width follows the glyph's advance width, three different widths, none of
   them square.

   Two separate causes, hence the two declarations.  The width came from `min-width` + 2x8px of side
   padding, i.e. from the TEXT metrics; the height came from the glyph alone (12 + 2x3), because in an
   inline-flex box the container's own `line-height` never applies — only the flex item's does.
   Stating both axes at 26px and dropping the padding makes the box a square that cannot follow the
   glyph, and `justify-content: center` keeps every glyph centred in it.  26px and not the 28px of the
   grid's action tiles next door: the chip is a status MARKER, not a control, and staying one step
   below the tiles keeps that reading.  `flex: none` is the "regardless of column squeeze" guarantee —
   the Status column is the narrowest in the grid.

   Same specificity as the palette rule above (one class), later in the file, so it wins on order —
   written as a separate block on purpose, so that rule stays the single place the colours live. */
.comment-status {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 26px;
  border-radius: var(--radius-sm);
  font-size: 12px;
  line-height: 16px;
  width: 26px;
  height: 26px;
  padding: 0;
  flex: none;
}

/* ============================================================================================
   3c. COMPONENTS / list filter bar — the inline bar that replaced the separate "Vyhledávání" box.
   SHARED by every index page: the values are the designer's, the per-page modifiers live further
   down and in the area sections, and the markup carries `list-filter-bar` plus the page's own class.
   This block stays AHEAD of the modifiers so they can override its basis.
   ============================================================================================ */

/* A one-line chip row fits the 50px fixed header, so no extra `.content` offset is needed.  Past
   roughly a dozen chips the row wraps and the fixed header grows — groupChipsModule.syncHeaderOffset()
   in web/js/modules.js measures that case and raises the offset at runtime. */
.list-filter-bar {
  display: flex;
  gap: 12px;
  align-items: flex-end;
  flex-wrap: wrap;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--border-default);
  margin-bottom: 6px;
}
.list-filter-bar__field .input-group { width: 100%; }
/* ActiveForm always emits the error container, empty or not. Left in place it would sit under
   each input and defeat `align-items: flex-end` (the fields would hang above the buttons). */
.list-filter-bar__field .help-block:empty { display: none; }
.list-filter-bar__actions {
  display: flex;
  gap: 8px;
  margin-left: auto;
}
/* The square clear-filter tile, on the control line. */
.list-filter-bar__actions .btn-clear-filter {
  width: var(--control-height);
  height: var(--control-height);
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
/* ---------- Filter bar field proportions ---------- */
.list-filter-bar__field--sm { flex: 1 1 170px; min-width: 170px; }
.list-filter-bar__field--lg { flex: 1.2 1 240px; min-width: 240px; }
/* ---------- The filter bar's action group stays on the input line ----------
   Two causes, both worth knowing.  (1) The bar is `align-items: flex-end`, which aligns MARGIN boxes:
   `.list-filter-bar__field` carries `margin: 0`, but `.form-group { margin-bottom: 10px }` is the
   same (0,1,0) and sits later in this file, so it won the tie and re-armed a 10px skirt under every
   field — the fields' border boxes ended 10px above the buttons.  (2) `Vyhledat` is a plain `.btn`
   (36px, deliberately off `--control-height`) while the inputs beside it are 34px; inside a filter
   bar the button IS a control on the input line, so here it takes the token.

   Restated at (0,2,0) rather than moved, so a later rhythm change to `.form-group` cannot take the
   bar with it again. */
.list-filter-bar .list-filter-bar__field { margin-bottom: 0; }
.list-filter-bar__actions .btn {
  height: var(--control-height);
  padding-top: 0;
  padding-bottom: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* `inline-flex` drops the whitespace-only node between the search button's glyph and its label
     (each run becomes an anonymous flex item and its edge whitespace is trimmed), so the gap
     has to be restated. Harmless on the icon-only ✕ beside it. */
  gap: 6px;
}
/* ---------- The client list's two-row filter bar ----------
   Everything except the second line is the SHARED bar: the hairline, the 12px gap,
   `align-items: flex-end`, the zeroed field margins, the 34px action buttons, the square clear tile.
   `--rows` turns the form back into a block container and moves the flex layout down one level, onto
   `__row`, because eight fields plus three actions cannot read as one row at any usable width.

   WHY `display: block` on the form and not `flex-wrap` with full-width rows: the form also carries the
   `show_inactive` hidden input, and `.form-control` on it (an old blank-and-submit handler needed the
   class) sets `display: block` — as a flex ITEM that would become a 34px empty box on the line.  As a
   block child of a block form it stays invisible.  `#advanced-search` is a block child too, so the
   extended fields open BELOW the two rows and inside the same card. */
.list-filter-bar--rows { display: block; }
.list-filter-bar__row {
  display: flex;
  gap: 12px;
  align-items: flex-end;
  flex-wrap: wrap;
}
.list-filter-bar__row + .list-filter-bar__row { margin-top: 10px; }
/* ---------- The list filter bar's header row ----------
   The card gets its title back and the action group moves up beside it, instead of sitting at the end
   of field row 2 where it read as a fourth field.

   The row renders INSIDE the form ("Vyhledat" is the submit and the toggle drives `#advanced-search`,
   both of which have to be within `ActiveForm`), so it cannot be the card's real `.box-header` — that
   element is a SIBLING of `.box-body`.  What it can do is borrow the header's two ingredients, and it
   does: `box-title` for the text and the shared `.list-filter-bar__actions`, whose `margin-left: auto`
   is the whole right-alignment mechanism.  Metrics follow `.box > .box-header`: `align-items: center`
   and a hairline below in the same `--border-default` the `.with-border` variant uses.  No side
   padding — the row sits in `.box-body`, whose inset is the card's, exactly as a header's is its own.
   The bar's OWN bottom hairline is untouched and still separates the whole filter from the grid. */
.list-filter-bar__head {
  display: flex;
  align-items: center;
  gap: 12px;
  padding-bottom: 10px;
  margin-bottom: 12px;
  border-bottom: 1px solid var(--border-default);
}
/* `.box-title` is an <h3>; AdminLTE zeroes its margin only as a descendant of a box header. */
.list-filter-bar__head .box-title { margin: 0; }
/* The search submit is the FILLED action of a filter bar — all three actions used to be the same white
   ghost, so nothing said which one runs the search.  Green and not orange: orange is the CTA family
   for actions that create or commit a RECORD, and running a search commits nothing.
   Scoped to `.list-filter-bar__actions` so the navbar's own "Vyhledat" (a deliberate ghost on the
   dark header) and the ghost buttons beside this one are out of reach.
   The FILL needs `!important` because the ghost it has to beat states `background: #fff !important`;
   the border and the ink win on count at (0,3,0). */
.list-filter-bar__actions .btn.btn-primary {
  background: var(--ok-green) !important;
  border-color: var(--ok-green);
  color: var(--text-inverse);
}
/* The bootstrap `.row`s of `#advanced-search` open BELOW the field rows and inside the same card, so
   they need the same 10px the rows give each other.  (Klienti's `.client-filter__advanced` was the
   page-private twin of this name and is now folded into it — that page's advanced block was the only
   one the flex rule at the end of this section never reached, so it was still a float row.) */
.list-filter-bar__advanced { margin-top: 10px; }
/* Field widths.  `min-width` is what decides wrapping for a flex item and `max-width` is what stops a
   select from eating the line, so each is a basis/min/max triple rather than a width.
   --date a DatePicker (six fit one 1500px line, which is what Pojistné události needs) · --cap a
   labelled select or short text field · --sel a Select2 · --grow the wide search term. */
.list-filter-bar__field--date { flex: 0 1 160px; min-width: 148px; max-width: 175px; }
.list-filter-bar__field--cap { flex: 1 1 180px; min-width: 170px; max-width: 210px; }
.list-filter-bar__field--sel { flex: 1 1 220px; min-width: 200px; max-width: 280px; }
.list-filter-bar__field--grow { flex: 3 1 320px; min-width: 300px; }
/* `__grid` — the escape hatch for a filter that CANNOT be a flex row: the report-filter family pairs
   its fields with the 212px account TreeViewInput.  Those blocks stay bootstrap and need the same
   10px `__advanced` gives, for the same reason.  Its own selector rather than folded into `__advanced`
   so the two intents stay legible; the value should move together. */
.list-filter-bar__grid { margin-top: 10px; }
/* A widget that emits SEVERAL fields inside one wrapper still owes the row its fields, not a box:
   RefModelSelector wraps its class half and its name half together, and as a single flex item the
   pair could only ever be one column of the bar.  `display: contents` drops the wrapper's box and
   lets the two halves take their own places on the line — the element stays in the DOM, which is
   what matters, because the widget's own JS finds its partner through `.parents('.ref-model-selector')`. */
.list-filter-bar__passthrough { display: contents; }
/* A filter row FILLS the card.  Every width modifier states a `max-width` and `--date` carries
   `flex-grow: 0` — right for what a FIELD may become on its own, wrong for what a ROW must do.  The
   user's ruling is that a row ends flush with the card edge, so inside a `--rows` bar the cap comes
   off and the leftover goes to the existing flex-grow weights (`--grow` keeps its three shares, which
   is what keeps the search term the widest field on its line).
   Scoped to `--rows` because a single-line bar puts its ACTION GROUP on the same flex line, so its
   fields must NOT eat the space the buttons need.  (0,3,0) against the modifiers' (0,1,0). */
.list-filter-bar--rows .list-filter-bar__row > .list-filter-bar__field { max-width: none; }
.list-filter-bar--rows .list-filter-bar__row > .list-filter-bar__field--date { flex-grow: 1; }
/* ---------- Every advanced row steps by the same 10px ----------
   `#advanced-search > .row` is a bootstrap FLOAT row, so its height is its tallest column and the short
   columns leave dead space underneath: the step from a short field to the row below it is not owned by a
   margin at all.  A panel with one wrapping label therefore showed three different gaps in one row.

   The base bar never had the problem because `.list-filter-bar__row` is a flex row with a shared control
   line, so the advanced rows get the SAME behaviour: bottom-aligned flex items put every control on one
   line and leave exactly one 10px `.form-group` margin between any field and the row below it.  A flex
   item establishes an independent formatting context, so that margin stops collapsing out of its column
   and becomes the gap itself — which is why the step is 10 from EVERY field, not only from the tallest.
   `flex-end` and not `stretch`: a label may legitimately need two lines, and the line that must agree is
   the CONTROL line, which is the bottom one.

   MEDIA QUERY: below 992px bootstrap's `.col-md-*` have no width and stack as blocks; as flex items they
   would shrink to their content and sit side by side, so this is scoped to the breakpoint where the
   columns actually have widths. */
@media (min-width: 992px) {
  .list-filter-bar__advanced > .row {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
  }
}
/* ---------- …and by the same 12px sideways ----------
   The vertical step above matched the base bar; the HORIZONTAL one did not.  `.list-filter-bar__row`
   is a flex row with `gap: 12px`, while an advanced row is bootstrap's grid, whose gutter is 15px of
   column padding on each side — 30px between neighbours, two and a half times the rhythm the two rows
   directly above it keep.

   Halving the gutter to 6px per side is the whole fix: the column WIDTHS stay percentages (border-box,
   so padding is inside them) and the row's negative margin still cancels the outer half, which is what
   keeps an advanced field flush with the card edge and with the base rows' first and last field.

   NOT `gap: 12px` with zeroed padding, which is the obvious move and is wrong: a wrapping flex container
   breaks lines on the items' HYPOTHETICAL sizes, before any shrinking, so two `col-md-6`s (50% + 50%)
   plus a 12px gap overflow and the second one wraps to its own line.  The gutter mechanism has no such
   problem because the padding is already inside the 50%.

   Outside the media query on purpose: below 992px the columns are full-width blocks and the pair still
   agrees — a smaller inset, still cancelled by the row's own margin. */
.list-filter-bar__advanced > .row { margin-left: -6px; margin-right: -6px; }
.list-filter-bar__advanced > .row > [class*="col-"] { padding-left: 6px; padding-right: 6px; }

/* ============================================================================================
   3d. COMPONENTS / box anatomy and form sections
   ============================================================================================ */
/* ---------- Boxes ---------- */
.box {
  border-radius: var(--radius-box);
  border: 1px solid var(--border-default);
  border-top-width: 1px;  /* AdminLTE has 3px status border-top */
  box-shadow: var(--shadow-box);
  transition: box-shadow 200ms cubic-bezier(.2,.6,.3,1), transform 200ms cubic-bezier(.2,.6,.3,1);
  margin-bottom: var(--spacing-box-gap);
}
.box.collapsed-box > .box-header { border-radius: calc(var(--radius-box) - 1px); }
.box > .box-footer { border-radius: 0 0 calc(var(--radius-box) - 1px) calc(var(--radius-box) - 1px); }
.form-actions { border-radius: var(--radius-box); }
.box .help-item-icon { color: var(--ok-mint); }
/* White box headers with green titles */
.box.box-solid.box-primary > .box-header,
.main-header + * .box-header, .box > .box-header {
  background: var(--surface-card) !important;
  color: var(--ok-green) !important;
}
.box.box-solid.box-primary { border-color: var(--border-default); }
.box.box-solid.box-default > .box-header { background: var(--surface-card) !important; color: var(--ok-green); }
.box-title { font-weight: 400; font-size: 16px; }
 /* pastel variant — was orange-light */
.box.box-solid > .box-header .btn.btn-default {
  border-radius: var(--radius-control);
  background: var(--surface-card);
  border: 1px solid var(--border-strong);
  color: var(--ok-green);
}
.box.box-solid > .box-header .btn.btn-default:hover { background: var(--surface-tint); }
/* The one real CTA is orange */
.content-wrapper .btn-success, .form-actions .btn-success {
  background: var(--ok-orange) !important;
  border-color: var(--ok-orange);
  color: var(--text-inverse);
}
.content-wrapper .btn-success:hover, .form-actions .btn-success:hover,
.content-wrapper .btn-success:focus, .content-wrapper .btn-success:active {
  background: var(--ok-orange-dark) !important;
  border-color: var(--ok-orange-dark);
}
.box, .box.box-solid.box-primary { border: none !important; box-shadow: 0 1px 3px rgba(0,60,50,.07), 0 6px 20px rgba(0,60,50,.06); }
.box > .box-header.with-border { border-bottom: 1px solid #EEF5F1; }
.form-actions, .box-body .form-actions {
  box-shadow: 0 1px 3px rgba(0,60,50,.07), 0 6px 20px rgba(0,60,50,.06);
  background: var(--ok-cream) !important;
  border: none;
}
.box:hover { box-shadow: 0 2px 6px rgba(0,60,50,.08), 0 10px 28px rgba(0,60,50,.09); }
/* The collapse/expand tool was white-on-white once box headers went white.  AdminLTE.min.css sets
   `.box.box-solid.box-primary > .box-header .btn { color: #fff }` at (0,5,0), which beats a plain
   `.btn-box-tool` (0,1,0) regardless of load order.  Matched with an equal-specificity selector (five
   classes, via a `.content-wrapper` prefix); our file loads after AdminLTE.min.css, so the tie
   resolves in our favour. */
.content-wrapper .box .box-header .btn.btn-box-tool { color: var(--ok-green); }
.content-wrapper .box .box-header .btn.btn-box-tool:hover { color: var(--ok-green-dark); }
/* A bare header-less wrapper `.box` (legacy page scaffolding around the real boxes on the
   client/contract/dashboard update pages) must not render as a card — boxes float on the page
   background.  `:not(.form-card)` is the escape hatch: a CREATE page's box IS the card, and two of
   them happen to hold a sub-section box, which this rule cannot tell apart from scaffolding, so those
   views say so in markup.  See the `.form-card` note further down. */
.content .box:not(.form-card):not(:has(> .box-header)):has(.box) {
  background: transparent !important;
  box-shadow: none !important;
  border: none;
  border-radius: 0;
}
.content .box:not(.form-card):not(:has(> .box-header)):has(.box):hover { box-shadow: none !important; }
.content .box:not(.form-card):not(:has(> .box-header)):has(.box) > .box-body { padding: 0; }
.box > .box-header .box-header-buttons a { margin: 0; }
.box > .box-header .box-header-buttons + .box-tools,
.box > .box-header .box-tools:only-of-type { margin-left: auto; }
.box > .box-header .box-header-buttons ~ .box-tools { margin-left: 8px; }
/* ---------- Form sections ----------
   Section grouping inside a form box body (Subjekt / Zařazení / Adresa + the merged Korespondenční
   adresa sub-block).  The designer's mock carried these as inline styles; they are classes here. */
.form-section-label {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-muted);
  border-bottom: 1px solid var(--border-default);
  padding-bottom: 6px;
  margin: 6px 0 14px;
}
/* Quieter sub-section label: no rule, no uppercase. Declared after the block so it also wins
   when both classes are applied to the same element. */
.form-section-label--sub {
  font-size: 12px;
  font-weight: 400;
  letter-spacing: normal;
  text-transform: none;
  color: var(--text-muted);
  border-bottom: 0;
  padding-bottom: 0;
  margin: 2px 0 10px;
}
/* Collapsible section: the heading itself is the toggle, with a small +/− chip pinned to the
   right edge — same semantics as a box collapse (+ = hidden, − = open). <details>/<summary>
   carries the open state, so no JS is involved and the state survives a re-render. Used by the
   "Korespondenční adresa" sub-section of the client form (mocks 7a/7b). */
.form-section-collapse > summary.form-section-label--toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  list-style: none;
}
.form-section-collapse > summary::-webkit-details-marker {
  display: none;
}
.form-section-collapse > summary:hover {
  color: var(--ok-green);
}
.form-section-collapse:not([open]) > summary .form-section-label__chip:before {
  content: "+";
}
.form-section-collapse[open] > summary .form-section-label__chip:before {
  content: "\2212";
}
/* The collapse chip belongs on the header's RIGHT edge, and neither flex order nor a margin can put
   it there.  DOM order inside `.box-header` is title -> help icon(s) -> `.box-tools` ->
   `.box-header-buttons`, so once the header became a flex row the chip landed BEFORE the buttons and
   the `margin-left: auto` rules could never match that order.  Flex `order` is not enough either: in a
   narrow right-hand column the header WRAPS and the chip then drops to a second line and aligns left.
   So the chip comes out of the flex flow entirely and is pinned to the header's top-right corner —
   deterministic in both the wide and the wrapping case — with `padding-right` reserving its column so
   the header buttons can never collide with it.  `.box-header` is already position:relative
   (AdminLTE). */
.box > .box-header:has(> .box-tools) { padding-right: 48px; }
.box > .box-header > .box-tools { position: absolute; right: 10px; top: 2px; margin: 0; }
/* Collapse chip: one glyph only, ever.  The chip is an empty <span> whose +/− comes from `:before`
   and the two state rules are mutually exclusive.  Belt-and-braces from the mock: the chip's own
   font-size is zeroed so a literal text node inside it could never render alongside the
   pseudo-element, and the pseudo-element gets the 11px back. */
.form-section-label__chip {
  display: inline-flex;
  width: 16px;
  height: 16px;
  align-items: center;
  justify-content: center;
  margin-left: auto;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  line-height: 1;
  color: var(--ok-green);
  font-size: 0;
}
.form-section-collapse > summary .form-section-label__chip:before { font-size: 11px; }
/* Vertical rhythm above a sub-section heading.  The heading carries only `.form-section-label`'s own
   `margin: 6px 0 14px`, so a grid ending directly above it left a 6px gap.  Taken as margin rather
   than as the mock's <hr>: the <hr> was deliberately dropped when these sub-sections lost their nested
   `.box` chrome (`.form-section-label` already draws its own bottom rule, so an <hr> above would box
   the heading between two lines), and one rule cannot drift out of sync across the five _documents.php
   copies and the comments partial the way six <hr>s could.  26px = the mock's 20px hr margin + the
   heading's own 6px.  `:not(:first-child)` keeps the gap off a heading that OPENS a box body, where
   the body padding already provides it; the second rule keeps it off a heading that follows form
   fields, whose `.row` siblings already end in a form-group's bottom margin.  Equal specificity
   (0,4,2) — the reset wins on order. */
.box-body > details.form-section-collapse:not(:first-child) > summary.form-section-label {
  margin-top: 26px;
}
.box-body > .row + details.form-section-collapse > summary.form-section-label {
  margin-top: 6px;
}
.box-body { padding: var(--spacing-box-body-top) var(--spacing-box-body-x) var(--spacing-box-body-bottom); }
.box > .box-header .box-title { padding: 0; }
.box > .box-header .box-header-buttons {
  float: none;
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--spacing-inline-gap);
  margin: 0 0 0 auto;
}
/* ---------- The sub-section create button ----------
   The button inside a collapsible sub-section heading rendered as a huge all-caps pill, because
   `text-transform` and `letter-spacing` are INHERITED properties and it picked up
   `.form-section-label`'s `uppercase` + `.06em` straight from its <summary> parent.  Font size and
   weight are restated as well so it can never inherit the label's 12px/600 either — `.btn` is (0,1,0)
   and would lose to any future rule on the heading.

   The padding matches the box-header buttons directly above it, which are 28px not by design of ours
   but by arithmetic: adminlte.css's `.box-header-buttons a { padding: 3px 6px }` (0,1,1) beats `.btn`'s
   `padding: 7px 14px`, and 3 + 20 line-height + 3 + 2 border = 28.  Stated as the same padding rather
   than a hard-coded height so a future change to the header buttons carries.  The icon-mode rule
   squares this button separately and outranks this one, so that mode is unaffected. */
.form-section-label--toggle .btn { font-size: 13px; font-weight: 400; letter-spacing: normal; text-transform: none; padding: 3px 6px; }
/* ---------- One box-header height ----------
   Box headers: title left, buttons on the same row right, wrapping gracefully in a narrow column
   instead of dropping to an awkward centred second line.  The header gets a real 8px padding box;
   until now it had none (adminlte.css's `.box-header { padding: 0 }`) and the title's own 10px stood in
   for it, which is why both move together — leaving the title's padding in place would double the
   inset.

   `min-height` and not padding, because the ask is that a header WITHOUT a button match one WITH it,
   so the padded ones must come out exactly as they are: a header carrying a 28px header button
   measures 8+28+8+1 = 45px while a header with nothing but its title measured 8+18+8+1 = 35px, a
   visible 10px step between two collapsed boxes standing on each other.  45px on a border-box header
   leaves every header that already reaches it untouched and grows the header-only ones into the same
   line.  The collapse tool is NOT what sets the height — it is absolutely positioned, which is also
   why the header reserves 48px of right padding for it. */
.box > .box-header {
  border-radius: calc(var(--radius-box) - 1px) calc(var(--radius-box) - 1px) 0 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 10px;
  padding: 8px;
  min-height: 45px;
}
/* The in-card action row: a right-aligned button row that opens a card's results block, sitting
   between the filter bar's hairline and the grid.  The gap is the button-row gap every other toolbar
   uses; the bottom margin is the 6px the filter bar already leaves above the grid, so the row lands on
   the card's existing rhythm rather than inventing one.  Nothing sizes the buttons — they keep the
   free-standing 36px deliberately, because they are in the scrolling content, not in the fixed
   header. */
.card-toolbar {
  display: flex;
  justify-content: flex-end;
  gap: var(--spacing-inline-gap);
  margin-bottom: 6px;
}
/* ---------- The floating .form-actions bar is promoted into the title row ----------
   `promoteFormActionsToTitleRow()` (web/js/scripts.js) adds this class ONLY after it has successfully
   built the title-row tiles, so the page can never end up with neither — the mechanism fails safe by
   leaving the bar exactly as it is.

   HIDDEN, NOT REMOVED, and this is the data-loss trap: the `input.action-save` inside the bar is what
   the title tile clicks, it is where every page-specific submit handler is bound, and its
   `name=action-save` still has to reach the POST.  `display: none` keeps it in the DOM and clickable
   via `.trigger('click')`.

   Scoped to the promoted class rather than written as a blanket rule, because `.form-actions` is also
   the DIALOG footer's source markup (showDialog() copies its HTML into `.bsdialog-footer`) and the ~13
   pages whose bar carries a labelled action of its own keep theirs. */
.form-actions.form-actions--promoted { display: none; }

/* ============================================================================================
   3e. COMPONENTS / grid and key-value list
   ============================================================================================ */
.pagination > li > a, .pagination > li > span { color: var(--ok-green); border-color: var(--border-default); }
.pagination > li:first-child > a, .pagination > li:first-child > span { border-radius: var(--radius-control) 0 0 var(--radius-control); }
.pagination > li:last-child > a, .pagination > li:last-child > span { border-radius: 0 var(--radius-control) var(--radius-control) 0; }
.pagination > .active > a, .pagination > .active > a:hover, .pagination > .active > a:focus,
.pagination > .active > span {
  background-color: var(--ok-green);  /* was stock #337ab7 blue */
  border-color: var(--ok-green);
  color: var(--text-inverse);
}
.kv-grid-table .skip-export.kv-align-center a { border-radius: var(--radius-control); }
.kv-grid-table thead tr th { background: transparent; font-weight: 600; color: var(--text-label); }
.kv-grid-table thead tr.filters td { background: transparent; }
.summary { color: var(--text-muted); font-size: 13px; }
/* Grid action buttons: square icon buttons (matches production) */
.kv-grid-table .btn-xs, .table .btn-xs {
  width: var(--size-grid-action-btn); height: var(--size-grid-action-btn); padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  line-height: 1;
}
/* Grid checkboxes: same language as form checkboxes, compact */
.kv-grid-table input[type="checkbox"], .table input[type="checkbox"] {
  appearance: none; -webkit-appearance: none; position: static; margin: 0;
  width: var(--size-checkbox-grid); height: var(--size-checkbox-grid); cursor: pointer;
  background: var(--surface-input); border: 1px solid var(--border-default); border-radius: var(--radius-sm);
  display: inline-grid; place-content: center; vertical-align: middle;
  transition: border-color 120ms, background-color 120ms;
}
.kv-grid-table input[type="checkbox"]:hover, .table input[type="checkbox"]:hover { border-color: var(--border-strong); }
.kv-grid-table input[type="checkbox"]:checked, .table input[type="checkbox"]:checked { background: var(--ok-green); border-color: var(--ok-green); }
.kv-grid-table input[type="checkbox"]:checked::before, .table input[type="checkbox"]:checked::before {
  content: ""; width: 11px; height: 11px; background: var(--text-inverse);
  clip-path: polygon(14% 44%, 0 65%, 40% 100%, 100% 16%, 84% 0%, 38% 68%);
}
/* Grid softening: rounded tinted header band, no hard side borders */
.kv-grid-table { border-collapse: separate; border-spacing: 0; }
.kv-grid-table > thead > tr.filters > td { background: transparent; border: none; padding-top: 10px; padding-bottom: 4px; }
.kv-grid-table > tbody > tr > td { border-top: none; border-bottom: 1px solid var(--border-default); }
.kv-grid-table > tbody > tr:last-child > td { border-bottom: none; }
/* Datepicker calendar addon in filter rows: rounded + tinted like other addons */
.input-group.date .input-group-addon, .kv-grid-table .filters .input-group-addon,
.krajee-datepicker + .input-group-addon {
  border-radius: var(--radius-control) 0 0 var(--radius-control);
  background: var(--surface-tint); border-color: var(--border-default); color: var(--ok-green);
}
/* Row selection: calm sky tint, NOT danger red.  Needs
   `CheckboxColumn 'rowSelectedClass' => 'kv-row-select'` (krajee's default is 'danger'). */
.kv-grid-table > tbody > tr.kv-row-select > td { background: var(--pastel-sky-light) !important; color: var(--pastel-sky-text); }
.kv-grid-table > tbody > tr.kv-row-select:hover > td { background: var(--ok-sky) !important; }
.input-group .input-group-addon:last-child { border-radius: 0 var(--radius-control) var(--radius-control) 0; }
.input-group .input-group-addon:first-child { border-radius: var(--radius-control) 0 0 var(--radius-control); }
/* Grid action buttons: uniform square icon tiles (they were a mix of btn/btn-sm sizes).  This
   higher-specificity rule keeps the non-btn-xs strays at the same size. */
.grid-view .action-column .btn {
  width: var(--size-grid-action-btn); height: var(--size-grid-action-btn);
  padding: 0 !important;
  display: inline-flex; align-items: center; justify-content: center;
  line-height: 1;
}
/* Squaring caught the bulk "Akce ▾" dropdown toggle — only square real icon buttons. */
.grid-view .action-column .btn.dropdown-toggle {
  width: auto; height: auto;
  padding: 4px 10px !important;
  display: inline-block;
  line-height: 18px;
}
/* THE GREY BAND BEHIND EVERY FILTER ROW.  The 2026 layer softens the CELLS (`> thead > tr > th` and
   `> tr.filters > td` are both `background: transparent`), but kartik paints the band on the THEAD
   ELEMENT: kv-grid.css:23 `.kv-table-header { background: linear-gradient(to bottom, #fff 0%, #eee
   100%) }`.  With transparent cells that gradient shows straight through — white at the header row,
   #eee at the filter row.  Nothing in our layer had ever targeted the thead, so the selector list
   simply had a hole.  Same for the footer band (kv-grid.css:18). */
.kv-grid-table > thead.kv-table-header,
.kv-grid-table > tfoot.kv-table-footer {
  background: transparent;
}
/* Grid x-scroll: site.css's `.grid-view th { white-space: nowrap }` forces every header onto one
   line, which inflates each column's intrinsic minimum width (one two-word header claimed 237px).
   Letting headers wrap costs nothing visually and reclaims the width — one document grid went 1075px
   -> 794px in a 722px container.  Any residual overflow is genuine content width, not a styling
   regression. */
.grid-view .kv-grid-table > thead > tr > th { white-space: normal; }
/* Filter-reset eraser (ActionColumn TYPE_LINK): `btn-link` inherits Bootstrap's link blue, which is
   off-palette; quiet ghost instead — green icon, mint hover, like every other ghost button. */
.kv-grid-table .btn-clear-filter,
.kv-grid-table .btn-clear-filter:focus {
  color: var(--ok-green);
  text-decoration: none;
}
.kv-grid-table .btn-clear-filter:hover {
  color: var(--ok-green);
  background: var(--brand-mint-bg);
}
/* ---------- Summary + pager on one line ---------- */
.list-gridfoot {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
}
.list-gridfoot .pagination { margin: 6px 0; }
/* ---------- Record overview boxes are key-value rows ----------
   The client and contract Přehled boxes are read-only summaries, so their disabled `div.form-control`
   pairs give way to a two-column list: label left in muted ink, value right in bold tabular figures, a
   hairline under every pair but the last.

   The values are still wrapped in a `div.form-control` inside a `field-<model>-<attribute>` row, which
   is what web/js/modules.js and the two _documents.php live-updaters write into and what
   ContractUpdateCept / ClientUpdateCept assert on — so the input chrome is stripped here rather than in
   the markup, and it is not a `<span>` because the tests match `div.form-control`.

   NOT changed: business-transaction's own _dashboard.php, which has the same shape.  Obchodní případ
   keeps the old look until it is asked for. */
.kv-grid {
  display: grid;
  grid-template-columns: 1fr auto;
  row-gap: 0;
}
/* The wrapper exists only to carry the `field-<model>-<attribute>` hook and the negative modifier;
   `display: contents` promotes its label and value to grid items so it costs no box and no margin
   (the same device the select2 rendered element uses). */
.kv-grid__row {
  display: contents;
}
.kv-grid__label,
.kv-grid__value {
  padding: var(--spacing-kv-row-pad-y) 0;
  border-bottom: 1px solid var(--border-default);
}
.kv-grid__label {
  color: var(--text-muted);
  padding-right: 12px;   /* a long label must not touch the value column */
}
/* `align-items: center` is what puts a one-line value in the MIDDLE of a row whose label wrapped.
   Both cells are grid items and both stretch (that is what keeps the hairline continuous), so the
   value cell is as tall as the two-line label while its content is one line; left at the flex
   default the line sat at the top and read as belonging to the label's first line only.  Centring
   the flex items centres the content inside the stretched cell without touching the cell itself.

   It replaces `baseline`, which the number/unit pair no longer needs: value and unit are the same
   13px/18.2px line, so the two alignments place them identically.  They part company only if a value
   ever wraps WHILE carrying a unit — then the unit centres against the whole value instead of riding
   its first line.  Every unit-bearing row in the app is a formatted amount, which does not wrap.
   A value that wraps on its own is unaffected either way: it is then the tallest thing in the row,
   so there is no slack left to centre it in. */
.kv-grid__value {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 4px;
  font-weight: 600;
  color: var(--text-body);
  font-variant-numeric: tabular-nums;
  text-align: right;
}
/* The last pair paints no rule, but KEEPS the 1px the border occupies — dropping the border outright
   made the last row a pixel shorter than every other row in the panel, which is what made the
   contract's pill row (its last) look like the pill was costing it height.  Keyed off `:last-child`
   rather than a class so the conditional rows cannot leave a dangling hairline whichever of them
   happens to be last. */
.kv-grid > .kv-grid__row:last-child > .kv-grid__label,
.kv-grid > .kv-grid__row:last-child > .kv-grid__value {
  border-bottom-color: transparent;
}
/* Strip the input chrome from the value carrier the live-updaters and the tests need. */
.kv-grid__value > .form-control {
  display: inline;
  width: auto;
  height: auto;
  min-height: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
  font: inherit;
  color: inherit;
  font-variant-numeric: inherit;
}
/* The unit sits outside .form-control (a `.text()` update would otherwise wipe it) and reads as
   part of the number, so it takes the value's weight and only loses a little contrast. */
.kv-grid__unit {
  color: var(--text-muted);
  font-weight: 600;
}
/* Contract only: a negative Zaplacené pojistné is the one number in this box worth spotting at a
   glance.  ORANGE, NOT RED — user ruling: red is reserved for ERRORS, and an outstanding balance is a
   figure to notice, not a fault.  The token is the CTA family's darker step, which is the app's "look
   here" colour.  Central rule, so every kv list in the app that marks a negative amount follows. */
.kv-grid__row--negative > .kv-grid__value,
.kv-grid__row--negative > .kv-grid__value > .kv-grid__unit {
  color: var(--brand-orange-dark);
}
/* The two state tints of the pill.  Both sit AFTER the chrome-stripping rule above on purpose: that
   rule paints `background: none` at the same (0,2,0) specificity, so a tint declared earlier in the
   file loses the tie and the pill renders with no fill at all — which is what "nekompletní" did.
   The alarm tint is light orange and not red: red is reserved for errors, and a missing document is
   a state to notice, not a fault. */
.kv-grid__value > .kv-pill--ok { background: var(--panel-success-bg); color: var(--ok-green); }
.kv-grid__value > .kv-pill--missing { background: var(--panel-danger-row-bg); color: var(--status-danger-muted); }
/* Overview key-value rows keep their 9px (explicit designer note).  They are unaffected by the
   form-group rhythm — `.kv-grid__row` is `display: contents`, so that margin never applied — and are
   re-stated here only so a future rhythm change cannot silently take them with it. */
.kv-grid__label, .kv-grid__value { padding: var(--spacing-kv-row-pad-y) 0; }
/* ---------- Grid headers ----------
   Three states on one cell: the label, the funnel, and the sort caret that REPLACES the funnel on the
   sorted column.  The funnel means "this column can be sorted".

   It is added server-side at ONE shared place: app\components\web\DataColumn appends
   `<i class="fa fa-filter kv-th-filter">` to the header content, and config/container.php substitutes
   that class for kartik\grid\DataColumn (the `dataColumnClass` every kartik GridView instantiates), so
   all ~150 kv grids get it without a single view being edited.  Everything below is CSS. */
.kv-grid-table > thead > tr > th {
  background: transparent;
  border-bottom: 2px solid var(--border-default);
  font-weight: 400;
  color: var(--text-label);
}
.kv-grid-table > thead > tr > th > a,
.kv-grid-table > thead > tr > th > a:hover,
.kv-grid-table > thead > tr > th > a:focus {
  color: var(--text-label);
  text-decoration: none;
}
.kv-grid-table > thead > tr > th > a:hover { color: var(--ok-green); }
.kv-grid-table > thead > tr > th > .kv-th-filter {
  margin-left: 5px;
  font-size: 11px;
  color: var(--ok-mint);
}
/* The caret REPLACES the funnel on the sorted column. */
.kv-grid-table > thead > tr > th:has(> a.asc) > .kv-th-filter,
.kv-grid-table > thead > tr > th:has(> a.desc) > .kv-th-filter { display: none; }
/* kartik puts its own glyph in a `.kv-sort-icon` span INSIDE the link and site.css's
   `a.asc:after, a.desc:after` adds a
   second one via `a.asc:after` — two sort glyphs on every sorted column today. Keep the
   pseudo-element (it is the one that sits right after the label) and drop the span. */
.kv-grid-table > thead > tr > th > a > .kv-sort-icon { display: none; }
.kv-grid-table > thead > tr > th > a.asc:after,
.kv-grid-table > thead > tr > th > a.desc:after {
  font-family: FontAwesome;
  font-size: 12px;
  color: var(--ok-green);
  padding-left: 5px;
  top: 0;
}
.kv-grid-table > thead > tr > th > a.asc:after { content: "\f0d8"; }
.kv-grid-table > thead > tr > th > a.desc:after { content: "\f0d7"; }
/* ---------- Grid action tile glyphs ----------
   font-awesome.min.css declares `.fa { font-size: inherit }`, so every glyph takes its size from its
   button — and `.btn` is 13px since the type was reverted to the legacy metrics.  In a 28px tile
   FontAwesome's own 14px is the size the tile was drawn around, so the glyph is given it back
   explicitly.  The tile geometry is untouched.

   DIRECT `.fa` child only, for the same reason the icon-mode rules are written that way:
   `.btn-icon-glyph` sizes itself and its two parts, and a descendant selector here would outrank it. */
.grid-view .action-column .btn > .fa,
.kv-grid-table .btn-xs > .fa,
.table .btn-xs > .fa {
  font-size: 14px;
}
/* ---------- The sorted column's header ----------
   With every header link the same weight and colour, the 12px caret was the single pixel of difference
   between "this column is sorted" and "this column is merely sortable" — easy to miss on a wide grid.
   The label now carries the state with its caret: same brand green, one weight step up.  600 and not
   700, because the grid header is a 400-weight row by design and 700 would read as a different type
   style rather than as a state of the same one.  Unsorted headers are untouched, so the contrast
   between the two is what does the work.
   Specificity: the base rules are (0,1,4) and (0,2,4); adding `.asc`/`.desc` makes these (0,2,4) and
   (0,3,4) — one class above each, so the hover state keeps the sorted colour too. */
.kv-grid-table > thead > tr > th > a.asc,
.kv-grid-table > thead > tr > th > a.desc,
.kv-grid-table > thead > tr > th > a.asc:hover,
.kv-grid-table > thead > tr > th > a.desc:hover,
.kv-grid-table > thead > tr > th > a.asc:focus,
.kv-grid-table > thead > tr > th > a.desc:focus {
  font-weight: 600;
  color: var(--ok-green);
}
.grid-view > table:not(.kv-grid-table) > thead > tr > th > a,
.grid-view > table:not(.kv-grid-table) > thead > tr > th > a:focus {
  color: var(--text-label);
  text-decoration: none;
}
.grid-view > table:not(.kv-grid-table) > thead > tr > th > a:hover { color: var(--brand-green); }
/* site.css hangs the sort caret off `a.asc:after` / `a.desc:after`; it inherits the link's
   colour, which is now the label grey. The sorted column's caret is the one green mark, exactly as
   the kv grids do. */
.grid-view > table:not(.kv-grid-table) > thead > tr > th > a.asc:after,
.grid-view > table:not(.kv-grid-table) > thead > tr > th > a.desc:after { color: var(--brand-green); }
/* Why `.form-card` exists (the selector that reads it is the header-less-box rule further up).  That
   rule paints a header-less `.box` that CONTAINS a `.box` transparent, because on an UPDATE page such
   a box is legacy scaffolding wrapped around the real cards.  A CREATE page's box is the opposite: it
   IS the card, and the box inside it is one of the form's own sub-sections.  Two create pages trip
   that (client/create's "Výchozí kontakt" panel and subject/create's `.box.data-detail` register
   panel — `display:none`, but `:has()` matches it anyway, which is why that page rendered with no card
   at all).  No CSS can tell the two shapes apart, so the create views say so in markup. */

/* Plain (non-kartik) grids.  The seven `yii\grid\GridView` grids in the app have no `.kv-grid-table`
   class, and EVERY grid rule in this file is scoped to it — so they kept bootstrap's default header
   link colour, which is the CTA orange.  Mirroring the two header rules plus the header-wrapping fix
   is the smallest thing that covers all seven instead of leaving the same bug behind seven times.
   NOT mirrored: the funnel glyph (DataColumn only substitutes for kartik's DataColumn) and the thead
   band (a plain table has no `.kv-table-header` to repaint). */
.grid-view > table:not(.kv-grid-table) > thead > tr > th { font-weight: 400; color: var(--text-label); white-space: normal; }
/* ---------- An inactive row is DISABLED, not an alarm ----------
   The entity grids mark a record that is no longer live (`is_finished`, or `deleted_at` for an account)
   with bootstrap's `danger` row class, which paints the alarm tint — so a whole page of ordinary rows read
   as a page of errors.  RED IS FOR ERRORS: inactive is the disabled surface with the ordinary body ink,
   which is how every other "present but not live" control in the app is drawn.  The grey is two steps
   darker than the disabled token, which is 3 points off white and could not be seen in a list; why it
   cannot collide with the hovered-row tint is derived in the zebra note at the end of section 3c.

   SCOPE — kartik puts the grid's id on every row it renders
   (GridViewTrait::renderTableRow -> `Html::addCssClass($options, $this->options['id'])`), so
   `tr.subject-grid` / `tr.contract-grid` / … is an exact, already-present hook and needs no markup.
   `tr.client-grid.danger` does not occur today (that grid sets no rowOptions), and is listed anyway so the
   pair the ruling names has ONE answer and adding the marker later is a view change with no CSS to chase.
   The two remaining `tr.danger` users in the app are deliberately NOT here and keep the alarm — see the
   note in the notifications section.

   Specificity: the base is `.table > tbody > tr.danger > td` (0,2,2) with `!important` on the fill, and its
   hover (0,3,2).  These are (0,4,2) / (0,4,3) and repeat the `!important`, so both win on count. */
.kv-grid-table > tbody > tr.subject-grid.danger > td,
.kv-grid-table > tbody > tr.client-grid.danger > td,
.kv-grid-table > tbody > tr.contract-grid.danger > td,
.kv-grid-table > tbody > tr.incident-grid.danger > td,
.kv-grid-table > tbody > tr.account-grid.danger > td {
  background-color: var(--surface-inactive-row) !important;
  color: var(--text-body);
}
.table-hover.kv-grid-table > tbody > tr.subject-grid.danger:hover > td,
.table-hover.kv-grid-table > tbody > tr.client-grid.danger:hover > td,
.table-hover.kv-grid-table > tbody > tr.contract-grid.danger:hover > td,
.table-hover.kv-grid-table > tbody > tr.incident-grid.danger:hover > td,
.table-hover.kv-grid-table > tbody > tr.account-grid.danger:hover > td {
  background-color: var(--surface-inactive-row-hover) !important;
}
/* ---------- A grid's favourite star, wherever the grid is drawn ----------
   KEYED TO `.grid-view`, NOT TO AN ANCESTOR, and that is the point.  The look used to be carried by
   `.content-wrapper .btn.btn-star` / `.btn-star-off`, so a grid drawn OUTSIDE `.content-wrapper` lost it —
   and one is drawn outside it every time a dialog opens (`showDialog()` moves content into a `.modal` that
   bootstrap appends to <body>).  Probed there, the star fell back to bootstrap's `.btn-warning`, an orange
   tile.  Keying the pair to `.grid-view` makes the answer true by construction for every grid.

   ONE favourite button in the design system, the title-row trio look — "gold means starred, green means
   you may star this":
     ☆ not favourited   ghost tile, OUTLINE star (fa-star-o), BRAND-GREEN ink   `btn-star-off`
     ★ favourited       ghost tile, FILLED star  (fa-star),   GOLD ink          `btn-star`
   The glyph swap is FontAwesome's, done in markup by FavoriteButton; only the ink and the tile are CSS.

   TWO NON-BUTTONS ARE OUT OF SCOPE: the home page's `.fav-row__star` (a decorative glyph, no tile, no
   link, and `.fav-list` is not a `.grid-view`) and the title row's own trio.
   (0,3,0) ties the source rules and wins on order; the `!important` is only there because theirs carries
   one on the fill. */
.grid-view .btn.btn-star {
  background: var(--surface-card) !important;
  border-color: var(--border-strong);
  color: var(--brand-gold);
}
.grid-view .btn.btn-star:hover, .grid-view .btn.btn-star:focus {
  background: var(--surface-tint) !important;
  border-color: var(--brand-gold);
  color: var(--brand-gold-dark);
}
.grid-view .btn.btn-star-off {
  background: var(--surface-card) !important;
  border-color: var(--border-strong);
  color: var(--brand-green);
}
.grid-view .btn.btn-star-off:hover, .grid-view .btn.btn-star-off:focus {
  background: var(--brand-mint-bg) !important;
  border-color: var(--border-strong);
  color: var(--brand-green-dark);
}
/* ---------- The state pill ----------
   `.kv-pill` is the state chip in the Přehled key-value panel of client and contract update ("Stavy
   požadovaných dokumentů") — mint when every requested document is in, light orange while some are
   missing.  It sits on a ~34px key-value row, and 5px of vertical padding instead of 3 takes it
   22px -> 26px, the height of the Úkoly status chip.  Font-size, line-height, radius, fill and ink are
   untouched.

   `.cbl-state`, the Uzávěrka provizí grid's state chip, is the SAME chip and joins the selector rather
   than restating these six metrics next to its own tints in 4e — the two read side by side in the app
   and were 22 vs 26.  Only the fill and the ink differ between them, and those belong to each chip's
   own state modifiers.

   The chip also carries `.form-control` so the document dialogs' `.text()` still lands on it, hence the
   same-specificity selector to win back the padding and fill the chrome-stripping rule above removes.

   THE VERTICAL PADDING IS 4/6 ON PURPOSE — it is optical, not geometric.  A symmetric 5/5 centres the
   16px line box in the 26px box exactly, but Inter puts its baseline at 80% of its font box
   (ascent 12, descent 3 at 12px), so the visible INK of both status names — "v pořádku" and
   "nekompletní", each with a descender and a caron/acute above cap height — spans 8.32px to 19.95px
   from the top and its centre lands 1.13px BELOW the pill's.  One pixel of the bottom padding moved to
   the top brings that to 0.13px and leaves the height at 4+16+6 = 26.  `display: inline-flex` with
   `align-items: center` does NOT fix this (measured: still 1.13px) — it centres the line box, which was
   never the thing off centre, and the pill is a flex item anyway so `inline-flex` blockifies to `flex`.
   Same selector as the palette rule so the two cannot drift; later in the file, so it wins the tie. */
.kv-grid__value > .kv-pill,
.cbl-state {
  display: inline-block;
  border-radius: var(--radius-sm);
  font-size: 12px;
  font-weight: 600;
  line-height: 16px;
  padding: 4px 8px 6px;
}
/* ---------- The pill must not deepen the key-value row ----------
   The pill is 26px against an 18.2px label line, and both cells stretch to the taller of the two, so
   the pill alone would make its row 8px deeper than every other row in the panel.  Centring the cells
   (`align-items` on `.kv-grid`) is not available: the row hairline is a border on each cell and only
   spans the row while both stretch.

   Pulling 4px off each end leaves the pill's PAINTED box untouched and hands the row height back to
   the label's line: 26 - 8 = 18px of contributed height against that 18.2px line, so the row measures
   exactly what its neighbours do and the value cell's own centring places the pill.  It touches
   nothing but the pill, so the rest of the panel is unaffected. */
.kv-grid__value > .kv-pill {
  margin-top: -4px;
  margin-bottom: -4px;
}

/* ============================================================================================
   3f. COMPONENTS / panels, flashes, error summaries
   ============================================================================================ */
.alert { border-radius: var(--radius-box); }
/* ---------- Flashes, static alerts and validation summaries ----------
   Every flash in the app is rendered by dmstr\widgets\Alert, which emits
   `<div class="alert alert-<type>"><i class="icon fa fa-…"></i>text<button class="close">×</button></div>`;
   a handful of views write the same `.alert` block by hand.  Both shapes are covered here, so no view
   changes were needed.

   `!important` is not decoration: AdminLTE.css:4376+ paints these classes
   `background-color: <saturated> !important; color: #fff !important`, so a tinted panel can only be
   reached by matching it.

   ActiveForm error summaries render as `.callout.callout-danger.error-summary` (all ~90 call sites pass
   that class), NOT as `.alert` — they are in the same AdminLTE `!important` list, so they take the
   danger anatomy here too. */
.alert-success, .alert-warning, .alert-danger, .alert-error,
.error-summary.callout-danger {
  position: relative;
  padding: 11px 38px 11px 14px;
  border: 1px solid;
  border-left-width: 4px;
  border-radius: var(--radius-control);
  box-shadow: none;
}
.alert-success {
  background-color: var(--panel-success-bg) !important;
  border-color: var(--panel-success-border);
  border-left-color: var(--ok-green);
  color: var(--ok-green) !important;
}
.alert-warning {
  background-color: var(--panel-warning-bg) !important;
  border-color: var(--panel-warning-border);
  border-left-color: var(--ok-gold);
  color: var(--panel-warning-text) !important;
}
.alert-danger, .alert-error, .error-summary.callout-danger {
  background-color: var(--panel-danger-bg) !important;
  border-color: var(--panel-danger-border);
  border-left-color: var(--status-danger);
  color: var(--panel-danger-text) !important;
}
/* JUDGEMENT CALL, flag for the designer: the batch named success / warning / danger only, but
   `.alert-info` is used in three live views and left alone it stays a saturated AdminLTE cyan slab,
   jarring beside three tinted panels.  Given the same anatomy in the palette's Sky Blue.  Delete this
   one rule block if the designer wants info left as-is. */
.alert-info {
  position: relative;
  padding: 11px 38px 11px 14px;
  border: 1px solid var(--panel-info-border);
  border-left: 4px solid var(--ok-sky);
  border-radius: var(--radius-control);
  box-shadow: none;
  background-color: var(--panel-info-bg) !important;
  color: var(--panel-info-text) !important;
}
.alert-info > i.fa-info:before { content: "\f05a"; }
        /* dmstr emits fa-info; use the disc */
.alert-info:not(:has(> i)):before { font-family: FontAwesome; margin-right: 8px; content: "\f05a"; }
.alert-info a { color: inherit; text-decoration: underline; }
/* A link inside a tinted panel can no longer be white-on-colour (AdminLTE.css:2417). */
.alert-success a, .alert-warning a, .alert-danger a, .alert-error a,
.error-summary.callout-danger a { color: inherit; text-decoration: underline; }
.error-summary.callout-danger > p { font-weight: 600; margin-bottom: 4px; }
.error-summary.callout-danger ul { margin-bottom: 0; padding-left: 18px; }
/* The summary is a <p> + <ul> stack, so its glyph has to ride on the heading rather than on the
   block (where it would sit on a line of its own above the text). */
.error-summary.callout-danger:before { content: none; }
.error-summary.callout-danger > p:first-child:before {
  font-family: FontAwesome;
  content: "\f06a";
  margin-right: 8px;
}
/* The glyph. dmstr already emits one per type and two of the three are already the designer's
   (fa-check, fa-warning == fa-exclamation-triangle \f071); only danger/error differ, so the
   glyph is swapped rather than the markup (fa-ban \f05e -> fa-exclamation-circle \f06a). */
.alert-danger > i.fa-ban:before, .alert-error > i.fa-ban:before { content: "\f06a"; }
.alert > i:first-child { margin-right: 8px; }
/* WARNING: do NOT add `.error-summary.callout-danger:before` to the two rules below.  It used
   to be in both of them, twenty lines AFTER the `content: none` the paragraph-glyph block above sets on
   that very selector — same specificity (0,2,1), later in the file, so the later pair won and every
   error summary in the app drew TWO exclamation discs: one as an anonymous block line above the heading
   and one inline on the heading itself.

   The `.alert-*` members stay exactly as they are: an `.alert` is a single line of text with no heading
   to hang a glyph on, so the block-level `:before` IS its anatomy.  Only the summary — a `<p>` + `<ul>`
   stack — wants the glyph on the heading. */
.alert-success:not(:has(> i)):before,
.alert-warning:not(:has(> i)):before,
.alert-danger:not(:has(> i)):before,
.alert-error:not(:has(> i)):before {
  font-family: FontAwesome;
  margin-right: 8px;
}
.alert-success:not(:has(> i)):before { content: "\f00c"; }
.alert-warning:not(:has(> i)):before { content: "\f071"; }
.alert-danger:not(:has(> i)):before,
.alert-error:not(:has(> i)):before { content: "\f06a"; }
/* Close ✕ top right at 60%. Absolute rather than BS3's floated `right: -21px` hack, which needs
   the alert to be `.alert-dismissable` — the widget never adds that class, so the ✕ used to sit
   at the end of the last text line. */
.alert > .close {
  position: absolute;
  top: 8px;
  right: 10px;
  margin: 0;
  color: inherit;
  opacity: .6;
  text-shadow: none;
}
.alert > .close:hover, .alert > .close:focus { opacity: 1; color: inherit; }

/* ---------- The floated flash (toast) ----------
   The toast (`okis.toast()` in web/js/scripts.js) is deliberately NOT a new component.  Its markup is
   dmstr\widgets\Alert's, so every declaration above it — the tint, the 4px left accent, the glyph, the
   radius, the absolute ✕ — is the one the page's own flashes use, and a change to the flash family is a
   change to the toast.  What is added here is only what makes it float: the stack, the shadow that
   lifts it off the page, and the two 8px slides.

   ONE deliberate departure, and it is the designer's: the toast's ink is SEMIBOLD.  A flash sits in the
   page and is read at leisure; a toast is momentary and has to be read at a glance.

   `top: 62px` is the 50px fixed header plus a 12px gap; `pointer-events` is off on the stack and back
   on inside a toast, so an empty stack (created once, then kept) can never swallow a click on the page
   underneath; `z-index` clears the modal (1050) so an acknowledgment fired while a dialog is open is not
   hidden behind it. */
.okis-toasts {
  position: fixed;
  top: 62px;
  right: 24px;
  z-index: 1060;
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: 360px;
  max-width: calc(100vw - 48px);
  pointer-events: none;
}
.okis-toast {
  margin: 0;
  font-weight: 600;
  pointer-events: auto;
  box-shadow: var(--shadow-dropdown);
  animation: okis-toast-in 160ms cubic-bezier(.2, .6, .3, 1);
}
.okis-toast--leaving { animation: okis-toast-out 200ms ease-in forwards; }
@keyframes okis-toast-in {
  from { opacity: 0; transform: translateY(-8px); }
  to { opacity: 1; transform: none; }
}
@keyframes okis-toast-out {
  from { opacity: 1; transform: none; }
  to { opacity: 0; transform: translateY(-8px); }
}

/* ============================================================================================
   3g. COMPONENTS / dialogs
   ============================================================================================ */
.modal [class*="select2-container--krajee"] { z-index: 1100; }
.modal-content { border-radius: var(--radius-modal); box-shadow: var(--shadow-dropdown); }
/* ---------- Confirmation dialogs ----------
   MECHANISM, which is the part that is easy to get wrong.  There is no BsDialog and no `data-confirm`
   override of our own in play: the dialog users actually see comes from KrajeeDialog
   (kartik\dialog\Dialog -> bootstrap3-dialog).  Every kartik GridView renders `Dialog::widget()`, which
   publishes a `krajeeDialog` instance in <head> and then, on document-ready, replaces `yii.confirm` with
   its own via `krajeeYiiConfirm()` — so it wins over the bootbox override web/js/scripts.js installs,
   and it is what both yii.js's `data-confirm` and the ~30 `data-confirm-message` handlers in modules.js
   end up calling.  Its stock look is a `type-warning` dialog with an orange header bar titled
   "Confirmation" in English (the shipped cs/sk `kvdialog` catalogs are empty).  scripts.js hooks
   `KrajeeDialog.prototype.confirm` and passes BootstrapDialog OPTIONS; the plugin itself is untouched.

   bootbox is still covered too — it remains `yii.confirm` on a page that renders no kartik widget, and
   modules.js calls `bootbox.alert/dialog/confirm` directly in a few places.  Its markup is different
   (no header, `.bootbox-body`), so the two anatomies key off `.bootstrap-dialog` and `.bootbox` and
   share only the card, the overlay and the buttons. */
.bootstrap-dialog .modal-content, .bootbox .modal-content {
  background: var(--surface-card);
  border: 0;
  border-radius: var(--radius-box);
  box-shadow: 0 12px 40px rgba(0, 42, 37, .28);
}
.bootstrap-dialog .modal-dialog, .bootbox .modal-dialog { width: 460px; }
/* Both plugins use the shared bootstrap backdrop, which no selector can scope to them, so the
   2026 overlay applies to every modal — which is what the design asks for anyway. */
.modal-backdrop, .modal-backdrop.in { background-color: var(--overlay-backdrop); opacity: .45; }
/* --- KrajeeDialog / bootstrap3-dialog --- */
/* No coloured header bar: the header keeps only the title, and becomes the top row of the card
   (40px icon disc left, title right). `.btn-default` lands on the header element itself
   (bootstrap3-dialog names it after the type), hence the doubled selector. */
.bootstrap-dialog .modal-header,
.bootstrap-dialog .modal-header.btn-default,
.bootstrap-dialog.type-default .modal-header {
  display: grid;
  grid-template-columns: 40px 1fr;
  gap: 14px;
  align-items: center;
  padding: 22px 22px 0;
  background: var(--surface-card);
  border: 0;
  border-radius: var(--radius-box) var(--radius-box) 0 0;
  box-shadow: none;
}
.bootstrap-dialog .modal-header:before {
  content: "\f05a";                      /* fa-info-circle — neutral */
  font-family: FontAwesome;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
  background: var(--pastel-sky-light);
  color: var(--pastel-sky-text);
}
.bootstrap-dialog.okis-confirm--danger .modal-header:before {
  content: "\f1f8";                      /* fa-trash — destructive */
  background: var(--panel-danger-bg);
  color: var(--status-danger);
}
/* The plugin nests title + close button in a `.bootstrap-dialog-header` div, which would take
   the whole second grid cell; `display: contents` promotes them so the title lands in it. */
.bootstrap-dialog .modal-header > .bootstrap-dialog-header { display: contents; }
.bootstrap-dialog .bootstrap-dialog-title,
.bootstrap-dialog.type-default .bootstrap-dialog-title {
  font-size: 16px;
  font-weight: 600;
  line-height: 1.35;
  color: var(--text-body);
}
/* The message is the body, indented to the title's column (22 + 40 + 14). */
.bootstrap-dialog .modal-body { padding: 8px 22px 4px 76px; }
.bootstrap-dialog .bootstrap-dialog-message {
  font-size: 13px;
  line-height: 1.45;
  color: var(--text-muted);
}
.bootstrap-dialog .bootstrap-dialog-close-button .btn-modal-close {
  background: none;
  border: 0;
  color: var(--text-muted);
  opacity: .6;
}
.bootstrap-dialog .bootstrap-dialog-close-button .btn-modal-close:hover { opacity: 1; }
/* --- bootbox --- */
/* bootbox has no title parameter and the app always passes a single message, so there the
   message IS the title line and any nested <p>/<small> becomes the 13px body. */
.bootbox .modal-body {
  display: grid;
  grid-template-columns: 40px 1fr;
  gap: 14px;
  align-items: start;
  padding: 22px 22px 6px;
}
.bootbox .modal-body:before {
  content: "\f05a";
  font-family: FontAwesome;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
  background: var(--pastel-sky-light);
  color: var(--pastel-sky-text);
}
.bootbox.okis-confirm--danger .modal-body:before {
  content: "\f1f8";
  background: var(--panel-danger-bg);
  color: var(--status-danger);
}
/* The ALERT's disc says which kind of message this is.  `info` is the sky disc declared above and needs
   no rule of its own: it is what every `bootbox.alert()` has always looked like, and it stays the
   default for the call sites that cannot prove their outcome.  The three below are opted into from JS by
   `okis.alert(msg, sev)` and use the same tint/ink pairs as the flashes in 3f, so a "saved" disc and a
   "saved" flash are the same green on the same mint. */
.bootbox.okis-alert--success .modal-body:before {
  content: "\f00c";
  background: var(--panel-success-bg);
  color: var(--ok-green);
}
.bootbox.okis-alert--warning .modal-body:before {
  content: "\f071";
  background: var(--panel-warning-bg);
  color: var(--panel-warning-text);
}
.bootbox.okis-alert--error .modal-body:before {
  content: "\f06a";
  background: var(--panel-danger-bg);
  color: var(--status-danger);
}
/* The message line sits on the CENTRE of the icon disc.  The grid is `align-items: start`, which is the
   right choice — a long message must grow DOWNWARD from the disc, not push the disc to the middle of a
   paragraph — but "start" aligns the top of a 21.6px line box with the top of a 40px disc, which puts
   the text 7.2px high.  The 9px is derived, not tuned: (40 - 16 x 1.35) / 2 = 9.2, i.e. half the
   difference between the disc and one line of the message.  It follows the two values above it — change
   the disc size or the message's line-height and this has to move with them, which is why all three
   live in one block. */
.bootbox .bootbox-body {
  font-size: 16px;
  font-weight: 600;
  line-height: 1.35;
  color: var(--text-body);
  padding-top: 9px;
}
.bootbox .bootbox-body p,
.bootbox .bootbox-body small,
.bootbox .bootbox-body .text-muted {
  font-size: 13px;
  font-weight: 400;
  line-height: 1.45;
  color: var(--text-muted);
  margin: 6px 0 0;
}
/* bootbox prepends the ✕ into the body (and inline-styles `margin-top: -10px`) whenever the
   dialog has no title, which would otherwise claim the first grid cell. */
.bootbox .bootbox-close-button {
  position: absolute;
  top: 12px;
  right: 14px;
  margin: 0 !important;
  color: var(--text-muted);
  opacity: .6;
  text-shadow: none;
}
.bootbox .bootbox-close-button:hover { opacity: 1; }
/* bootbox's own title variant (bootbox.dialog(), used for a few custom dialogs in modules.js)
   keeps a plain white header rather than growing a second icon disc. */
.bootbox .modal-header {
  background: var(--surface-card);
  border: 0;
  padding: 20px 22px 0;
}
.bootbox .modal-header .modal-title { font-size: 16px; font-weight: 600; color: var(--text-body); }
.bootbox:has(> .modal-dialog .modal-header) .modal-body { display: block; padding: 10px 22px 4px; }
.bootbox:has(> .modal-dialog .modal-header) .modal-body:before { content: none; }
.bootbox:has(> .modal-dialog .modal-header) .bootbox-body { font-size: 14px; font-weight: 400; color: var(--text-muted); }
/* --- shared: footer --- */
.bootstrap-dialog .modal-footer, .bootbox .modal-footer {
  border-top: 0;
  padding: 12px 22px 22px;
  text-align: right;
}
.bootstrap-dialog .modal-footer .btn, .bootbox .modal-footer .btn { min-width: 92px; }
/* Ghost "Zrušit" + the filled verb.  The dialogs are appended to <body>, i.e. outside
   `.content-wrapper`, so none of the content-area button repaints reach them — these rules are the whole
   palette.  `!important` because the frozen sources pin `.btn-danger { background: #fff !important }`
   and do the same for `.btn-success` inside the content area, so a plain declaration here would lose
   regardless of specificity.

   An ALERT's single OK joins the ghost, it does not lead anything — there is no choice to make in a
   dialog with one button, so the filled verb would be shouting.  It shares the cancel's rules rather
   than repeating them.  (bootbox would otherwise have made it `btn-primary`, i.e. orange.) */
.modal-footer .btn.okis-confirm__cancel,
.modal-footer .btn.okis-alert__ok {
  background: var(--surface-card) !important;
  border-color: var(--border-strong) !important;
  color: var(--ok-green) !important;
}
/* The alert's OK takes the hover but NOT the `:focus` half. It opens focused (scripts.js restores
   the focus bootbox used to put on its `btn-primary`), so a focus repaint would mean the resting
   white ghost is the one state nobody ever sees. The 2px ring at the end of this section is the
   focus signal there, which is what a ring is for. */
.modal-footer .btn.okis-confirm__cancel:hover,
.modal-footer .btn.okis-confirm__cancel:focus,
.modal-footer .btn.okis-alert__ok:hover {
  background: var(--surface-tint) !important;
  border-color: var(--ok-green) !important;
  color: var(--ok-green-dark) !important;
}
.modal-footer .btn.okis-confirm__ok {
  background: var(--ok-green) !important;
  border-color: var(--ok-green) !important;
  color: var(--text-inverse) !important;
}
.modal-footer .btn.okis-confirm__ok:hover,
.modal-footer .btn.okis-confirm__ok:focus {
  background: var(--ok-green-dark) !important;
  border-color: var(--ok-green-dark) !important;
  color: var(--text-inverse) !important;
}
.okis-confirm--danger .modal-footer .btn.okis-confirm__ok {
  background: var(--status-danger) !important;
  border-color: var(--status-danger) !important;
  color: var(--text-inverse) !important;
}
.okis-confirm--danger .modal-footer .btn.okis-confirm__ok:hover,
.okis-confirm--danger .modal-footer .btn.okis-confirm__ok:focus {
  background: var(--status-danger-text) !important;
  border-color: var(--status-danger-text) !important;
  color: var(--text-inverse) !important;
}
/* ---------- The dialog footer's focus ring stops reading as a second border ----------
   `bootbox.alert()` focuses its OK button as it opens, so the button comes up wearing the app's global
   focus ring, `0 0 0 3px rgba(0,80,70,.14)`.  A 3px spread with no offset HUGS the border, and on a
   filled button the result is a pale second edge one shade off the first — and on an orange OK it is
   also the wrong hue.

   Replaced, in dialog footers only, by a ring that is unmistakably a ring: 2px brand green, held 2px off
   the button so there is white between the two edges.  Accessibility is preserved — it is still
   `:focus-visible`, so it still appears for keyboard users and on the auto-focused OK, which is correct:
   that button IS focused and Enter will activate it.  Every other button in the app keeps the global
   wash. */
.bootstrap-dialog .modal-footer .btn:focus-visible,
.bootbox .modal-footer .btn:focus-visible {
  box-shadow: none;
  outline: 2px solid var(--brand-green);
  outline-offset: 2px;
}

/* ============================================================================================
   3h. COMPONENTS / canonical classes — one block per Figma "Buttons" / "Chips" component.  Every value
   was MEASURED off the as-built app; each block names its Figma component and the legacy classes it
   currently coexists with.

   WHY IT IS IN A @layer.  Emission is ADDITIVE: widgets emit the canonical class ALONGSIDE the legacy one
   (`btn btn-success btn-cta`), so both the legacy rule and the block below match the same element.
   Unlayered, a bare `.btn-cta` (0,1,0) in the last stylesheet would OUTRANK the legacy paint wherever that
   paint is itself a bare (0,1,0) rule without `!important` — and it is, outside `.content-wrapper`.  Two
   real regressions on surfaces no static page capture can reach: `.btn-success` at <body> level (where
   dialogs are appended) is brand green from skin.css and `.btn-cta` would repaint it orange;
   `.btn-primary` at <body> level and in the navbar is orange and `.btn-brand` would repaint it green.
   `@layer` removes the whole class of problem by construction: unlayered styles beat layered ones
   regardless of specificity, so EVERY legacy rule — base, contextual, hover, focus, disabled — keeps
   winning for as long as the legacy class is on the element.  No `!important` anywhere.  It also fails
   safe: a browser that does not understand `@layer` drops this block and the app renders as it does today.

   HAND-OFF: when a view stops emitting the legacy class, the canonical class must start winning.  That is
   one edit — delete the `@layer okis-components {` wrapper and its closing brace — and it must wait until
   the legacy classes are gone from the markup.

   DELIBERATELY NOT DECLARED HERE: padding / font-size on the paint classes (still owned by the legacy
   `.btn` box), and a glyph size on the tiles (the grid tiles render their `.fa` at 14px, the clear-filter
   funnel at 13px — two call sites, two answers, so the tile shape does not claim it).
   ============================================================================================ */
@layer okis-components {

  /* ============ THE HEIGHT LADDER ============
     36px free-standing  ·  34px on a control line  ·  28px compact  ·  20px the grid checkbox.

     36px is the BLESSED free-standing default: it is what a plain `.btn` already computes (`padding:
     7px 14px` + `line-height: 20px` + 2px border), so declaring it changes nothing today and makes the
     value survive the day that padding stops being reachable.  Figma's Buttons page says 34; the ruling
     keeps as-built 36 and gives 34 to the control line only.  The other three rungs have their own
     homes: 34 = --control-height (the filter-bar actions, the record trio, the navbar, every
     input-group); 28 = --size-grid-action-btn / --size-boxheader-icon-btn / --size-chip-add-btn;
     20 = --size-checkbox-grid / --size-radio-form.

     Why this is inert today: every 34 and every grid 28 is pinned by an UNLAYERED `height`
     declaration, and unlayered beats layered whatever the specificity, so the control line keeps
     winning for as long as the legacy classes are on the elements.

     The centering is stated WITH the height, because a fixed height without it would let a descender or
     a taller glyph sit off-centre once `display` is ours to set.  Today bootstrap's unlayered
     `.btn { display: inline-block }` wins, so the flex properties are inert; they take effect together
     with the height. */
  .btn-cta, .btn-brand, .btn-ghost, .btn-ghost-danger {
    height: var(--size-btn-height);
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  /* TRANSITIONAL — the one rung of the ladder that is NOT unlayered-pinned.
     The box-header / sub-section buttons are 28px because their `padding: 3px 6px` shrinks the box, NOT
     because anything declares a height.  So there is nothing unlayered for the 36px above to lose to,
     and without this rule those buttons grow 28 -> 36 (measured: 22 of them on one update page, and
     +48px of page height).  `auto` hands them back to the padding that has always sized them.
     Remove it once `.btn-boxheader` is emitted on those buttons and carries the 28 itself. */
  .box-header-buttons :is(.btn-cta, .btn-brand, .btn-ghost, .btn-ghost-danger),
  .form-section-label--toggle :is(.btn-cta, .btn-brand, .btn-ghost, .btn-ghost-danger) {
    height: auto;
  }

  /* TRANSITIONAL — the same job for the bootstrap size classes, and for the same reason.
     A free-standing `.btn-sm` computes 28px and `.btn-xs` 24px from padding alone, with no `height`
     anywhere to pin them, so the 36px above wins the moment one of them gains a paint class — which
     happened the day the bypass widgets were folded into app\widgets\Button and put `.btn-ghost` on a
     `btn btn-default btn-sm` trigger.  `auto` hands them back to the padding.
     `.btn-lg` is NOT listed: its only free-standing use is the login page, which unpins itself
     unlayered in `2d. BASE / buttons` because it has to beat the padding there as well.
     Remove it once the size classes have heights of their own. */
  :is(.btn-cta, .btn-brand, .btn-ghost, .btn-ghost-danger):is(.btn-sm, .btn-xs) {
    height: auto;
  }

  /* ---------- .btn-cta — Figma Buttons / "CTA (orange)" ----------
     The one filled orange action: "Uložit", "Nový klient", "Provést uzávěrku", the toolbar "+".
     Coexists with: btn-success (widgets/Button TYPE_SUCCESS).
     NOTE for the hand-off: OUTSIDE `.content-wrapper` today's `btn-success` is brand green, not orange
     (skin.css).  Those call sites need a per-site ruling, not a blanket rename. */
  .btn-cta {
    background-color: var(--brand-orange);
    border-color: var(--brand-orange);
    color: var(--text-inverse);
    border-radius: var(--radius-control);
  }
  .btn-cta:hover, .btn-cta:focus, .btn-cta:active, .btn-cta:active:focus {
    background-color: var(--brand-orange-dark);
    border-color: var(--brand-orange-dark);
    color: var(--text-inverse);
  }

  /* ---------- .btn-brand — Figma Buttons / "Brand (filled green)" ----------
     The filled brand-green action: the filter bar's "Vyhledat" — running a search commits nothing, so it
     takes brand green rather than the orange CTA.
     Coexists with: btn-primary.
     EMISSION: deliberately NOT a TYPE_* mapping.  TYPE_PRIMARY maps to `.btn-ghost` (the majority look:
     ~137 of its ~139 call sites render as the white ghost), and `.btn-brand` is written explicitly at
     the three places that really are brand green — the "Vyhledat" submit of the client, notification and
     commission-balance-log filter bars.  Those three are raw `Html::submitButton` and never passed
     through widgets/Button anyway, so the class is stated at the call site, which is where a one-off
     look belongs. */
  .btn-brand {
    background-color: var(--brand-green);
    border-color: var(--brand-green);
    color: var(--text-inverse);
    border-radius: var(--radius-control);
  }
  .btn-brand:hover, .btn-brand:focus, .btn-brand:active, .btn-brand:active:focus {
    background-color: var(--brand-green-dark);
    border-color: var(--brand-green-dark);
    color: var(--text-inverse);
  }

  /* ---------- .btn-ghost — Figma Buttons / "Ghost (white)" ----------
     The default quiet button, and the most common one in the app: white fill, strong-border outline,
     brand-green ink, mint on hover.
     Coexists with: btn-default (TYPE_DEFAULT) and btn-primary (TYPE_PRIMARY — the content-area
     btn-primary IS this look, which is why the two types share one canonical class).
     Some containers tint the hover with `--surface-tint` instead (box-solid headers, the content-area
     btn-primary); `--brand-mint-bg` is the base answer. */
  .btn-ghost {
    background-color: var(--surface-card);
    border-color: var(--border-strong);
    color: var(--brand-green);
    border-radius: var(--radius-control);
  }
  .btn-ghost:hover, .btn-ghost:focus {
    background-color: var(--brand-mint-bg);
    border-color: var(--border-strong);
    color: var(--brand-green);
  }

  /* ============ THE DANGER FAMILY ============
     One `btn-danger` used to wear three different looks.  The ruling: they are THREE JOBS, so three
     classes, and the WHITE GHOST is the canonical one — the quiet destructive button is the default,
     the louder two are earned.
       .btn-ghost-danger — the everyday destructive action (canonical)
       .btn-tile--danger — the blush tile in a record title row
       .btn-danger-solid — the verb in a confirm dialog, and nowhere else
     Only .btn-ghost-danger is emitted (TYPE_DANGER).  The other two are defined and documented here so
     the values do not have to be re-derived when they are wired. */

  /* ---------- .btn-ghost-danger — Figma Buttons / "Ghost danger" ----------
     The destructive action drawn quietly: white fill, red ink, tinted red border.  CANONICAL.
     Coexists with: btn-danger (widgets/Button TYPE_DANGER).  This is the look every btn-danger OUTSIDE
     `.content-wrapper` renders today. */
  .btn-ghost-danger {
    background-color: var(--surface-card);
    border-color: var(--status-danger-border);
    color: var(--status-danger-text);
    border-radius: var(--radius-control);
  }
  .btn-ghost-danger:hover, .btn-ghost-danger:focus {
    background-color: var(--status-danger-wash);
    border-color: var(--status-danger-text);
    color: var(--status-danger-text);
  }

  /* ---------- .btn-tile--danger — the pastel tile variant ----------
     The destructive action in a record title row, where the buttons are pastel tiles rather than
     outlines and a white ghost would read as a hole in the row.  Blush fill, no separate border colour,
     the same red ink.
     A MODIFIER, not a paint class: pair it with .btn-tile / .btn-tile-sm for the shape.
     No emission point yet. */
  .btn-tile--danger {
    background-color: var(--pastel-blush);
    border-color: var(--pastel-blush);
    color: var(--status-danger-text);
  }
  .btn-tile--danger:hover, .btn-tile--danger:focus {
    background-color: var(--pastel-blush-hover);
    border-color: var(--pastel-blush-hover);
    color: var(--status-danger-text);
  }

  /* ---------- .btn-danger-solid — the dialog verb ----------
     EXCLUSIVE to the OK button of a destructive confirm dialog.  The full-strength red is the one place
     the app still spends it: the dialog has already interrupted the user, the verb is the point of the
     interruption, and there is no surrounding content for it to shout over.  Do NOT use it anywhere
     else — an in-page destructive action is .btn-ghost-danger.
     No emission point yet: scripts.js builds the dialog buttons itself (btnOKClass / className), so
     this gets wired there rather than through widgets/Button. */
  .btn-danger-solid {
    background-color: var(--status-danger);
    border-color: var(--status-danger);
    color: var(--text-inverse);
    border-radius: var(--radius-control);
  }
  .btn-danger-solid:hover, .btn-danger-solid:focus {
    background-color: var(--status-danger-text);
    border-color: var(--status-danger-text);
    color: var(--text-inverse);
  }

  /* ---------- .btn-tile — Figma Buttons / "Icon tile 36" ----------
     The square icon-only tile of the record toolbar in body.toolbar-icons.
     Coexists with: the toolbar rules on `p.pull-left/.pull-right/.communication .btn`.
     `font-size: 0` is NOT restated: hiding a label the markup still carries is an icon-MODE concern that
     belongs to body.toolbar-icons, not to the tile shape — a `.btn-tile` is icon-only by construction.
     No emission point yet. */
  .btn-tile {
    width: var(--size-toolbar-icon-tile);
    height: var(--size-toolbar-icon-tile);
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
    flex: none;
    border-radius: var(--radius-control);
  }

  /* ---------- .btn-tile-sm — Figma Buttons / "Icon tile 28" ----------
     The grid-row action tile (view / update / delete) and the filter row's clear-filter funnel — both
     measure the same shape, which is why ActionColumn can emit it on both.
     Coexists with: btn-default + `.grid-view .action-column .btn`.
     Emitted by components/web/ActionColumn.php. */
  .btn-tile-sm {
    width: var(--size-grid-action-btn);
    height: var(--size-grid-action-btn);
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
    border-radius: var(--radius-control);
  }

  /* ---------- .btn-boxheader — Figma Buttons / "Box-header 28" ----------
     The small LABELLED button of a box header or a form sub-section heading.  A short button, not a
     tile: 3 + 20 line-height + 3 + 2 border = the 28px that lines it up with the tile ladder.
     Coexists with: btn-default inside `.box-header-buttons` (adminlte.css's `padding: 3px 6px`) and
     `.form-section-label--toggle .btn`.  In body.toolbar-icons the same button squares to
     --size-boxheader-icon-btn.  No emission point yet. */
  .btn-boxheader {
    padding: 3px 6px;
    line-height: 20px;
    border-radius: var(--radius-control);
  }

  /* ---------- .chip — Figma Chips / "Chip (pill)" ----------
     The bordered white pill: group-membership chips in the record title row, the saved-search chips on
     the home page, the entity chip in the Avíza/Úkoly lists.
     Coexists with: `.search-chip` (from the frozen home sheet, which is why the shape is restated here
     under the canonical name rather than aliased) and its two size modifiers `.entity-chip` /
     `.header-groups > .search-chip`, which carry the same 4/6 optical split at their own sizes.
     The 4/6 vertical padding is optical, not geometric — see `.kv-grid__value > .kv-pill`.
     Emitted by widgets/GroupChips.php (its _header-chips partial). */
  .chip {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 4px 8px 6px 14px;
    background-color: var(--surface-card);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-pill);
    font-size: 13px;
    color: var(--brand-green);
    transition: border-color 120ms, box-shadow 120ms;
  }
  .chip:hover {
    border-color: var(--brand-green);
    box-shadow: var(--shadow-box);
  }

  /* ---------- .status-chip — Figma Chips / "Status chip" ----------
     The small square-cornered state label.  There IS a shared shape: `.cbl-state` and `.kv-pill` are one
     rule and agree on all six metrics below; only the tint differs, and the tint belongs to the state
     modifier, so no fill or ink is declared here.  The 4/6 vertical padding is optical, not geometric —
     see that rule for the measurement.
     Coexists with: .cbl-state, .kv-pill.  No emission point yet. */
  .status-chip {
    display: inline-block;
    padding: 4px 8px 6px;
    border-radius: var(--radius-sm);
    font-size: 12px;
    font-weight: 600;
    line-height: 16px;
  }
}

/* ============================================================================================
   4a. AREAS / record title header and group chips
   ============================================================================================ */
/* The title row's pastel tiles: blush trash and sky merge.  (There is no cream star tile — a
   favourited star is a ghost tile with a GOLD GLYPH everywhere; see the grid-star block in 3e.) */
.content-header .btn-danger { background: var(--ok-blush) !important; border-color: var(--ok-blush); color: var(--status-danger-text); }
.content-header .btn-danger:hover { background: var(--pastel-blush-hover) !important; border-color: var(--pastel-blush-hover); color: var(--status-danger-text); }
.content-header > h1 > .title-text:after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 44px;
  height: 3px;
  border-radius: 2px;
  background: var(--ok-gold);
  display: none;
}
.content-header .btn.btn-merge { background: var(--ok-sky) !important; border-color: var(--ok-sky); color: var(--pastel-sky-text); }
.content-header .btn.btn-merge:hover { background: #B9CBF0 !important; border-color: #B9CBF0; color: var(--pastel-sky-text); }
/* Content-area pastels (grids, boxes): blush trash. */
.content-wrapper .btn-danger { background: var(--ok-blush) !important; border-color: var(--ok-blush); color: var(--status-danger-text); }
.content-wrapper .btn-danger:hover { background: var(--pastel-blush-hover) !important; border-color: var(--pastel-blush-hover); color: var(--status-danger-text); }
/* Disabled buttons: ghost stays visible but clearly inert */
.btn.disabled, .btn[disabled], fieldset[disabled] .btn {
  background: var(--surface-disabled) !important; border-color: var(--border-default) !important;
  color: var(--text-placeholder) !important; opacity: 1; cursor: not-allowed; box-shadow: none;
}
/* ---------- [header] gold bar + record actions in the fixed content header ---------- */
.content-header > h1 {
  display: flex;               /* h1:before{align-self:stretch} in okis-2026.css needs a flex h1 */
  align-items: center;
  gap: 14px;                   /* + the bar's own margin-right:14px = 28px bar-to-title */
  float: none;                 /* adminlte.css:459 floats the h1 at >=992px, which shrink-wraps it;
                                  the mock is float:none so the h1 spans the header and the actions'
                                  margin-left:auto can push them flush right. Safe: .content-header
                                  has no other child (no breadcrumb is rendered into it). */
  white-space: nowrap;         /* keep: single line, actions shrink-to-fit */
  overflow: visible;           /* adminlte.css:60 h1{overflow:hidden} would clip the buttons */
  /* One title-row height whether or not the row carries buttons.  Without this the row is only as
     tall as the 26.4px title line — a 7.6px shorter header on every page with no action — because
     the 34px buttons are what stretches it everywhere else.  34px is that button-carrying case
     (`--control-height`, the height both `.page-actions .btn` and the record trio are pinned to),
     and it is the CEILING the fixed header can take: 8 + 34 + 8 + 1 = 51px, one pixel inside the
     52px `.content` clears for it. */
  min-height: var(--size-control-height);
}
/* The gold bar is a 4px flex item, so it takes its proportional share of any shrinkage: measured
   4px -> 1.625px once the title is long enough to overflow. Pin it. */
.content-header > h1:before {
  content: "";
  width: 4px;
  align-self: stretch;
  background: var(--ok-gold);
  border-radius: 2px;
  margin-right: 14px;
  flex: none;
}
/* A long title must ellipsize here rather than overflow the header, now that the h1 no longer clips.
   `overflow != visible` also zeroes this flex item's automatic minimum size, so it can actually
   shrink. */
.content-header > h1 > .title-text { display: inline-block; position: relative; padding-bottom: 0; overflow: hidden; text-overflow: ellipsis; }
.content-header .record-actions {
  display: inline-flex;
  gap: var(--spacing-inline-gap);
  margin-left: auto;           /* actions sit flush right, NOT beside the title */
  padding-right: 8px;
  font-size: 14px;             /* don't inherit the h1's 24px */
  flex: none;                  /* a long title must ellipsize, never squash the buttons */
}
/* The header is position:fixed and `.content` only clears it by margin-top:52px (>=992px), so the
   title row's buttons must fit inside that budget: 3 + 18 line-height + 3 + 2 border = 26px, which fits
   the h1's 26.4px line box and leaves the header at its pre-change 50.4px.  Cheaper than touching
   adminlte.css's offset system. */
.content-header .btn { line-height: 18px; padding: 3px 10px; }
.content-header .record-actions .btn {
  width: var(--size-title-trio-btn); height: var(--size-title-trio-btn);
  padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 15px;
}
/* Disabled buttons must not react to hover.  The disabled palette is pinned at (0,2,0) with
   `!important`, but the per-variant HOVER rules are more specific and also `!important`, so they won in
   the disabled state — a disabled "Uložit" flashed dark orange and a disabled `btn-gold` flashed mint.
   The same mismatch also broke the RESTING disabled state of the gold/star variants
   (`.content-wrapper .btn.btn-gold` (0,3,0) already outranked `.btn.disabled` (0,2,0), so they stayed
   white instead of going ghost), so both states are re-asserted here.
   `.btn.btn` is a deliberate duplicate class: it lifts these selectors to (0,4,0) — enough to outrank
   the most specific competitor, `.content-wrapper .btn.btn-gold:hover` (0,4,0, which then loses the tie
   on load order) — without enumerating every variant by hand. */
.content-wrapper .btn.btn.disabled, .content-wrapper .btn.btn[disabled],
.content-wrapper .btn.btn.disabled:hover, .content-wrapper .btn.btn[disabled]:hover,
.content-wrapper .btn.btn.disabled:focus, .content-wrapper .btn.btn[disabled]:focus,
.content-wrapper .btn.btn.disabled:active, .content-wrapper .btn.btn[disabled]:active,
.content-wrapper fieldset[disabled] .btn, .content-wrapper fieldset[disabled] .btn:hover {
  background: var(--surface-disabled) !important;
  border-color: var(--border-default) !important;
  color: var(--text-placeholder) !important;
  box-shadow: none !important;
  transform: none !important;
}
/* ---------- Group chips under the record title ----------
   The chip row's `margin-left: auto` claims the free space, so the chips sit flush right with the
   record-action trio 20px after them.  When the widget renders nothing (no groups, no permission) the
   trio's own `margin-left: auto` still applies, so pages without chips are untouched.
   The `.search-chip` / `.search-chip__remove` base rules are not repeated here — they are in
   `4g. AREAS / home page`. */
.content-header > h1 > .header-groups {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--spacing-inline-gap);
  margin-left: auto;
  font-size: 13px;      /* don't inherit the h1's 24px */
  line-height: 18px;
  white-space: normal;  /* the h1 is nowrap; the chip row is the one place that may wrap */
  min-width: 0;
}
.content-header > h1 > .header-groups + .record-actions {
  margin-left: 20px;    /* the trio follows the chips, not the far edge */
}
/* The round 28x28 ⊕ — the small-tile rung of the size ladder.  Beats
   `.content-header .btn { padding: 3px 10px }` on specificity, and is deliberately OUTSIDE
   `.record-actions` so the trio's 34px squares do not apply. */
.content-header > h1 > .header-groups > .header-groups__add {
  width: var(--size-chip-add-btn);
  height: var(--size-chip-add-btn);
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-pill);
  font-size: 11px;
  line-height: 1;
  flex: none;
}
/* ---------- Page actions in the content header ----------
   Not `.record-actions`: that class squares its buttons into icon tiles and these carry labels.  The
   placement is the record-actions placement without the squaring. */
.content-header .page-actions {
  display: inline-flex;
  gap: 8px;
  margin-left: auto;
  padding-right: 8px;
  font-size: 14px;
  flex: none;                  /* a long title must ellipsize, never squash the buttons */
}
/* ---------- The record title toolbar ----------
   The trio gained Zavřít (✕ ghost) and Uložit (a disc) as one row, and the floating `.form-actions` bar
   is gone from the pages that have the toolbar.  The two tiles inherit the trio's squaring and gap from
   `.content-header .record-actions`, so the only work here is colour.
   Not touched: the `.form-actions` fixed-positioning rules in adminlte.css — every other form in the app
   (dialogs, lookup tables, create pages, user profile) still uses that bar.

   Uložit is the ORANGE CTA: orange is the CTA FAMILY, and the save disc is the save action wherever it
   is drawn.  The rule stays rather than being deleted because the selector documents WHY it can win
   (`.content-wrapper .btn-success { background: var(--ok-orange) !important }` is (0,2,0), this is
   (0,4,0) and repeats the `!important`) and it pins the state explicitly so the disc cannot drift if the
   base changes again.  `:active` is listed with hover/focus because the base states the same three. */
.content-header .record-actions .btn.btn-success {
  background: var(--ok-orange) !important;
  border-color: var(--ok-orange);
  color: var(--text-inverse);
}
.content-header .record-actions .btn.btn-success:hover,
.content-header .record-actions .btn.btn-success:focus,
.content-header .record-actions .btn.btn-success:active {
  background: var(--ok-orange-dark) !important;
  border-color: var(--ok-orange-dark);
  color: var(--text-inverse);
}
/* Sloučit retires its Sky Blue fill for a white ghost with a dark-green glyph, so the toolbar reads as
   one row of quiet tiles with a single filled action (Uložit).  Same specificity trick: the fill rule is
   `.content-header .btn.btn-merge` at (0,3,0). */
.content-header .record-actions .btn.btn-merge {
  background: var(--surface-card) !important;
  border-color: var(--border-strong);
  color: var(--ok-green);
}
.content-header .record-actions .btn.btn-merge:hover,
.content-header .record-actions .btn.btn-merge:focus,
.content-header .record-actions .btn.btn-merge:active {
  background: var(--surface-tint) !important;
  border-color: var(--ok-green);
  color: var(--ok-green-dark);
}
/* ---------- Navbar ----------
   Every navbar button is white with dark-green ink.  Matching on `.navbar-nav > li > .btn` rather than on
   the variant classes is what makes the bell consistent: it is a bare `.btn` while there is nothing
   unread and a `.btn.btn-primary` once there is (views/layouts/header.php), so keying off the variant
   would have made it change shape with the count.  The same selector leaves the search pair alone — it
   sits one level deeper, inside `.input-group-btn`, and is already this exact ghost. */
.main-header .navbar .navbar-nav > li > .btn,
.main-header .navbar .btn-primary.btn-user, .main-header .btn-user {
  background: var(--surface-card) !important;
  border-color: var(--border-strong) !important;
  color: var(--ok-green) !important;
  font-weight: 400;
}
/* Logout is a bare white glyph on the green header — no fill, no border; hover is a 15% white
   wash. It is the one navbar button that does NOT go white, so it has to outrank the white block
   above ((0,4,1) with the `> li >` selector) — hence the same shape plus `.btn-logout`. */
.main-header .navbar .navbar-nav > li > .btn.btn-logout,
.main-header .navbar .btn-logout, .main-header .btn-logout {
  background: transparent !important;
  border-color: transparent !important;
  color: var(--text-inverse) !important;
  box-shadow: none;
}
.main-header .navbar .navbar-nav > li > .btn.btn-logout:hover,
.main-header .navbar .navbar-nav > li > .btn.btn-logout:focus,
.main-header .navbar .btn-logout:hover, .main-header .btn-logout:hover {
  background: rgba(255, 255, 255, .15) !important;
  border-color: transparent !important;
  color: var(--text-inverse) !important;
}
.list-filter-bar__actions .btn.btn-primary:hover,
.list-filter-bar__actions .btn.btn-primary:focus,
.list-filter-bar__actions .btn.btn-primary:active,
.list-filter-bar__actions .btn.btn-primary:active:focus {
  background: var(--ok-green-dark) !important;
  border-color: var(--ok-green-dark);
  color: var(--text-inverse);
}
/* ---------- The title row's own edges ----------
   The record-action trio is 34px squares, joining the control height.  The header's top padding is
   trimmed to 8px so the fixed header still stays within the 52px content offset (8 + 34 + 8 + 1 = 51px).

   THE RIGHT EDGE.  The fixed header's padding-left is 24px to match `.content`, but its padding-right was
   left at AdminLTE's 15px — so the h1 ended 9px past where the content ends, and the record-actions' own
   `padding-right: 8px` then put the last button past that.  Both are restated: 24px matches the content
   column on both sides, and with that the trio's extra 8px would push it 8px INSIDE the cards' right
   edge, so it goes.  `.page-actions` — the index pages' other occupant of this header — carries the same
   8px for the same reason and is zeroed with it. */
.content-header { padding-left: 24px; padding-top: 8px; padding-right: 24px; }
.content-header .record-actions,
.content-header .page-actions { padding-right: 0; }
/* ---------- A LABELLED title-row action is 34px ----------
   `.content-header .btn` is deliberately squeezed to `padding: 3px 10px` so the fixed header
   stays inside the 52px `.content` clears for it, which leaves the header at 44.4px.  A LABELLED page
   action inherited that squeeze and came out 26px tall while every other control on the page is 34px.
   Restoring the app's standard 14px side padding and taking the vertical to 7px gives
   7 + 18 (the header's own line-height) + 7 + 2 = 34px — the `--control-height` value, reached through
   the padding because the header's line-height is 18px and not the content area's 20px.

   34px and NOT the 36px a record toolbar uses: that toolbar sits in the scrolling content and can be any
   height, these sit in the FIXED header, and 9+36+8+1 = 54px would push it past the 52px offset and over
   the top of the page.  34px lands the header at exactly 52px — flush, no overlap, and the largest value
   that fits.  If 36px is ever wanted here, the header's padding and `.content`'s offset have to move
   together.

   Nothing is needed for the two-line labels three of these pages carry: the bar is
   `align-items: flex-end`, so a taller label grows its own field upwards and every CONTROL on the row
   still shares one baseline. */
.content-header .page-actions .btn { padding: 7px 14px; height: var(--size-control-height); }
/* The `.page-actions` Pjax containers.  `yii\widgets\Pjax` renders a `<div>`, and modules.js reloads
   both by id after a phase change, so neither may be unwrapped in the markup.  As flex ITEMS they would
   swallow the group's gap between their own children and, when a state renders them empty, still claim a
   gap of their own on both sides.  `display: contents` takes the boxes out of the layout while leaving
   the elements — and therefore the pjax targets — in the DOM, so the buttons inside become direct flex
   children of `.page-actions` and the group spaces itself as if it were flat. */
.content-header .page-actions > div { display: contents; }
/* ---------- The title-row trio: ghost tiles with coloured ink ----------
   User ruling.  The trio was the last place in the app where a button's MEANING was carried by a pastel
   FILL (a Buttercream star, a Powder Blush delete) while every other button in the row says it with ink on
   white — two fills against three ghosts and one orange disc read as four button systems in 200px.  So the
   fills go and the ink stays: one ghost shell, four glyphs.

     ☆ / ★  outline star in brand green / filled star in gold   (`btn-star-off` / `btn-star`)
     ⤢ 🗑 ✕  merge and close in brand green, delete in RED ink
     💾      Uložit stays the ORANGE DISC

   BORDER: `--border-strong` on all four, INCLUDING delete.  The canonical `.btn-ghost-danger` uses the
   tinted `--status-danger-border`, which is right for a free-standing destructive button; here the four
   tiles are one row and a different border on one of them re-introduces exactly the "several systems"
   problem this removes.  The red ink plus the trash glyph is signal enough, and the HOVER does take the
   danger border.

   SPECIFICITY: the fills are `!important` at (0,3,0) and (0,2,0) (`.content-wrapper .btn-danger` also
   matches, since `.content-header` is inside `.content-wrapper`).  Adding `.record-actions` takes these to
   (0,4,0) / (0,3,0) and they repeat the `!important`, so they win outright and the scope stays exactly the
   title-row trio: the same classes on a grid row or in a dialog are untouched. */
.content-header .record-actions .btn.btn-star,
.content-header .record-actions .btn.btn-star-off,
.content-header .record-actions .btn.btn-danger {
  background: var(--surface-card) !important;
  border-color: var(--border-strong);
}
.content-header .record-actions .btn.btn-star { color: var(--brand-gold); }
.content-header .record-actions .btn.btn-star-off { color: var(--brand-green); }
.content-header .record-actions .btn.btn-danger { color: var(--status-danger); }
.content-header .record-actions .btn.btn-star:hover,
.content-header .record-actions .btn.btn-star:focus,
.content-header .record-actions .btn.btn-star:active {
  background: var(--surface-tint) !important;
  border-color: var(--brand-gold);
  color: var(--brand-gold-dark);
}
.content-header .record-actions .btn.btn-star-off:hover,
.content-header .record-actions .btn.btn-star-off:focus,
.content-header .record-actions .btn.btn-star-off:active {
  background: var(--brand-mint-bg) !important;
  border-color: var(--border-strong);
  color: var(--brand-green-dark);
}
.content-header .record-actions .btn.btn-danger:hover,
.content-header .record-actions .btn.btn-danger:focus,
.content-header .record-actions .btn.btn-danger:active {
  background: var(--status-danger-wash) !important;
  border-color: var(--status-danger);
  color: var(--status-danger-text);
}
/* ---------- The groups ⊕ carries a label when there are no groups ----------
   With chips beside it the bare ⊕ is unambiguous: it is the "one more of these" control at the end of a
   row of groups.  Alone on the title line it names nothing — there is no "Skupiny" anywhere else on the
   page for it to attach to.  The markup adds the label and this modifier only in that case, so a record
   WITH groups is byte-identical to before.

   Icon-only mode keeps the bare tile.  `font-size: 0` blanks the text node without a wrapper to hang
   `display: none` on and restores the glyph on the direct `.fa` child — the same technique the
   box-header buttons use, for the same reason (the label is a bare text node next to the `<i>`).
   `body.toolbar-icons` in front takes that selector to (0,4,1) against this modifier's (0,3,1), so it
   wins on count and the order of the two blocks is irrelevant. */
.content-header > h1 > .header-groups > .header-groups__add--labelled {
  width: auto;
  height: var(--size-chip-add-btn);
  padding: 0 12px;
  gap: 6px;
  font-size: 13px;
}
/* A bar whose submit is a NAMED action ("Odeslat", "Provést", "Použít") keeps its word and lands
   in `.page-actions`, the title row's labelled-CTA slot, rather than becoming a floppy disc.
   `.page-actions` and `.record-actions` each carry `margin-left: auto`, so on the one page that
   ends up with BOTH (Adresář: Použít + Zavřít) the free space was shared between them and the CTA
   stopped 500px short of its tile. Only the first of the pair should push. */
.content-header > h1 > .page-actions + .record-actions { margin-left: 0; }

/* ============================================================================================
   4b. AREAS / icon-only toolbar mode — the opt-in user preference `body.toolbar-icons`.
   ============================================================================================ */
/* The tile geometry is the designer-approved mock's:
     .content .btn[title] { width: 36px; padding-left: 0; padding-right: 0; text-align: center }
     .content .btn[title]:has(.caret) { width: 48px }
     .content .btn[title] .caret { margin-left: 2px }
     .btn-group .btn[title] { width: 36px }
   The mock's own markup had already dropped the button text, so it needed no text-hiding rule; our
   buttons keep their full markup, so the text is hidden here (`font-size: 0`) and restored on the icon
   only — the hidden label lives on in the `title` tooltip that LinkButton sets automatically.
   Scoped to the actual toolbar containers (the pull-left/pull-right action rows and the communication
   multi-button) rather than the mock's broad `.content`, so grid buttons, form buttons and the
   record-actions trio are never touched. */
body.toolbar-icons p.pull-left .btn[title],
body.toolbar-icons p.pull-right .btn[title],
body.toolbar-icons .communication .btn[title] {
  width: var(--size-toolbar-icon-tile);
  padding-left: 0;
  padding-right: 0;
  text-align: center;
  font-size: 0;
}
body.toolbar-icons p.pull-left .btn[title] > .fa,
body.toolbar-icons p.pull-right .btn[title] > .fa,
body.toolbar-icons .communication .btn[title] > .fa {
  font-size: 13px; /* matches the current .btn text size */
}
body.toolbar-icons p.pull-left .btn[title]:has(.caret),
body.toolbar-icons p.pull-right .btn[title]:has(.caret),
body.toolbar-icons .communication .btn[title]:has(.caret) {
  width: 48px;
}
body.toolbar-icons p.pull-left .btn[title] .caret,
body.toolbar-icons p.pull-right .btn[title] .caret,
body.toolbar-icons .communication .btn[title] .caret {
  margin-left: 2px;
}
/* Split "+" groups (e.g. Smlouvy/Obchodní případ/Pojistné události): the titled
   btn-gold segment gets the same fixed 36px; the untitled btn-success "+" segment
   already has no text to hide and keeps its natural (icon-only) width. */
body.toolbar-icons p.pull-right .btn-group .btn[title] {
  width: var(--size-toolbar-icon-tile);
}
/* A toolbar button with NO icon must opt OUT of the icon treatment entirely.  The rules above key the
   text-hiding off `.btn[title]` alone and restore the glyph via `.btn[title] > .fa`, so a button whose
   markup carries no `<i>` lost its label and gained nothing back — a blank 36x36 tile.  The label is the
   only affordance those buttons have.  `:not(:has(> .fa))` lifts these selectors to (0,5,2) vs the
   block's (0,4,2), so they win on specificity, not order. */
body.toolbar-icons p.pull-left .btn[title]:not(:has(> .fa)),
body.toolbar-icons p.pull-right .btn[title]:not(:has(> .fa)),
body.toolbar-icons .communication .btn[title]:not(:has(> .fa)) {
  width: auto;
  padding-left: 10px;
  padding-right: 10px;
  font-size: 13px;
}
/* Icon-row rhythm.  The rows are inline flow, so the gaps were whatever whitespace text nodes and the
   widgets' inline `margin: 0 3px` happened to add up to — measured 3, 3.3, 3.9, 5, 6.1 and 8px between
   neighbours on one page — and the help "?" icons (a bare `<i>` sibling of the buttons,
   `vertical-align: baseline`) sat 1.5px above the buttons' optical centre.  Making each row the flex row
   the mock already is fixes both: whitespace-only text nodes generate no flex items, so the spacing
   becomes exactly one uniform gap, and `align-items: center` centres the "?" against the tiles.
   `flex: none` on the icons so a full row can never squeeze them.
   Scoped to `body.toolbar-icons` — the default text toolbar keeps its accepted look. */
body.toolbar-icons p.pull-left,
body.toolbar-icons p.pull-right,
body.toolbar-icons .communication > .pull-left {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--spacing-inline-gap);
}
/* CommunicationButton writes `margin-left/right: 3px` as inline styles on the wrapper and on
   every button inside it, which would stack with the gap — hence !important. The wrapper keeps
   a 6px right margin because it is a separate float, not a flex sibling of `p.pull-left`. */
body.toolbar-icons .communication .btn { margin-left: 0 !important; margin-right: 0 !important; }
body.toolbar-icons .communication > .pull-left { margin-left: 0 !important; margin-right: var(--spacing-inline-gap) !important; }
body.toolbar-icons p.pull-left > .help-item-icon,
body.toolbar-icons p.pull-right > .help-item-icon,
body.toolbar-icons .communication .help-item-icon {
  flex: none;
  margin-left: 0;
  line-height: 1;
}
/* Icon-only mode reaches the box headers: the box-header buttons and the sub-section create button
   become square icon tiles too.  This is strictly a `body.toolbar-icons` treatment — in text mode they
   stay icon + text — and production markup keeps the full label while the CSS hides it, exactly as the
   toolbar block above does.
   The tile takes the 28px rung, which is the exact height the same buttons measure WITH text, so the
   tile cannot grow the header by 2px when icon mode is on.
   The font-size restore deliberately matches the DIRECT `.fa` child only: the composite glyph below
   sizes itself and its parts, and a descendant selector here would outrank it. */
body.toolbar-icons .box > .box-header .box-header-buttons .btn[title],
body.toolbar-icons .form-section-label--toggle .btn[title] {
  width: var(--size-boxheader-icon-btn);
  height: var(--size-boxheader-icon-btn);
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 0;
}
body.toolbar-icons .box > .box-header .box-header-buttons .btn[title] > .fa,
body.toolbar-icons .form-section-label--toggle .btn[title] > .fa {
  font-size: 13px;
}
/* Same opt-out as the toolbar rows: a button with no glyph at all would become an empty tile, so it
   keeps its label.  `:not(:has(.fa))` adds one class level, so it wins on specificity. */
body.toolbar-icons .box > .box-header .box-header-buttons .btn[title]:not(:has(.fa)),
body.toolbar-icons .form-section-label--toggle .btn[title]:not(:has(.fa)) {
  width: auto;
  padding: 3px 6px;
  font-size: 13px;
}
/* The icon-mode-only glyph carried by buttons that the text mode renders as a label alone ("Vložit do
   obálky", "Spojit dokumenty").  Hidden by default so text mode is unaffected.  The envelope + arrow
   composite is knocked out of the button fill so the two glyphs stay legible where they overlap. */
.btn-icon-glyph { display: none; }
body.toolbar-icons .btn-icon-glyph {
  position: relative;
  display: inline-flex;
  font-size: 12px;
  line-height: 1;
}
body.toolbar-icons .btn-icon-glyph > .fa-arrow-down {
  position: absolute;
  top: -7px;
  left: 50%;
  transform: translateX(-50%);
  font-size: 8px;
  text-shadow: -1.5px 0 var(--surface-card), 1.5px 0 var(--surface-card), 0 1.5px var(--surface-card), 0 -1.5px var(--surface-card);
}
/* ---------- One row, one height: the icon-mode tile is a SQUARE ----------
   Two things had to be pinned here.  (1) With `font-size: 0` the button's line box comes from whatever
   is inside it: an `<i>` at 13px produced a 21px content box (37px total) while an empty one fell back to
   the 20px line-height (36px), so icon buttons sat 1px taller than the icon-less and the untitled "+"
   segments — hence the explicit height and the geometric centring instead of inline layout.  (2) That
   height used to be expressed as `var(--control-height)`, and when the control token moved 36 -> 34 every
   icon-mode toolbar tile quietly became a 36x34 RECTANGLE.

   So the height is `--size-toolbar-icon-tile` (the designer's own toolbar spec) and NOT the control
   token, which the form controls need at 34.  `p.` in the selectors is deliberate but has a known gap: a
   toolbar group that sits in a `div.pull-left` (Pjax cannot wrap a `<p>`) is not reached, which is why
   the commission balance-log toolbar has a rule of its own. */
body.toolbar-icons p.pull-left .btn,
body.toolbar-icons p.pull-right .btn,
body.toolbar-icons .communication .btn {
  padding-top: 0;
  padding-bottom: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  height: var(--size-toolbar-icon-tile);
}
/* ---------- The Export group joins the icon-only toolbar ----------
   The one toolbar control the rules above can NEVER reach, because it can never live where they look.
   They are scoped to the toolbar PARAGRAPHS, and ExportButton emits a `.btn-group` holding a
   `<ul class="dropdown-menu">` — and a `<ul>` start tag CLOSES an open `<p>`, no matter how deeply it is
   nested inside it, so the group is always a SIBLING of the paragraph in the parsed DOM.  (The same rule
   is why "PDF formuláře" used to escape the paragraph on contract update: a `<div class="communication">`
   sat between them.  That one is fixed in the markup, because the div genuinely belonged outside.)

   So the group is matched by its own class instead.  The declarations are the toolbar block's own,
   restated for this selector rather than added to its list, so the paragraph rules keep saying exactly
   what they say today.  The 6px margin is the row gap — the group is not a flex item of the row, so it
   has to state it itself, and the widget writes 3px inline on both sides, hence the `!important` pair. */
body.toolbar-icons .export-actions > .btn[title] {
  width: 48px;
  height: var(--size-toolbar-icon-tile);
  padding-left: 0;
  padding-right: 0;
  text-align: center;
  font-size: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
body.toolbar-icons .export-actions > .btn[title] > .fa { font-size: 13px; }
body.toolbar-icons .export-actions > .btn[title] .caret { margin-left: 2px; }
body.toolbar-icons .export-actions { margin-left: var(--spacing-inline-gap) !important; margin-right: 0 !important; }
body.toolbar-icons .content-header > h1 > .header-groups > .header-groups__add--labelled {
  width: var(--size-chip-add-btn);
  padding: 0;
  gap: 0;
  font-size: 0;
}
body.toolbar-icons .content-header > h1 > .header-groups > .header-groups__add--labelled > .fa {
  font-size: 11px;
}
/* ---------- The box-header ⊕▾ needs room for its caret ----------
   `body.toolbar-icons` only.  The rule above squares every titled box-header button to 28px with
   `padding: 0` and `font-size: 0`, which is right for a single-glyph ⊕.  One box header's button is a
   ButtonDropdown, so it renders TWO children — `.fa-plus-circle` and `.caret` — into the same 28px, and
   the two touch.  The toolbar block twenty lines up already ruled on exactly this shape: a titled icon
   button carrying a caret goes 36 -> 48px, i.e. +12px for the caret and its 2px gap.  The same +12 on
   the 28px header rung is 40px.

   40 is the same NUMBER as --size-input-addon and deliberately NOT the same TOKEN: one is the icon-mode
   header tile with a caret, the other the addon column, and they answer to different rungs (28 and 34).
   `:has(.caret)` adds one level over the base selector, so it wins without an `!important`. */
body.toolbar-icons .box > .box-header .box-header-buttons .btn[title]:has(.caret),
body.toolbar-icons .form-section-label--toggle .btn[title]:has(.caret) {
  width: 40px;
}
body.toolbar-icons .box > .box-header .box-header-buttons .btn[title] .caret,
body.toolbar-icons .form-section-label--toggle .btn[title] .caret {
  margin-left: 2px;
}

/* ============================================================================================
   4c. AREAS / entity forms
   ============================================================================================ */
/* Field-label variant (e.g. Cizinec): label on top, box below — opt in with
   'checkbox-stack' on the field's form-group. */
.checkbox-stack .checkbox label:has(> input[type="checkbox"]) {
  flex-direction: column-reverse;
  align-items: flex-start;
  gap: 6px;
}
/* ---------- [subjekt-grid] ----------
   The Subjekt section of the client update form.  The company and person branches place the same fields
   in different columns and a different order, and the three always-visible fields (RČ/IČO, Typ klienta,
   Cizinec) are single SHARED instances — so one float-based source order cannot render both branches
   without leaving a hole in row 1.  The section is a 12-column grid instead and each field container is
   positioned per branch.
   Geometry is Bootstrap's, deliberately: the container carries `.row`'s -15px side margins and every item
   carries `.col-md-*`'s 15px side padding, so a span of N columns is pixel-identical to `.col-md-N` and
   the field rhythm matches the neighbouring sections. */
.subjekt-grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  margin-left: -15px;
  margin-right: -15px;
}
.subjekt-grid .sj-col {
  padding-left: 15px;
  padding-right: 15px;
  min-width: 0;
}
/* The #has-name / #has-id-number toggle wrappers must not form a box of their own, otherwise
   their children cannot be placed in the parent grid. Kept deliberately below the specificity of
   site.css's `.client-update #has-name.disabled { display: none }` (id + 2 classes) so hiding a
   branch still wins over this rule. */
.subjekt-grid .sj-branch {
  display: contents;
}
/* Placement uses a definite row plus a span and an explicit order — never a definite column — so
   auto-placement packs each row left to right in `order` sequence. A branch whose optional field
   is absent (no Právní forma when the client type does not load ARES) then closes up instead of
   leaving a hole. */
.subjekt-grid.is-person .sj-id-number    { grid-row: 1; grid-column: span 5; order: 1; }
.subjekt-grid.is-person .sj-client-type  { grid-row: 1; grid-column: span 5; order: 2; }
.subjekt-grid.is-person .sj-foreign      { grid-row: 1; grid-column: span 2; order: 3; }
.subjekt-grid.is-person .sj-pre-nominal  { grid-row: 2; grid-column: span 2; order: 4; }
.subjekt-grid.is-person .sj-lastname     { grid-row: 2; grid-column: span 4; order: 5; }
.subjekt-grid.is-person .sj-firstname    { grid-row: 2; grid-column: span 4; order: 6; }
.subjekt-grid.is-person .sj-post-nominal { grid-row: 2; grid-column: span 2; order: 7; }
.subjekt-grid.is-company .sj-id-number   { grid-row: 1; grid-column: span 3; order: 1; }
.subjekt-grid.is-company .sj-name        { grid-row: 1; grid-column: span 6; order: 2; }
.subjekt-grid.is-company .sj-client-type { grid-row: 1; grid-column: span 3; order: 3; }
.subjekt-grid.is-company .sj-legal-form  { grid-row: 2; grid-column: span 5; order: 4; }
.subjekt-grid.is-company .sj-file-sign   { grid-row: 2; grid-column: span 5; order: 5; }
/* Cizinec is the row's right-edge checkbox in both branches, so pin it there: if Právní forma is
   absent the two text fields close up on the left and the checkbox stays put. */
.subjekt-grid.is-company .sj-foreign     { grid-row: 2; grid-column: 11 / span 2; order: 6; }
/* ---------- The unified "add to group" popup ----------
   The popup holds a single field, so its body collapses to about 70px — and `showDialog()` moves
   `.form-actions` out of the body into the dialog FOOTER, which then sits directly under the select.  The
   dropdown is absolutely positioned and would cover "Přidat" / "Zavřít" for as long as it is open.
   Reserving room on the form (a direct child of `.modal-body`, so its height grows the body) keeps the
   dropdown over empty space instead. */
.group-assign-form { min-height: 230px; }
/* The one select2 that both picks an existing group and creates a new one.  Existing groups carry a
   mint fa-tag; the "create new" option is the highlighted last row.  The markup comes from the widget's
   templateResult, so these are plain descendant rules — no specificity fight with the select2
   stylesheets, which style the <li> and not its contents.  Both options share the same glyph gutter so
   the labels line up whichever kind of row the eye lands on. */
.group-option > .fa,
.group-option-new > .fa {
  width: 16px;
  margin-right: 6px;
  text-align: center;
}
.group-option > .fa-tag { color: var(--ok-mint); }
/* The create row reads as an action, not as one more group in the list: green label, mint
   tint, and a rule separating it from the groups above it. `display: block` with negative
   margins that cancel the option's own padding (measured 7px 12px live, krajee-bs3 theme)
   lets the tint and the divider bleed to the full row — an inline span would leave a gap
   on every side. The divider is --border-strong rather than --border-default so it stays
   visible against the mint that select2 paints the highlighted row with. */
.group-option-new {
  display: block;
  margin: -7px -12px;
  padding: 7px 12px;
  border-top: 1px solid var(--border-strong);
  background-color: var(--surface-tint);
  color: var(--ok-green);
  font-weight: 500;
}
.group-option-new > .fa-plus-circle { color: var(--ok-green); }
/* Highlighted, select2 already paints the row mint with green text — which is the mock's
   treatment for this option anyway — so step out of the way and only keep the divider. */
.select2-results__option--highlighted .group-option-new {
  background-color: transparent;
  color: inherit;
}
.select2-results__option--highlighted .group-option-new > .fa-plus-circle,
.select2-results__option--highlighted .group-option > .fa-tag { color: inherit; }
/* The hint under the field collided with the select: kartik's activeform.css pulls
   `.kv-form-bs3 .hint-block` up by 5px, which suits a plain input's slack but lands the text on top
   of select2's block.  That stylesheet is injected into the dialog body at render time, i.e. AFTER
   this file, so an equal-specificity (0,2,0) rule would lose — hence the duplicate-class trick the
   disabled-button block also uses.  Scoped to this popup so hints elsewhere keep the vendor
   spacing. */
.group-assign-form.group-assign-form .hint-block { margin-top: 4px; }
/* Checkbox rows: box on the left, 10px gap, label weight normal.  The app's canonical BS3/Yii markup
   nests the input inside the label, so the LABEL is the flex container.  The `:has()` is not decoration —
   it has to be carried over from the base `.checkbox label:has(> input[type="checkbox"])` rule whose gap
   this overrides: `:has()` lends its argument's weight, putting that rule at (0,2,2), which a plain
   `.group-assign-form .checkbox label` (0,2,1) would lose to. */
.group-assign-form .checkbox label:has(> input[type="checkbox"]) {
  display: flex;
  align-items: center;
  gap: 10px;
  font-weight: 400;
}
.group-assign-form .checkbox label input[type="checkbox"] { margin: 0; flex: none; }
.group-assign-notify > .form-group:last-child { margin-bottom: 0; }
/* Rizika: one card per risc instead of a stack of nested boxes. */
.risk-card {
  border: 1px solid var(--border-default);
  border-left: 4px solid var(--status-risk-edge);
  border-radius: var(--radius-control);
  margin-bottom: 10px;
  background: var(--surface-card);
}
.risk-card__head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 14px;
  background: var(--brand-mint-bg);
  border-radius: calc(var(--radius-control) - 1px) calc(var(--radius-control) - 1px) 0 0;
}
.risk-card__name {
  color: var(--ok-green);
  font-size: 14px;
}
.risk-card__toggle {
  margin-left: auto;
  width: 24px;
  height: 24px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
}
/* Nine columns: Specifikace / Pojistná částka / Limit plnění / Čerpání z limitu / Spoluúčast / Počátek /
   Konec / Sazba / Sleva.  `align-items: end` keeps the inputs on one baseline when a label wraps to two
   lines.  Roční / Lhůtní pojistné are two extra cells that only exist in "sum of riscs" mode; while
   modules.js keeps them `.hidden` they are display:none and take no grid cell, so the common case is
   exactly nine. */
.risk-grid {
  display: grid;
  grid-template-columns: 1.2fr 1fr 1fr 1fr 0.8fr 1fr 1fr 0.7fr 0.8fr;
  gap: 10px;
  padding: 12px 14px;
  align-items: end;
}
.risk-grid > .form-group {
  margin-bottom: 0;
}
/* Hidden value carriers (lock_version, risc_ids_hidden, the premium *_hidden pair) sit outside
   the grid — zero height, but their .form-group margin would still open a gap above it. */
.subject-risc-form > .form-group {
  margin-bottom: 0;
}
/* Unarranged riscs: slim row, GOLD edge, field grid collapsed.  `--off` is the server's verdict
   (SubjectRisc::$is_active) and never changes client-side; `--collapsed` is the +/− toggle.
   User ruling: a not-yet-insured risk is a STATE, not an error, so the whole `--off` treatment sits in
   the warning family rather than the danger one. */
.risk-off-heading {
  border-bottom: 0;
  margin: 18px 0 10px;
}
.risk-card--off {
  border-color: var(--panel-warning-border);
  border-left-color: var(--ok-gold);
  margin-bottom: 8px;
  background: var(--panel-warning-bg);
}
.risk-card--off .risk-card__head {
  background: var(--panel-warning-bg);
  border-radius: calc(var(--radius-control) - 1px);
}
.risk-card--off .risk-card__name {
  color: var(--panel-warning-text);
  font-size: 13px;
  font-weight: 600;
}
.risk-card--collapsed > .risk-card__body {
  display: none;
}
/* …unless the collapsed risc failed validation: its messages must stay reachable. A risc with
   data is normally active (= expanded) after a failed save, but rate/discount can be rejected
   while the risc has no start date, which would otherwise hide the error. */
.risk-card--collapsed:has(.has-error) > .risk-card__body {
  display: block;
}
/* ---------- Subject "Nesjednaná rizika": compact pills ----------
   The unarranged riscs were slim full-width bars; compacted into pills that wrap across the row, a
   vehicle with a dozen of them costs three lines instead of twelve.  Nothing inside the cards moved, so
   every field name and the POST are unchanged.

   The pill/card distinction is carried entirely by `.risk-card--collapsed`, which is exactly the class the
   +/− toggle adds and removes.  That is what keeps the expand behaviour: the click handler is untouched,
   and dropping the class turns the pill back into the full card on a row of its own, wide enough for the
   nine-column field grid. */
.risk-off-list {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: flex-start;
}
/* Default for anything in the list: a full row, i.e. the card.  `flex-basis: 100%` is also what forces an
   expanded risc onto its own flex line.  The margin goes because the row's `gap` now does the spacing. */
.risk-off-list > .risk-card {
  flex: 1 0 100%;
  margin-bottom: 0;
}
/* …unless it is collapsed, in which case it shrinks to its content and shares the row.
   `:not(:has(.has-error))` mirrors the escape hatch below: a collapsed risc whose fields failed
   validation keeps its body visible, and a visible field grid needs the full width. */
.risk-off-list > .risk-card--collapsed:not(:has(.has-error)) {
  flex: 0 0 auto;
/* the 4px gold edge is a card affordance; on a pill the tint carries the meaning */
  border: 1px solid var(--panel-warning-border);
  border-radius: var(--radius-pill);
}
.risk-off-list > .risk-card--collapsed:not(:has(.has-error)) > .risk-card__head {
  padding: 4px 5px 4px 12px;
  gap: 8px;
  border-radius: var(--radius-pill);
}
/* The round 22px "+".  `margin-left: auto` resolves to 0 in a content-sized flex container, so the button
   sits hard against the name — the same mechanism the chip row relies on. */
.risk-off-list > .risk-card--collapsed:not(:has(.has-error)) .risk-card__toggle {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  font-size: 11px;
}
/* "Zasílat upozornění" sits in its own tinted panel, since it applies to the group being CREATED rather
   than to the assignment — it appears only when the select2 carries a new name.  The inner form-group's
   trailing margin would show up as dead space inside the panel. */
.group-assign-notify {
  padding: 12px;
  border-radius: var(--radius-control);
  background-color: var(--surface-tint);
  margin-bottom: 10px;
}
/* ---------- A stacked checkbox sits on its row's control line ----------
   `.checkbox-stack` stacks label-over-box, and the box then inherited the block-checkbox centring margin,
   so it hung ~3px below the line it shares with the date inputs beside it (bottom-aligned to the 34px
   input rather than centred on it).  Zeroing just the box's own VERTICAL margin leaves the stack's 6px gap
   to do the spacing and lands the box's centre on the input's centre.  The horizontal margin is
   deliberately untouched — the inline variant needs it.

   Scoped to `.checkbox-stack`, which is the shared opt-in for this exact geometry (three fields use it,
   all sitting next to 34px inputs), and one class more specific than the rule it corrects.
   (The row's HORIZONTAL misalignment was a markup fix — a grid column's width is what the `col-md-*`
   class means, and overriding it in CSS would leave the view claiming a width it no longer has.) */
.checkbox-stack .checkbox label:has(> input[type="checkbox"]) > input[type="checkbox"] {
  margin-top: 0;
  margin-bottom: 0;
}
/* Field widths.  The three row-1 selects are capped so the free space goes to the search term (the widest
   field by far — it takes six kinds of identifier), and the row-2 select2s share the line evenly with the
   action group.  `min-width` is what decides wrapping for a flex item, so the caps are stated as a
   max/min pair rather than a fixed width. */
.client-filter__field { flex: 1 1 180px; min-width: 170px; max-width: 210px; }
.client-filter__field--grow { flex: 3 1 320px; min-width: 300px; }
.client-filter__field--sel { flex: 1 1 220px; min-width: 200px; }
/* Úkoly only: the six-field row needs a smaller HYPOTHETICAL SIZE for its `--grow` field.
   Flexbox decides where a line breaks from each item's hypothetical main size — the flex-basis CLAMPED BY
   min/max-width — and only THEN shrinks what it has placed.  So a row whose bases overflow wraps even
   though its min-widths would have fitted: at basis 320 / min 300 this row's hypothetical sizes came to
   1160 plus 5x12 gap = 1220 against a 1186px card, and the last field dropped to a line of its own.
   Lowering the basis alone is not enough, because the 300px min then becomes the clamp — hence both.
   220 for both fits and leaves room for the grow weights to share; the 3:1 weight is untouched, so that
   field still ends up the widest on the line.
   Scoped to this form: no other bar puts a `--grow` field on a six-field line. */
.comment-search .list-filter-bar__row > .list-filter-bar__field--grow {
  flex-basis: 220px;
  min-width: 220px;
}
/* ---------- Obchodní případ: the two moved boxes ----------
   Pojišťovny and Druhy pojištění moved from the bottom of the left column into the right one.  Nothing to
   declare for the move itself — it is markup — but the right column is 1/3 of the page, so the two grids
   that used to have 2/3 need the scroll container bootstrap 3 only hands out below 767px.  Without it the
   last columns are simply clipped by the card. */
.business-transaction-form .col-md-4 .kv-grid-container { overflow-x: auto; }
/* ---------- "Rozšířené vyhledávání" when it is OPEN ----------
   The toggle carries `.active` while the panel is open, and nothing in the 2026 layer claimed that state,
   so bootstrap's own `.btn-default.active` did — grey on a grey border, plus `.btn.active`'s inset
   box-shadow, which is what read as a second border inside the first.  On top of that `.btn.active:focus`
   RESTORES the UA focus ring that `.btn:focus { outline: none }` had removed, so the button also gained a
   blue halo the moment it was clicked.

   Open is a SELECTED state, so it takes the app's selected look: the mint fill every hovered or selected
   ghost button uses, the brand-green border that says "this is on", and the same green ink the button has
   when it is off.  No shadow.

   `#advanced-search-toggle` is the id modules.js drives on all five index filters, and the (1,1,0) it
   gives beats every one of bootstrap's `.btn-default.active…` rules ((0,2,0)-(0,3,0)) without an
   `!important`.  `:focus-visible` still draws a ring — keyboard users must keep it — but it is the app's
   green one, not the UA blue, and it is not drawn for a mouse click. */
#advanced-search-toggle.active,
#advanced-search-toggle.active:hover,
#advanced-search-toggle.active:focus {
  background-color: var(--brand-mint-bg);
  border-color: var(--brand-green);
  color: var(--brand-green);
  box-shadow: none;
  outline: none;
}
#advanced-search-toggle.active:focus-visible {
  outline: 2px solid var(--brand-green);
  outline-offset: 1px;
}

/* ============================================================================================
   4d. AREAS / notifications
   ============================================================================================ */
/* Notifications-specific field widths.  `max-width` is what keeps the line unwrapped: a flex item sized
   `auto` bases its width on its content, and the Typ select's widest option measured 376px, which pushed
   Obsah onto a second row. */
.notif-filter__field {
  flex: 0 1 auto;
  min-width: 150px;
  max-width: 180px;
}
/* The type select carries the longest prompt ("- Typ notifikace -"); Obsah takes the slack. */
.notif-filter__field:first-child { min-width: 180px; max-width: 220px; }
/* A 160px basis, not the mock's 200px: flex decides wrapping on BASE sizes, and a 200px basis left the
   button pair without room on the line (it wrapped under the fields). */
.notif-filter__field--grow { min-width: 160px; max-width: none; flex: 1 1 160px; }
/* ---------- Status segmented toggle + "mark all as read" ---------- */
.notif-toolbar {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 10px 0;
}
.notif-status { display: inline-flex; }
/* Mint, not solid green — the same "selected but quiet" treatment the active pager segment uses.  Weight
   600 is what carries the state without colour alone. */
.notif-status__segment--active {
  background-color: var(--brand-mint-bg);
  font-weight: 600;
}
/* On the control line with the segments beside it.  `.btn-sm`'s own 4px vertical padding leaves 28px, so
   the height alone would not centre the label: at border-box 34 the two 1px borders and a 18px line box
   leave exactly 7px above and below.  The horizontal padding is left to `.btn-sm`. */
.notif-toolbar__markall {
  margin-left: auto;
  height: var(--size-control-height);
  padding-top: 7px;
  padding-bottom: 7px;
}
/* ---------- List-style table ---------- */
.notif-table {
  table-layout: fixed;
  width: 100%;
}
/* 90px, not the mock's 70px: 70 fits the two 28px buttons but not the "Akce ▾" export dropdown the column
   header keeps (72px + the cell's padding = 88px), which spilled into Datum. */
.notif-col-actions { width: 90px; }
.notif-col-date { width: 110px; white-space: nowrap; color: var(--text-muted); }
.notif-col-entity { width: 320px; }
/* (The orange `.notif-dot` and its `.notif-col-dot` column are gone — the row tint and the bold subject
   are the unread cues.) */
.notif-date__time {
  display: block;
  font-size: 12px;
}
/* One line per field: with table-layout:fixed the cell width is known, so long subjects and
   previews end in an ellipsis instead of growing the row to five lines (the old grid's look).
   Both carry a title attribute, and the row detail has the full text. */
.notif-subject,
.notif-preview {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.notif-subject {
  color: var(--text-body);
  margin-bottom: 2px;
}
.notif-preview {
  color: var(--text-muted);
  font-size: 13px;
}
/* Weight is the second unread cue next to the dot and the tint. */
.notification-unread .notif-subject { font-weight: 600; }
.notification-read .notif-subject { font-weight: 400; }
/* Row tints.  site.css paints these two classes (#f9f9f9 / rgba(101,224,255,.47)) with `!important`, so
   matching it is the only way in; the selectors below are also more specific.  Hover keeps a visible
   response, which a plain `!important` tint would have swallowed. */
.notif-table > tbody > tr.notification-unread { background-color: var(--pastel-sky-light) !important; }
.notif-table > tbody > tr.notification-read { background-color: var(--surface-card) !important; }
.notif-table > tbody > tr.notification-unread:hover { background-color: var(--pastel-sky-light-hover) !important; }
.notif-table > tbody > tr.notification-read:hover { background-color: var(--surface-row-hover) !important; }
/* Only the "no entity" placeholder is notifications-only — the chip itself is the page-independent
   `.entity-chip` in `3b. COMPONENTS / chips`, shared with the Úkoly list. */
.notif-entity--empty { color: var(--text-placeholder); }
/* DELIBERATELY STILL RED — the other `tr.danger` rows in the app, checked one by one so the inactive-row
   list in 3e is a decision and not a sample:
     modules/document/views/required-document/_grid.php   a required document that is MISSING
     modules/finance/views/commission/_grid.php           a commission rate flagged COLOR_DANGER
   Both are "something is wrong here", which is exactly what the ruling reserves red for.  Two more mark
   an inactive record and would take the grey by the same argument, but neither is an entity grid:
   subject/anniversary-hash and console/maintenance. */

/* ---------- The Avíza status segments: 34px is a MINIMUM, not a width ----------
   All three segments were pinned to `width: 34px; padding: 4px 0`, which is right for the two envelope
   glyphs and wrong for "Vše": the word is ~27px at 13px, so it sat in a 32px content box and read as
   clipped.  `min-width` keeps the icon tiles exactly as they were — a 13px glyph plus 2x9px padding plus
   the 2px border is 33, which the 34px floor rounds back up — and lets the text one take the width its
   label needs.
   The `height` puts the group on the control line with the "Označit vše" button; 9px HORIZONTAL is the
   width ruling above and must not be folded into it, and the 7px vertical is what centres a 18px line box
   inside border-box 34 (see `.notif-toolbar__markall`), so the widened "Vše" keeps its proportions. */
.notif-status__segment {
  text-align: center;
  width: auto;
  min-width: 34px;
  height: var(--size-control-height);
  padding: 7px 9px;
}

/* ============================================================================================
   4e. AREAS / commission balance log
   ============================================================================================ */
/* ---------- Grid ----------
   230px is the mock's Akce width; it fits the seven 28px tiles plus the gaps the inline
   whitespace between them already produces, and nowrap keeps them on one line. */
.cbl-col-actions { width: 230px; white-space: nowrap; }
/* "1.10.2025 – 30.10.2025" must not break across two lines. */
.cbl-col-period { white-space: nowrap; }
/* The header period is the secondary of the two, hence the muted ink (mock: #5E6E6A). */
.cbl-col-period--header { color: var(--text-muted); }
/* State chip.  bootstrap's `.label` is 75% font-size with white ink on a saturated fill; this chip is a
   tinted pill with a dark ink of the same hue, so ink and fill are restated here.  Its SIZE is the
   shared `.kv-pill` anatomy in `3f. COMPONENTS` — the same chip serves both pages.
   The base is the NEUTRAL chip, which is what any state outside the three below gets. */
.cbl-state {
  background: var(--surface-disabled);
  color: var(--text-muted);
}
.cbl-state--validate { background: var(--ok-cream); color: var(--panel-warning-text); }
.cbl-state--send { background: var(--pastel-sky-light); color: var(--pastel-sky-text); }
.cbl-state--closed { background: var(--panel-success-bg); color: var(--ok-green); }
/* ---------- Uzávěrka provizí: one toolbar button height ----------
   The record toolbar mixed 36px and 28px, because some of its buttons pass `SIZE_SMALL` and one emits
   `.btn-sm` — a per-call-site choice in the view, not a design decision.  They also sat 4px apart
   vertically, because the two sizes centre on different line boxes.

   Normalised in CSS rather than by editing the widgets: `CommissionBalanceLogRegenerateButton` and
   `LinkButton` are shared, so changing their defaults would move buttons on pages nobody asked about.
   Scoped to this page's toolbar through the wrapper the view already renders.

   36px, NOT the 34px `--control-height`: 36 is what every other record toolbar in the app measures and
   what a plain `.btn` is deliberately kept at.  One value here if all toolbars should move onto the
   token instead. */
.commission-balance-log-view .card-toolbar .btn {
  padding: 7px 14px;
  line-height: 20px;
}

/* ============================================================================================
   4f. AREAS / dashboard
   ============================================================================================ */
/* ---------- Dashboard chart toggles: compact checkboxes ----------
   The Statistiky tab drives its four charts with 19 series toggles.  They were 28x28 — the size restored
   for FORM checkboxes at the client's request — which is oversized next to their 13px year/company
   labels; and because `.checkbox-inline` is missing from the canonical custom-appearance rule (which
   lists only `.checkbox` and `.form-group`) the unchecked ones were plain NATIVE checkboxes stretched to
   28px: square corners, no tint, no border.

   Both are fixed here with the compact grid treatment: 20px, `--radius-sm`, an 11px check.  Scoped to
   `body.body-dashboard` (the controller-id body class, so it holds for every dashboard action) AND to
   `.checkbox-inline`, which on this page means exactly those 19 toggles.

   NOT applied to the "Uživatel - Profil" tab (10 checkboxes in `.checkbox` / `.form-group`): that tab
   renders the shared user-profile form, so shrinking it here would contradict the form-checkbox ruling and
   would make the same form look different from /access/user/profile. */
body.body-dashboard .checkbox-inline input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  width: var(--size-checkbox-grid);
  height: var(--size-checkbox-grid);
  margin: 0;
  cursor: pointer;
  background-color: var(--surface-input);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sm);
  display: inline-grid;
  place-content: center;
  vertical-align: middle;
}
body.body-dashboard .checkbox-inline input[type="checkbox"]:hover { border-color: var(--border-strong); }
/* The white check itself is the shared SVG background; only its size and the box colours are restated, so
   the checked box does not inherit the tint set above. */
body.body-dashboard .checkbox-inline input[type="checkbox"]:checked {
  background-color: var(--ok-green);
  background-size: 11px;
  border-color: var(--ok-green);
}
/* ---------- The dashboard's tab strip, switcher and cards on one pair of edges ----------
   The dashboard's three siblings (the account-switcher `<ul>`, the `.nav-tabs` and krajee's
   `.tab-content`) share ONE inset, because the 10px that only `.tab-content` had was lifted onto their
   common parent `.dashboard-form`; that inset is now deleted rather than moved again, so the block lands
   on the same pair of edges as the record pages while keeping the internal alignment.  The `.tab-content`
   zeroing that used to be paired with it is redundant: `.tabs-x > .tab-content { padding-left: 0;
   padding-right: 0 }` further down states it for EVERY krajee TabsX in the app, and the dashboard's
   `.tab-content` is a direct child of `div.tabs-x`.  The vertical 10px (the gap between the tab strip and
   the first card) is untouched by either. */

/* ---------- The account switcher is white, not field-tinted ----------
   Every form control in the app is filled `--surface-input`.  That works on a white card; this select2 is
   the one control in the app standing directly on the page's tinted background, and #FAFDFB against
   #F4FFFB is a 2-3 point difference per channel — the control effectively disappears.  White is the fix,
   scoped to this one switcher: the field tint stays the rule everywhere else.  (0,4,0) with the
   `.field-dashboard-account_id` wrapper against the base rule's (0,3,0), so it needs no `!important`. */
.dashboard-form .field-dashboard-account_id [class*="select2-container--krajee"] .select2-selection {
  background: var(--surface-card);
}
:is(.checkbox, .form-group, .checkbox-inline) input[type="checkbox"]:checked:disabled,
.checkbox label input[type="checkbox"]:checked:disabled,
label > input[type="checkbox"]:checked:disabled {
  background: var(--brand-mint-bg) url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%235E6E6A' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round' d='M3.5 8.5l3 3 6-7'/%3E%3C/svg%3E") center/70% no-repeat;
  border-color: var(--brand-mint);
}

/* ============================================================================================
   4g. AREAS / home page
   ============================================================================================ */
 /* fa-circle: filled */

/* Search-history chips row (replaces the Historie vyhledávání box) */
.search-history {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-bottom: 36px; padding: 12px 8px 0;
}
.search-history__label { font-size: 13px; color: var(--text-muted); font-weight: 600; }
/* 4/6 vertical, not 5/5: the optical compensation of `.kv-grid__value > .kv-pill`, measured with
   that rule's own reference strings — ink centre 1.284px below the chip's at 5/5, 0.284px at 4/6.
   The height is unchanged.  `.entity-chip` and `.header-groups > .search-chip` restate all four
   insets, so each carries its own split at its own size and neither inherits this one. */
.search-chip {
  display: inline-flex; align-items: center; gap: 8px;
  background: var(--surface-card); border: 1px solid var(--border-strong); border-radius: var(--radius-pill);
  padding: 4px 8px 6px 14px; font-size: 13px; color: var(--ok-green);
  transition: border-color 120ms, box-shadow 120ms;
}
.search-chip:hover { border-color: var(--ok-green); box-shadow: var(--shadow-box); }
.search-chip > a { color: var(--ok-green); text-decoration: none; }
.search-chip__remove {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--surface-tint); color: var(--ok-green);
  font-size: 11px; line-height: 1; text-decoration: none;
}
.search-chip__remove:hover { background: var(--ok-blush); color: var(--status-danger-text); }
.search-history__clear { font-size: 13px; color: var(--status-danger-text); margin-left: 4px; }
.search-history__clear:hover { color: #8C1D16; }
/* Favorites grid: text stacks instead of nested bordered boxes */
.fav-stack { display: flex; flex-direction: column; gap: 1px; }
.fav-stack__title { font-weight: 600; }
.fav-stack__meta { font-size: 12px; color: var(--text-muted); }
/* Result-box count badge (post-search state) */
.box-title .badge-count { background: var(--surface-tint); color: var(--ok-green); }
/* 3/5 vertical, not 4/4: the optical compensation of `.kv-grid__value > .kv-pill`, measured with
   that rule's own reference strings — ink centre 1.369px below the chip's at 4/4, 0.369px at 3/5.
   The 28px height is unchanged.  (Re-measured after the h1 heading rule started resolving to Inter:
   these chips inherit the h1's family, so the Helvetica figures this comment used to carry — 1.088
   and 0.088 — no longer describe anything on screen.  3/5 is still the best INTEGER split, because
   the next step down, 2/6, overshoots to −0.631; only a half-pixel 2.5/5.5 would beat it, at −0.131,
   and that would be the chip family's only fractional inset.) */
.content-header > h1 > .header-groups > .search-chip {
  padding: 3px 8px 5px 12px;
  font-size: 13px;
  gap: 4px;
}
.content-header > h1 > .header-groups > .search-chip > .fa-tag {
  color: var(--ok-mint);
  margin-right: 2px;
}
/* ---------- The home page's SEARCH-RESULTS state ----------
   Client ruling: the DEFAULT state is right as it stands and does not change — only the answer state does.
   The markup half is in views/site/_search.php: the Oblíbené card is not rendered while the search has
   rows, and the results column widens to the full row.  Deliberately left alone there: one white `.box`
   per result TYPE, the green `.box-title`, the count badge, the row action tiles and every link's target.

   Everything below is scoped to `.site-search__results`, the results column's own class, so the Oblíbené
   card in the default state is untouched.

   Result-row links go brand green: the app's grid link colour is the CTA orange, which on this page
   competes with the row's own action tiles for the eye — the results are a list to READ, not a set of
   calls to action.  Buttons keep their own paint. */
.site-search__results .box-body table a:not(.btn) { color: var(--brand-green); }
.site-search__results .box-body table a:not(.btn):hover,
.site-search__results .box-body table a:not(.btn):focus { color: var(--brand-green-dark); }
/* The header rule drops from 2px to the same hairline the rows use.  It is the last piece of table chrome
   heavy enough to read as a data grid rather than a compact result list — the striping and the cell
   borders were already gone, so this one value is the whole difference. */
.site-search__results .kv-grid-table > thead > tr > th { border-bottom-width: 1px; }
/* Two columns, boxes FLOWING into them (approved look: .superpowers/sdd/figma-live/figma-uvod-2col.png).
   The mock's arrangement is a flow, not a pair-per-row: its two short left boxes and one taller right box
   overlap vertically, which `col-md-6` pairs cannot produce — a float row is as tall as its tallest member
   and the next box starts below both.  `column-count` gives exactly that behaviour and needs no markup
   change, so the `li.site-search[data-save-url]` wrapper web/js/modules.js walks up to when it records a
   search-history entry stays where it is.
   The `li`s are bootstrap grid cells; inside a multicol container their float and gutter would break the
   flow, hence the reset.  `break-inside: avoid` keeps a box whole — without it a long grid would be sliced
   across the column boundary.  The vertical rhythm is the box's own margin, so only the horizontal gap is
   declared. */
.site-search__results > ul.row {
  column-count: 2;
  column-gap: var(--spacing-box-gap);
  margin: 0;
}
.site-search__results > ul.row > li {
  float: none;
  width: 100%;
  padding: 0;
  break-inside: avoid;
}
/* Half the width means three of the six result grids no longer fit.  kartik already wraps every grid in
   `.kv-grid-container.table-responsive`, but bootstrap 3 only gives `.table-responsive` its overflow
   inside a `max-width: 767px` media query — on the desktop the overflow is CLIPPED by the card and the
   last columns are simply lost.  Turning the wrapper into a real scroll container keeps the data
   reachable; the scroll is inside the card and the page itself still does not scroll horizontally. */
.site-search__results .kv-grid-container { overflow-x: auto; }
/* ---------- The home page's default state ----------
   Approved look: .superpowers/sdd/figma-live/figma-uvod-final-default.png.  Two changes, both a re-layout
   of markup that already existed: the search history moves from a bare row into the same white card as
   everything else on the page (label as a muted uppercase caption on its own line), and the single wide
   "Oblíbené" grid becomes THREE small per-entity cards side by side.

   The chip, its ✕ and "Vymazat vše" keep every rule they had — `.search-chip*` and
   `.search-history__clear` are declared just above and are not restated, which is why the modifier is on
   `.search-history` and not a new class.  Same for the star: it is still `FavoriteButton`, still
   `.favorite`, still the same AJAX round trip; only the tile it used to be drawn as is gone.

   The history card: `.search-history` carries a bottom margin and an asymmetric inset that were the
   spacing of a bare row standing on the page background.  Inside a `.box-body` the card already provides
   the inset and the `.box` its rhythm, so the modifier zeroes them rather than fighting them. */
.search-history--card { display: block; margin-bottom: 0; padding: 0; }
.search-history--card .search-history__label {
  display: block;
  margin-bottom: 10px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.search-history__chips { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; }
/* The three favourite boxes.  `.fav-box` is a plain card with a header that carries NO hairline — at this
   size the title and the first row are close enough that a divider reads as a table header, which is
   exactly the "grid" impression this undoes.  The rows are quiet: no borders, no zebra, one hover tint.
   Equal heights: the mock's three cards share a bottom edge, which a bootstrap float row cannot do (each
   column is as tall as its own content).  Flexing the row — and the columns, so the card inside can
   stretch — is the whole fix; the columns keep their `col-md-4` width and their gutters. */
.fav-boxes { display: flex; flex-wrap: wrap; }
.fav-boxes > [class*="col-"] { display: flex; }
.fav-boxes > [class*="col-"] > .fav-box { flex: 1 1 auto; }
.fav-box > .box-header { padding-bottom: 4px; }
.fav-box > .box-body { padding-top: 4px; }
.fav-list { list-style: none; margin: 0; padding: 0; }
.fav-row {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 6px 4px;
  border-radius: var(--radius-sm);
  font-size: 13px;
}
.fav-row:hover { background: var(--surface-tint); }
/* The star.  FavoriteButton always appends `btn-warning btn-star` (it is only ever rendered in the
   favourited state here), and bootstrap's `.btn-warning` (0,1,0) would put its amber FILL behind the
   glyph — there is no `.btn` on the element, so nothing else from the button vocabulary applies.
   `.fav-list` in front of the class is (0,2,0) and settles it without an `!important`. */
.fav-list .fav-row__star {
  flex: none;
  background: none;
  border: 0;
  padding: 0;
  color: var(--brand-gold);
  font-size: 13px;
  line-height: 1;
  text-decoration: none;
}
.fav-list .fav-row__star:hover, .fav-list .fav-row__star:focus {
  color: var(--brand-gold-dark);
  text-decoration: none;
}
/* Both halves of a row are one line and ellipsised, never wrapped: the card is a third of a row wide
   and the meta now carries the client name plus the whole contract identity, which does not fit.  A
   wrap would make the three cards different heights and turn the list back into a block of text.
   `min-width: 0` is what lets a flex item shrink below its content at all — without it the ellipsis
   never engages and the row overflows the card instead.  The full string is in `title` on both. */
.fav-row__link, .fav-row__meta {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.fav-row__link { color: var(--brand-green); font-weight: 600; }
.fav-row__link:hover, .fav-row__link:focus { color: var(--brand-green-dark); text-decoration: underline; }
/* The separator is drawn, not stored: the view hands over the record's remaining description
   lines and the middot belongs to the layout.

   `flex: 1 1 0` is what keeps the TITLE intact: a zero flex basis carries no shrink weight, so the
   meta absorbs the whole overflow — it takes the row's leftover width by growing into it and gives it
   back by ellipsising.  With the default `auto` basis both halves shrink in proportion and a 9-digit
   contract number loses its last digits while the meta beside it still has 200px of text. */
.fav-row__meta { flex: 1 1 0; color: var(--text-muted); font-size: 12px; }
.fav-row__meta::before { content: "·"; margin-right: 6px; }
.fav-list__empty { margin: 0; padding: 6px 4px; color: var(--text-muted); font-size: 13px; }
/* ---------- The central search can show a selection again ----------
   One selection is declared for the whole app: `::selection { background: var(--ok-mint); color:
   var(--ok-green) }`.  The navbar search input's own FILL is `--ok-mint`, so selecting text there paints
   mint on mint and the only thing that moves is the ink — effectively invisible.

   SCOPED, NOT GLOBAL — the global was considered and measured, and it is not safe.  A brand-green fill
   with white ink is the obvious high-contrast answer on a light page, but the app has real DARK surfaces:
   `.main-header` and its `.navbar` are `--ok-green` flat, and the sidebar's `treeview-menu` is a 7% green
   over white.  Selecting the wordmark or a navbar label would then paint green on green — the same bug
   moved somewhere else.  The mint/green pair is right for the ~99% of the app that is white or near-white;
   only the one mint control is wrong, so only the one mint control is restated.
   `.main-header` keeps the rule off the home page's own search box (same `.search-history-form` class,
   white fill, where the global mint reads fine).  (0,2,0) + a pseudo-element against the global's (0,0,0),
   so no `!important`. */
.main-header .search-history-form .form-control::selection {
  background: var(--brand-green);
  color: var(--text-inverse);
}

/* ============================================================================================
   4h. AREAS / profile and access
   ============================================================================================ */
.user-update-profile .box-body > div > .row:last-child > div > .form-group:last-child { margin-bottom: 0; }
/* Profile (/access/user/profile): the vertical rhythm was gone — every label sat flush against the field
   above it.  ROOT CAUSE: adminlte.css:139 ends a long legacy selector list with
   `.box-body > div > .row:last-child > div > .form-group { margin-bottom: 0 }`, whose intent was "don't
   leave a trailing gap under the last row of a box body".  The profile form is a SINGLE row, so that row
   is also the last one and the rule zeroed the margin of EVERY form-group in it.  (The right-hand checkbox
   column is nested one `.row` deeper, which is why only two of the three columns looked broken.)
   Restored scoped to the profile page, keeping the original intent by zeroing only the genuinely last
   group in each column.  The legacy selector is (0,4,2); prefixing it with `.user-update-profile` makes
   ours (0,5,2), so it wins on specificity, not load order.  It restates the base step, so it has to track
   the base step. */
.user-update-profile .box-body > div > .row:last-child > div > .form-group { margin-bottom: 10px; }
/* …and the checkbox column reads as one list rather than five separate fields: a tighter, even step. */
.user-update-profile .form-group:has(> .checkbox) { margin-bottom: 6px; }
/* ============================================================================================
   4h. AREAS / profile, access and the login page
   ============================================================================================ */

/* ---------- The login page's "O" ----------
   `views/layouts/content-login.php` renders `<section class="login-logo"><img
   src="/images/znacka_bila.svg"></section>` and skin.css caps it at `max-width: 25vw`.  That used to
   produce the giant white O; after the logo became an SVG it rendered 0x0.

   ROOT CAUSE: `web/images/znacka_bila.svg` carries a `viewBox` and NO `width`/`height` attributes, i.e. it
   has an intrinsic RATIO but no intrinsic SIZE.  `.body-guest .content-wrapper` is `display: flex`
   (skin.css), so `.login-logo` is a flex item whose `flex-basis: auto` resolves against its content — and
   a replaced child with no intrinsic size contributes 0.  The section collapses to 0 and takes the image
   with it; neither cap is involved, and stating any size at all brings it back.

   So the fix is to state the size the SVG no longer carries.  `25vw` is not a new number: it is exactly
   what skin.css's cap already resolved to before, which is why the O comes back at the reference size
   rather than at a size of my choosing.  The cap stays where it is and is now a no-op; `height: auto`
   keeps the viewBox ratio.  `flex-shrink: 0` protects the decoration from a narrow viewport; below 768px
   `.hidden-xs` on the section removes it, as it always has. */
.body-guest .login-logo { flex-shrink: 0; }
.body-guest .login-logo img { width: 25vw; height: auto; }
/* ---------- The profile's switch column joins the form's rhythm ----------
   /access/user/profile lays out three `col-md-4` columns: two of ordinary fields and one of five
   checkboxes.  A FIELD row is 55px — an 18px label, a 3px gap and the 34px control — plus a 10px margin,
   so the left two columns step by 65.  A CHECKBOX row is only its label box, 34px for one line of text and
   36px for two, so the third column stepped by 45-47 and drifted further from the fields with every row.

   Two changes, one in the markup and one here.  MARKUP: the column used to wrap its five fields in a
   nested `.row > .col-md-12`, which contributed nothing — one full-width child — while its 15px gutter
   pulled the checkboxes left of the column edge the browser had already given them.  Gone, which is also
   what makes the selector below a plain child combinator.

   CSS: 55px is the field row's box, so the two `:nth-child`s of any row now agree and the 10px margin
   already on the group supplies the same 65px step.  `padding-top: 18px` is the label line the switches do
   not have — it puts the box on the CONTROL line of the row beside it instead of on its label line.  18 and
   not the full 21 (label + gap) on purpose: two of the five labels wrap to two lines (36.4px), and
   18 + 36.4 = 54.4 still fits inside the 55px box, so a wrapping label cannot push its row out of the
   rhythm.  The 3px the one-line rows need is supplied by the box's own centring inside the label.

   Scoped to the class the view carries: this geometry is "a column of switches beside a column of fields",
   and the profile is the only page in the app that has one. */
.user-profile-switches > .form-group {
  min-height: 55px;
  padding-top: 18px;
}
/* "Úprava profilu" leads the read-only profile: the button moved from after the last field to before the
   first one (the ruling: it was easy to miss at the bottom) and is now the orange CTA.  Standing directly
   on the field grid it needs the gap a form row would have given it, so it takes the `.form-group` bottom
   margin every row above it uses instead of introducing a second rhythm. */
.user-profile-edit-cta { margin-bottom: 10px; }

/* ============================================================================================
   4i. AREAS / vendor surfaces
   ============================================================================================ */
/* U7) Kartik tabs-x (dashboard overview) — align with the 4h quiet-tab design;
   tabs-x ships its own boxed styling at higher specificity. */
.tabs-krajee .nav-tabs { background: transparent; border-bottom: 1px solid var(--border-default); }
.tabs-krajee .nav-tabs > li > a,
.tabs-krajee.tabs-above .nav-tabs > li > a {
  border: none !important;
  border-bottom: 3px solid transparent !important;
  border-radius: 0 !important;
  background: transparent !important;
  box-shadow: none !important;
  color: var(--text-muted);
  padding: 10px 2px;
}
.tabs-krajee .nav-tabs > li.active > a,
.tabs-krajee .nav-tabs > li.active > a:hover,
.tabs-krajee .nav-tabs > li.active > a:focus,
.tabs-krajee.tabs-above .nav-tabs > li.active > a {
  border-bottom-color: var(--ok-gold) !important;
  color: var(--ok-green);
  font-weight: 600;
}
.tabs-krajee > .tab-content { background: transparent; box-shadow: none; border: none; }
/* ---------- CKEditor 4 chrome ----------
   The editor was still stock moono-lisa (#d1d1d1 / #bcbcbc borders, #f8f8f8 toolbar and footer bands,
   #e5e5e5 button states, square corners) next to our flat mint fields.  The widget is used in ~12 places,
   so this is a global restyle of the CHROME only.

   LOAD ORDER: CKEditor injects its own skin stylesheets from JS, so `assets/<hash>/skins/moono-lisa/
   editor.css` always lands at the END of <head> — after this file.  Any override of ours that merely tied
   on specificity would therefore lose, exactly like the select2-in-a-dialog case, so the same `:root `
   prefix is used here: it adds one class level and matches precisely what the unprefixed selector matched.

   The editable text area itself is an <iframe>; its background and typography come from CKEditor's
   contents.css INSIDE that document and are unreachable from here — which is also why `.cke_inner` is
   white rather than the fields' tint.
   Focus: CKEditor adds `cke_focus` to the chrome, so the focus ring needs no JS; `:focus-within` is kept
   as a fallback for non-iframe (inline/divarea) instances. */
:root .cke_chrome { border: 1px solid var(--border-default); border-radius: var(--radius-control); box-shadow: none; }
:root .cke_inner { background: var(--surface-card); border-radius: var(--radius-control); }
:root .cke_top {
  background: var(--surface-card);
  border-bottom: 1px solid var(--border-default);
  border-radius: var(--radius-control) var(--radius-control) 0 0;
  padding: 5px 8px 3px;
}
:root .cke_bottom {
  background: var(--surface-card);
  border-top: 1px solid var(--border-default);
  border-radius: 0 0 var(--radius-control) var(--radius-control);
}
:root a.cke_button { border-radius: var(--radius-sm); }
/* Stock swaps border+padding on hover/active, which makes the toolbar jitter — keep the
   geometry fixed and change only the fill. */
:root a.cke_button_off:hover, :root a.cke_button_off:focus { background: var(--surface-tint); border: 0; padding: 4px 6px; }
:root a.cke_button_off:active, :root a.cke_button_on { background: var(--brand-mint-bg); border: 0; padding: 4px 6px; }
:root .cke_button_label { color: var(--text-muted); }
:root .cke_button_arrow { border-top-color: var(--ok-green); }
:root .cke_toolgroup a.cke_button:last-child:after,
:root .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after,
:root .cke_combo:after { border-right-color: var(--border-default); }
:root .cke_toolbar_separator { background: var(--border-default); }
:root a.cke_combo_button { border-radius: var(--radius-sm); border-color: var(--border-default); }
:root .cke_combo_on a.cke_combo_button, :root .cke_combo_off a.cke_combo_button:hover,
:root .cke_combo_off a.cke_combo_button:focus, :root .cke_combo_off a.cke_combo_button:active {
  background: var(--surface-tint);
  border: 1px solid var(--border-strong);
}
:root .cke_combo_text { color: var(--ok-green); }
:root .cke_combo_arrow { border-top-color: var(--ok-green); }
/* Toolbar dropdown panels are appended to <body>, same as the select2 dropdown. */
:root .cke_panel { border: 1px solid var(--border-default); border-radius: var(--radius-control); box-shadow: var(--shadow-dropdown); }
:root .cke_panel_grouptitle { background: var(--surface-tint); border-bottom: 1px solid var(--border-default); color: var(--ok-green); }
:root .cke_panel_listItem.cke_selected a, :root .cke_panel_listItem a:hover,
:root .cke_panel_listItem a:focus, :root .cke_panel_listItem a:active { background-color: var(--brand-mint-bg); }
:root .cke_path_item, :root .cke_path_empty { color: var(--text-muted); }
:root .cke_resizer { border-color: transparent var(--border-strong) transparent transparent; }
:root .cke_chrome.cke_focus, :root .cke_chrome:focus-within {
  border-color: var(--ok-green);
  box-shadow: var(--ring-focus);
}
/* ---------- The record page's header rows sit on the cards' edges ----------
   The contract page had four different left edges and three different right ones: `.content`'s own 24px
   inset (where the gold title bar, the toolbar, the tab strip and the tab wrapper `.box` all start), 10px
   further in where the CARDS started, and further still where the first toolbar BUTTON started.  Client
   update (no tabs) was already on `.content`'s edges for its cards, which is what every non-tabbed page in
   the app uses — so the CARDS move OUT to the app's edge rather than the header rows moving in.

   THE CARDS: krajee's TabsX gives `.tab-content` a flat `padding: 10px`, so everything inside the active
   tab pane is inset 10px from the tab strip above it and from the wrapper box's edges.  Only the two
   HORIZONTAL sides are zeroed: the TOP 10px is the gap between the tab strip and the first card and has to
   stay.  `.tabs-x` is used in exactly two places (the contract form and the dashboard form), and the
   dashboard's own copy of this declaration is in its section above, so this changes the contract page. */
.tabs-x > .tab-content {
  padding-left: 0;
  padding-right: 0;
}
/* ---------- /admin/role/view — the two things the user asked for, and nothing else ----------
   This is a VENDOR page (mdmsoft/yii2-admin).  The user's own scope: "you can fix just the blue colour and
   height of the box underneath it".  Everything else on it — the vendor toolbar, the table skin, the
   >> / << buttons — is deliberately left as found.

   a) THE ASSIGNED-USER BADGES.  The vendor's `_script.js` builds each one as
      `<span class="label label-info"><a>`, i.e. bootstrap's cyan #00C0EF with a white label colour that the
      app's orange link colour then overrides INSIDE it — a cyan pill with orange text, the only two colours
      on the page that are in no palette.  Retinted to the app's quiet chip, with the anchor made to inherit
      so the badge has ONE colour.  Scoped to `.auth-item-view`, the vendor view's own wrapper, so the app's
      other `.label-info` is untouched.

   b) THE DUAL-LIST BOXES.  Both are `select.form-control.list[multiple][size=20]` and both rendered 34px
      tall — one row of a 306-option list, with the second row clipped mid-glyph.  Cause: bootstrap's
      `select[multiple], select[size] { height: auto }` (0,1,1) is overridden by
      `.form-control, select.form-control { height: var(--control-height) }`, which is later and equally
      specific.  `height: auto` hands the box back to its `size` attribute; `max-height` caps the 20-row
      result at a sane picker height and lets the list scroll.  Scoped to the same wrapper: a native
      multi-select elsewhere in the app has the identical defect, but the ruling names this page only. */
.auth-item-view .label.label-info {
  /* `!important` twice, and only because AdminLTE.min.css spends one first:
     `.bg-aqua, …, .label-info { background-color: #00C0EF !important }`. Nothing else on this page
     needs one. */
  background-color: var(--brand-mint-bg) !important;
  color: var(--brand-green) !important;
}
.auth-item-view .label.label-info > a,
.auth-item-view .label.label-info > a:hover,
.auth-item-view .label.label-info > a:focus {
  color: inherit !important;
  text-decoration: none;
}
.auth-item-view select.form-control[multiple] {
  height: auto;
  max-height: 320px;
}
