/* ═══════════════════════════════════════════════════════════════════════════
   AllurePOS Kasir: "The Check" (navy + brass from icons/logo.png)
   Loaded by index.html only, as the last element of <head>. admin.html and
   dapur.html do not load it.

   Contract (design spec sections 2, 3 and 9):
   - New tokens use the --k- prefix on :root. Legacy tokens (--blue, --text,
     --bg2 ...) are NEVER redefined on :root: they are remapped only inside
     the non-fiscal wrappers of the bridge below, so #fiscal-modal and
     #esir-info-modal keep today's values.
   - Fonts are set on wrappers only, never on body or html.
   - Everything visual lives inside @media screen, so print (the frozen @page
     and receipt rules in index.html) is untouched.
   - Every !important lives in the one LEGACY OVERRIDES block, except the
     reduced-motion block and the #k-more lock-hide rule.
   - New classes use the k- prefix. Never create .hidden, .active, .disabled
     or .show: JS uses those as state.

   Order: 1 @font-face, 2 tokens, 3 keyframes, 4 @media screen (bridge,
   legacy overrides, base, components, surfaces, responsive, PDA),
   5 reduced motion.
   ═══════════════════════════════════════════════════════════════════════════ */


/* ── 1. Fonts ────────────────────────────────────────────────────────────────
   Fira Sans 400/600/700 and Fira Sans Condensed 600 (SIL OFL 1.1, see
   fonts/fira/OFL.txt). Bundled woff2 subsets latin, latin-ext and cyrillic
   from @fontsource/fira-sans and @fontsource/fira-sans-condensed 5.3.0; the
   unicode-range values are copied from the package CSS. No runtime CDN.
   Font-feature gate: 'tnum' is present in the latin and latin-ext files (the
   cyrillic files carry no digits, the latin file serves them). 'zero' is not
   in these subsets, so font-feature-settings: "zero" is a harmless no-op. */
@font-face {
  font-family: "Fira Sans";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/fira/fira-sans-cyrillic-400-normal.woff2") format("woff2");
  unicode-range: U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116;
}
@font-face {
  font-family: "Fira Sans";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/fira/fira-sans-latin-ext-400-normal.woff2") format("woff2");
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face {
  font-family: "Fira Sans";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/fira/fira-sans-latin-400-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
  font-family: "Fira Sans";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("fonts/fira/fira-sans-cyrillic-600-normal.woff2") format("woff2");
  unicode-range: U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116;
}
@font-face {
  font-family: "Fira Sans";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("fonts/fira/fira-sans-latin-ext-600-normal.woff2") format("woff2");
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face {
  font-family: "Fira Sans";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("fonts/fira/fira-sans-latin-600-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
  font-family: "Fira Sans";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("fonts/fira/fira-sans-cyrillic-700-normal.woff2") format("woff2");
  unicode-range: U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116;
}
@font-face {
  font-family: "Fira Sans";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("fonts/fira/fira-sans-latin-ext-700-normal.woff2") format("woff2");
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face {
  font-family: "Fira Sans";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("fonts/fira/fira-sans-latin-700-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
  font-family: "Fira Sans Condensed";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("fonts/fira/fira-sans-condensed-cyrillic-600-normal.woff2") format("woff2");
  unicode-range: U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116;
}
@font-face {
  font-family: "Fira Sans Condensed";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("fonts/fira/fira-sans-condensed-latin-ext-600-normal.woff2") format("woff2");
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face {
  font-family: "Fira Sans Condensed";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("fonts/fira/fira-sans-condensed-latin-600-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}


/* ── 2. Tokens ───────────────────────────────────────────────────────────── */
:root {
  /* 2.1 Core palette (navy and brass sampled from icons/logo.png) */
  --k-navy: #0B2146;            /* ink, the check slab, primary fills, occupied tables */
  --k-navy-raised: #16336A;     /* tier-2 pay keys, hover/pressed of navy fills */
  --k-navy-hover: #1F3F7A;      /* hover of tier-2 keys on the slab */
  --k-brass: #C9973B;           /* ONE brass element per screen, fill only, navy text */
  --k-brass-hover: #D4A54B;
  --k-brass-press: #B28135;
  --k-paper: #F4F6F9;           /* page, main area, floor */
  --k-surface: #FFFFFF;         /* header, order column, keys, modals */
  --k-sunken: #EDF0F5;          /* tracks, table headers, stepper keys, disabled */
  --k-sunken-press: #DDE3EC;
  --k-slate: #46526E;           /* secondary text */
  --k-ink-3: #5C6882;           /* muted text, placeholders */
  --k-line: #D6DCE5;            /* decorative dividers only */
  --k-line-strong: #7B879C;     /* borders that carry meaning (3:1+) */
  --k-slab-ink-2: #AFBBD3;      /* secondary text on navy */
  --k-slab-edge: #6A7FAF;       /* 1px edge of tier-2 keys on the slab */
  --k-focus: #1F5FD0;           /* focus ring on light surfaces */
  --k-focus-on-slab: #E6B85C;   /* focus ring inside the navy slab */

  /* 2.2 State colours */
  --k-ok: #1B7A46;
  --k-ok-ink: #17613A;
  --k-ok-tint: #E7F4EC;
  --k-warn-fill: #F4C04F;
  --k-warn-ink: #6B4600;
  --k-warn-tint: #FFF1CF;
  --k-warn-line: #B07A08;
  --k-warn-hover: #FDE6A8;      /* hover/pressed of the warn button */
  --k-danger: #B3261E;
  --k-danger-ink: #8C1D16;
  --k-danger-tint: #FCEBEA;
  --k-info: #1A4FA8;
  --k-info-tint: #E8F0FC;

  /* Role tokens (design system: ink, on-*, control/selected/sheet edges). In Navy & Emas they resolve
     to the kasir's own values; the themes below move them apart, so text never has to be navy. */
  --k-ink: var(--k-navy);
  --k-on-navy: var(--k-surface);
  --k-on-brass: var(--k-navy);
  --k-on-warn-fill: var(--k-navy);
  --k-on-danger: var(--k-surface);
  --k-control-edge: transparent;
  --k-selected-edge: transparent;
  --k-sheet-edge: transparent;

  /* 2.3 Overlay and elevation */
  --k-scrim: rgba(11, 33, 70, .48);          /* non-fiscal modals only */
  --k-e1: 0 1px 2px rgba(11, 33, 70, .10);   /* occupied tables, the check */
  --k-e2: 0 6px 16px rgba(11, 33, 70, .14);  /* Više popover, fiscal-fields sheet */
  --k-e3: 0 24px 48px rgba(11, 33, 70, .28); /* modals */

  /* 3. Typography: six steps, nothing under 13px; weights 400/600/700 only */
  --k-font: "Fira Sans", "Segoe UI Variable Text", "Segoe UI", Roboto, system-ui, sans-serif;
  --k-font-tight: "Fira Sans Condensed", "Bahnschrift SemiCondensed", "Segoe UI", Roboto, sans-serif;
  --k-t-meta: 13px;  --k-lh-meta: 1.3;
  --k-t-sm: 15px;    --k-lh-sm: 1.25;
  --k-t-md: 17px;    --k-lh-md: 1.25;
  --k-t-lg: 21px;    --k-lh-lg: 1.2;
  --k-t-xl: 28px;    --k-lh-xl: 1.1;
  --k-t-2xl: 36px;   --k-lh-2xl: 1.1;

  /* 4. Spacing (4px grid) */
  --k-1: 4px;
  --k-2: 8px;
  --k-3: 12px;
  --k-4: 16px;
  --k-5: 24px;
  --k-6: 32px;

  /* 4. Sizes */
  --k-hit: 44px;                 /* minimum real hit box */
  --k-h-key2: 48px;              /* tier-2 pay keys, modal fields, search */
  --k-h-key: 56px;               /* tier-1 pay keys, modal primary/money, cash input */
  --k-h-head: 52px;              /* header */
  --k-h-tabs: 48px;              /* view tabs (the PDA cart offset reads this) */
  --k-cart: clamp(360px, 29vw, 440px);

  /* 4. Radius: three steps tied to hierarchy, plus round for status */
  --k-r-control: 6px;
  --k-r-card: 10px;
  --k-r-sheet: 14px;
  --k-r-round: 999px;

  /* 4. Z-index ladder (values JS or frozen code owns are kept) */
  --k-z-canvas: 1;
  --k-z-pda: 100;
  --k-z-banner: 500;
  --k-z-lock: 9999;
  --k-z-modal: 10000;            /* .modal-overlay, frozen */
  --k-z-toast: 10050;            /* S8.1 toasts */
  --k-z-lpfr: 10060;             /* L-PFR banner above payment modals */
  --k-z-lsm: 100002;
  --k-z-top: 999999;             /* terminal selector, SaaS lock, message box */

  /* 4. Motion: only in answer to an action */
  --k-dur-fast: 120ms;
  --k-dur: 180ms;
  --k-ease: cubic-bezier(.2, .7, .2, 1);
}


/* ── 3. Keyframes ────────────────────────────────────────────────────────────
   The one global `pulse` is an opacity-only fade. JS still names it for the
   pending badge ('pulse 1s infinite alternate'), so it must stay `pulse`.
   The SaaS lock's red glow (renamed k-saas-pulse) has no user since S6 and
   is gone from index.html, with the unused fadeIn beside it. */
@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: .55; }
}
@keyframes k-spin {
  to { transform: rotate(360deg); }
}
/* Indeterminate progress bar: sized for an inner bar 25% of its track. */
@keyframes k-indeterminate {
  from { transform: translateX(-100%); }
  to { transform: translateX(400%); }
}

/* The Više popover fades in when it opens (motion answers the tap). */
@keyframes k-fade-in {
  from { opacity: 0; }
}

/* A refused PIN shakes the dots of the lock screen (6.15a). Reduced motion stops it with every other animation (5.). */
@keyframes k-pin-shake {
  0%, 100% { transform: translateX(0); }
  20%, 60% { transform: translateX(-8px); }
  40%, 80% { transform: translateX(8px); }
}


/* ── 4. Screen ───────────────────────────────────────────────────────────── */
@media screen {

  /* 4.1 Legacy token bridge (spec 2.4). Scoped to the non-fiscal wrappers,
     never :root. Frozen JS writes var(--blue), var(--gold), var(--green),
     var(--red), var(--bg3), var(--text3) into inline styles, and allure's
     !important rules read var(--bg2), var(--nav), var(--border): remapping
     them here makes all of those AA with zero JS edits. #fiscal-modal and
     #esir-info-modal are <body> children outside .pos-layout and are
     excluded from the overlay selector, so they keep today's values.
     .k-msg is the App.message box (void confirm, alerts), also a <body>
     child: without it allure-theme.css paints its title with the light
     theme's --fg, which is unreadable in Malam. */
  .pos-header, .pos-layout,
  .modal-overlay:not(#fiscal-modal):not(#esir-info-modal),
  #staff-lock-screen, #training-mode-banner, #lsm-modal-pos,
  #saas-expired-lockscreen, #terminal-selector-overlay, .k-msg {
    --blue: var(--k-navy);   --orange: var(--k-navy); --accent: var(--k-navy);
    --lblue: var(--k-navy-raised);
    --text: var(--k-ink);    --fg: var(--k-ink);
    --text2: var(--k-slate); --text3: var(--k-ink-3);
    --bg: var(--k-paper);    --bg2: var(--k-surface); --nav: var(--k-surface);
    --card: var(--k-surface); --surface: var(--k-surface);
    --bg3: var(--k-sunken);  --bg4: var(--k-sunken-press);
    --border: var(--k-line);
    --green: var(--k-ok);    --red: var(--k-danger);  --teal: var(--k-info);
    --gold: var(--k-warn-ink);            /* text use: history status, pending rows */
  }
  .pos-header { --gold: var(--k-warn-fill); } /* fill use: training ON = var(--gold) + #000 text (JS) */
  #training-mode-toggle-btn, #pda-mode-btn { --bg3: transparent; } /* JS "off" state = var(--bg3) */


  /* ══ 4.2 LEGACY OVERRIDES ═══════════════════════════════════════════════
     The ONLY place in this file with !important (target: 30 or fewer).
     Each rule beats a legacy !important rule in allure-theme.css,
     design-system.css or the inline <style> of index.html, which stay
     unedited. Name the rule it beats next to each entry.
     ════════════════════════════════════════════════════════════════════ */

  /* Page: cool paper instead of cream + dot grid.
     Beats allure-theme.css `body { background-color: #f5efe4 !important;
     background-image: radial-gradient(...) !important }`. Screen only; the
     body rule in index.html is not migrated. */
  html body {
    background: var(--k-paper) !important;
    background-image: none !important;
  }

  /* Header: one 52px row at every width (spec 7 #35).
     Beats the inline <style> `@media (max-width: 768px) { .pos-header {
     height: auto !important; padding: 10px !important } }`. */
  .k-bar {
    height: var(--k-h-head) !important;
    padding: 0 var(--k-3) !important;
  }

  /* L-PFR status pill. JS rewrites its className every 8 s ('badge
     badge-green ml-auto' or 'badge badge-red ml-auto'), so it is styled by
     id; the colours come from --k-pill-bg / --k-pill-fg, set per state in
     4.5. Beats allure-theme.css `.badge-green` / `.badge-red`
     { background; color } !important. */
  .k-bar #lpfr-status-badge {
    background: var(--k-pill-bg) !important;
    color: var(--k-pill-fg) !important;
  }

  /* L-PFR guard banner (D4; js/lpfr-alert.js stays frozen). Above the
     payment modals (z 10000), so "NE IZDAVATI racune" stays readable over an
     open cash sheet; kasir face, left-aligned, room for the warning glyph
     (::before in 4.5). Beats the banner's inline cssText (z-index:9998;
     font:600 14px/1.4 system-ui; text-align:center; padding:10px 16px). Its
     tested colours (red, orange and blue with white text, already AA) are
     not touched. JS measures the rendered height for body padding-top. */
  #lpfr-alert-banner {
    z-index: var(--k-z-lpfr) !important;
    font: 600 var(--k-t-sm)/1.4 var(--k-font) !important;
    text-align: left !important;
    padding: 10px var(--k-4) 10px 48px !important;
  }

  /* Pay keys on the check keep their own colours while .disabled (they dim
     to opacity .45 instead, see 6.2), so the brass Gotovina key still reads
     as brass on an empty bill. Colours come from --k-pay-bg / --k-pay-fg,
     set per key. Beats the inline <style> `.pay-btn.disabled { background:
     var(--bg3) !important; color: var(--text3) !important }`. */
  .k-check .pay-btn.disabled {
    background: var(--k-pay-bg) !important;
    color: var(--k-pay-fg) !important;
  }

  /* The header Odjava is the one logout: hide the small link that
     updateStaffSidebarLabel injects into #cart-waiter (JS never toggles
     it). Beats that link's inline `display: inline-flex`. */
  #cart-waiter a[onclick^="logoutStaff"] { display: none !important; }

  /* Floor canvas: plain paper, no dot grid, no visible frame. The border
     stays 1px wide (only its colour goes), so the canvas geometry that the
     layout maths reads does not move. Beats allure-theme.css
     `.floorplan-canvas { background-color; background-image;
     background-size; border: 1px solid var(--border) } !important`. */
  #floorplan-canvas {
    background: var(--k-paper) !important;
    border-color: transparent !important;
  }

  /* Walls: line-strong bars. Beats the inline <style> `.floor-table.line-h`
     / `.line-v { background: #CDBA96 !important }`. The dead layout-edit
     look (.draggable) keeps its own rule. */
  #floorplan-canvas .floor-table:is(.line-h, .line-v):not(.draggable) {
    background: var(--k-line-strong) !important;
  }

  /* Menu keys: columns that fill the row (no ragged right gap) and 6px
     gaps (no zero-gap keypad). One track rule serves every size: each
     grid-* class (JS) sets --k-key-min in 6.9. Beats the inline <style>
     `.menu-grid.grid-sm / -md / -lg / -detail { grid-template-columns;
     gap } !important` and `body.pda-waiter-mode .menu-grid
     { grid-template-columns } !important`. */
  #menu-grid {
    grid-template-columns: repeat(auto-fill, minmax(var(--k-key-min, 136px), 1fr)) !important;
    gap: 6px !important;
  }

  /* Selected category chip: navy fill, white text (allure's var(--blue)
     + #fff, bridged), without the orange glow. Beats the inline <style>
     `.category-chip.active { box-shadow: 0 4px 15px rgba(255,140,45,.35)
     !important }`. */
  .k-chips .category-chip.active { box-shadow: none !important; }

  /* PDA mode (spec 7 #35): the Korpa tab and the table picker are shown in
     PDA mode only. JS never toggles either of them (switchView only moves
     .active), so their static inline display:none hid the waiter's cart
     tab: after picking a table there was no way back to the order. Beats
     those two inline display:none values. */
  body.pda-waiter-mode #tab-cart,
  body.pda-waiter-mode #pda-table-selector-container { display: flex !important; }

  /* PDA order panel: it covers the main area right under the view tabs,
     whose strip is --k-h-tabs (48px) tall, not 50. Beats the inline
     <style> `body.pda-waiter-mode .cart-sidebar { top: 50px; height:
     calc(100% - 50px) } !important`. */
  body.pda-waiter-mode .cart-sidebar {
    top: var(--k-h-tabs) !important;
    height: calc(100% - var(--k-h-tabs)) !important;
  }

  /* Open orders: nothing under 13px. renderList sets 13px and up itself
     since S8.3; the help line (index.html markup, unchanged) still carries
     an inline 12px, which grows here to 13. Beats that inline font-size
     declaration. */
  #open-orders-modal [style*="font-size: 12px"] {
    font-size: var(--k-t-meta) !important;
  }

  /* ══ end LEGACY OVERRIDES ══════════════════════════════════════════════ */


  /* 4.3 Base */

  /* Typography goes on wrappers only (never body/html), so the frozen receipt
     elements keep body typography. design-system.css already makes buttons
     and fields inherit font-family. */
  .pos-header, .pos-layout,
  .modal-overlay:not(#fiscal-modal):not(#esir-info-modal),
  #k-more, #staff-lock-screen, #training-mode-banner,
  #lpfr-alert-banner, #saas-expired-lockscreen {
    font-family: var(--k-font);
  }

  /* Focus: a visible ring on every keyboard stop in the non-fiscal UI.
     (0,2,1) beats the `outline: none` in .form-input / .lang-btn. */
  :where(.pos-header, .pos-layout,
    .modal-overlay:not(#fiscal-modal):not(#esir-info-modal),
    #k-more, #staff-lock-screen, #training-mode-banner,
    #saas-expired-lockscreen, #lsm-modal-pos, #terminal-selector-overlay, .k-msg)
    :is(button, a[href], input, select, textarea, summary, [tabindex]):focus-visible {
    outline: 2px solid var(--k-focus);
    outline-offset: 2px;
  }
  /* Inside the navy check slab the ring turns light gold. */
  :where(.k-check) :is(button, a[href], input, select, textarea, summary, [tabindex]):focus-visible {
    outline-color: var(--k-focus-on-slab);
  }

  /* Hover gating: hover styles are written ONLY inside
     @media (hover: hover) and (pointer: fine), so a tap on the touch till
     never leaves a hover state behind. Pressed feedback uses :active
     (background change only, no transform). */

  /* Text that stays in the accessibility tree and in translation, but not
     on screen (size labels, alert labels at narrow widths). */
  .k-visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
  }

  /* Sentence case for Title Case copy from lang.js ("Podeljeno Plaćanje",
     "Istorija Transakcija"); the copy itself does not change. Only on short
     labels that carry no acronym or name in sr, en or id, and only on a
     block-level box (a span inside a flex row qualifies; a .k-btn itself
     does not, so the class goes on its inner span). */
  .k-sentence { text-transform: lowercase; }
  .k-sentence::first-letter { text-transform: uppercase; }


  /* 4.4 Components (spec section 6) */

  /* 6.1 Buttons .k-btn: 44px, radius 6, 15/600, icon 20. Pressed feedback
     is an instant colour change, never a transform. The primary action is
     always navy; brass only on money confirms; red only when destructive. */
  .k-btn {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--k-2);
    flex-shrink: 0;
    min-width: var(--k-hit);
    height: var(--k-hit);
    padding: 0 var(--k-4);
    border: 1px solid transparent;
    border-radius: var(--k-r-control);
    background: transparent;
    color: var(--k-ink);
    font: 600 var(--k-t-sm)/var(--k-lh-sm) var(--k-font);
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }
  .k-btn > i {
    flex-shrink: 0;
    font-size: 20px;
    line-height: 1;
  }
  .k-btn__label {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .k-btn--compact {
    padding: 0 var(--k-3);
    font-family: var(--k-font-tight);
  }
  .k-btn--lg { height: var(--k-h-key2); }
  .k-btn--xl {
    height: var(--k-h-key);
    font-size: var(--k-t-md);
    line-height: var(--k-lh-md);
  }
  /* Full width (the confirm key at the foot of a payment sheet). */
  .k-btn--block {
    flex: 1 1 100%;
    width: 100%;
  }

  .k-btn--primary { background: var(--k-navy); color: var(--k-on-navy); }
  .k-btn--secondary { background: var(--k-surface); border-color: var(--k-line-strong); }
  .k-btn--quiet { color: var(--k-slate); }
  .k-btn--money { background: var(--k-brass); border-color: var(--k-control-edge); color: var(--k-on-brass); }
  .k-btn--danger { background: var(--k-danger); color: var(--k-on-danger); }
  .k-btn--danger-ghost { background: var(--k-surface); border-color: var(--k-danger); color: var(--k-danger); }
  .k-btn--warn { background: var(--k-warn-tint); border-color: var(--k-warn-line); color: var(--k-warn-ink); }

  /* Hover (pointer devices only), then pressed, then disabled: same
     specificity for hover and pressed, so source order lets a press win. */
  @media (hover: hover) and (pointer: fine) {
    .k-btn--primary:hover { background: var(--k-navy-raised); }
    .k-btn--secondary:hover,
    .k-btn--quiet:hover { background: var(--k-sunken); }
    .k-btn--money:hover { background: var(--k-brass-hover); }
    .k-btn--danger:hover { background: var(--k-danger-ink); }
    .k-btn--danger-ghost:hover { background: var(--k-danger-tint); }
    .k-btn--warn:hover { background: var(--k-warn-hover); }
  }
  .k-btn--primary:active { background: var(--k-navy-raised); }
  .k-btn--secondary:active,
  .k-btn--quiet:active { background: var(--k-sunken-press); }
  .k-btn--money:active { background: var(--k-brass-press); }
  .k-btn--danger:active { background: var(--k-danger-ink); }
  .k-btn--danger-ghost:active { background: var(--k-danger-tint); color: var(--k-danger-ink); }
  .k-btn--warn:active { background: var(--k-warn-hover); }

  /* Disabled: [disabled] or .is-disabled. --money adds nothing, because JS
     writes opacity .5 + pointer-events none on the payment confirms. */
  .k-btn:is([disabled], .is-disabled) { cursor: default; }
  .k-btn:is(.k-btn--primary, .k-btn--danger):is([disabled], .is-disabled) {
    background: var(--k-sunken);
    border-color: transparent;
    color: var(--k-ink-3);
  }
  .k-btn--secondary:is([disabled], .is-disabled) {
    background: var(--k-sunken);
    border-color: var(--k-line);
    color: var(--k-ink-3);
  }
  .k-btn--quiet:is([disabled], .is-disabled) { background: transparent; color: var(--k-ink-3); }
  .k-btn--danger-ghost:is([disabled], .is-disabled) {
    background: var(--k-surface);
    border-color: var(--k-line);
    color: var(--k-ink-3);
  }

  /* Icon-only button: a real 44x44 box, always with an aria-label. */
  .k-iconbtn {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: var(--k-hit);
    height: var(--k-hit);
    padding: 0;
    border: 0;
    border-radius: var(--k-r-control);
    background: transparent;
    color: var(--k-slate);
    font-size: 20px;
    line-height: 1;
    text-decoration: none;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }
  .k-iconbtn > i { font-size: 20px; }
  @media (hover: hover) and (pointer: fine) {
    .k-iconbtn:hover { background: var(--k-sunken); color: var(--k-ink); }
  }
  .k-iconbtn:active { background: var(--k-sunken-press); color: var(--k-ink); }
  /* Bordered icon buttons next to a .k-btn--secondary (order actions). */
  .k-iconbtn--secondary {
    border: 1px solid var(--k-line-strong);
    background: var(--k-surface);
    color: var(--k-ink);
  }
  .k-iconbtn--danger-ghost {
    border: 1px solid var(--k-danger);
    background: var(--k-surface);
    color: var(--k-danger);
  }
  @media (hover: hover) and (pointer: fine) {
    .k-iconbtn--secondary:hover { background: var(--k-sunken); color: var(--k-ink); }
    .k-iconbtn--danger-ghost:hover { background: var(--k-danger-tint); color: var(--k-danger); }
  }
  .k-iconbtn--secondary:active { background: var(--k-sunken-press); color: var(--k-ink); }
  .k-iconbtn--danger-ghost:active { background: var(--k-danger-tint); color: var(--k-danger-ink); }
  /* Quiet remove/delete in rows (split payment rows, reservations). */
  .k-iconbtn--danger { color: var(--k-danger); }
  @media (hover: hover) and (pointer: fine) {
    .k-iconbtn--danger:hover { background: var(--k-danger-tint); color: var(--k-danger); }
  }
  .k-iconbtn--danger:active { background: var(--k-danger-tint); color: var(--k-danger-ink); }

  /* Count bubble: grows for 2-3 digit counts. JS flips its inline display
     (none / flex), so display is never set here. */
  .k-count {
    position: absolute;
    top: -6px;
    right: -6px;
    align-items: center;
    justify-content: center;
    min-width: 22px;
    height: 22px;
    padding: 0 6px;
    border-radius: var(--k-r-round);
    background: var(--k-danger);
    color: var(--k-on-danger);
    font: 700 var(--k-t-meta)/1 var(--k-font);
    font-variant-numeric: tabular-nums lining-nums;
  }

  /* 6.3 Status pills: not interactive (exempt from the 44px rule). */
  .k-pill {
    display: inline-flex;
    align-items: center;
    gap: var(--k-2);
    flex-shrink: 0;
    height: 28px;
    padding: 0 var(--k-3);
    border-radius: var(--k-r-round);
    font: 600 var(--k-t-sm)/1 var(--k-font-tight);
    white-space: nowrap;
  }
  .k-pill > i { font-size: 16px; line-height: 1; }
  .k-pill--ok { background: var(--k-ok-tint); color: var(--k-ok-ink); }
  .k-pill--danger { background: var(--k-danger); color: var(--k-on-danger); }
  .k-pill--info { background: var(--k-info-tint); color: var(--k-info); }
  .k-pill--warn { background: var(--k-warn-tint); color: var(--k-warn-ink); }
  .k-pill--neutral { background: var(--k-sunken); color: var(--k-slate); }

  /* 6.4 Fields .k-field: 44px (48 in modals, 56 for the cash amount), white,
     a 1px line-strong edge (3:1+), 17/400 navy (17 avoids zoom on focus),
     ink-3 placeholder (5.59:1). The focus ring comes from 4.3. */
  .k-field {
    display: block;
    width: 100%;
    min-width: 0;
    height: var(--k-hit);
    padding: 0 var(--k-3);
    border: 1px solid var(--k-line-strong);
    border-radius: var(--k-r-control);
    background: var(--k-surface);
    color: var(--k-ink);
    font: 400 var(--k-t-md)/var(--k-lh-md) var(--k-font);
    text-overflow: ellipsis;
  }
  .k-field::placeholder {
    color: var(--k-ink-3);
    opacity: 1;
  }
  @media (hover: hover) and (pointer: fine) {
    .k-field:hover { border-color: var(--k-slate); }
  }
  .k-field:focus { border-color: var(--k-ink); }
  .k-field:is([aria-invalid="true"], .k-field--error) { border-color: var(--k-danger); }
  .k-field:disabled {
    background: var(--k-sunken);
    color: var(--k-ink-3);
  }
  /* Selects: no native arrow; a chevron drawn from two token-coloured
     triangles (no image, no network), with room kept for it. */
  .k-field--select {
    -webkit-appearance: none;
    appearance: none;
    padding-right: calc(var(--k-3) + 20px);
    background-image:
      linear-gradient(45deg, transparent 50%, var(--k-slate) 50%),
      linear-gradient(135deg, var(--k-slate) 50%, transparent 50%);
    background-position:
      calc(100% - var(--k-3) - 10px) 50%,
      calc(100% - var(--k-3) - 4px) 50%;
    background-size: 6px 6px;
    background-repeat: no-repeat;
    cursor: pointer;
  }

  /* 6.2 The check .k-check: the one dark surface in the order column, a
     navy slab like the bill folder a waiter carries. It holds the total
     (36/700 white, the number read aloud) and the pay keys. One brass key:
     Gotovina. Keys never get pointer-events:none or [disabled]: #pay-online
     is never un-disabled by togglePaymentButtons, yet it is the live
     Online/App path. */
  .k-check {
    margin: 0 var(--k-2) var(--k-2);
    padding: var(--k-3);
    border-radius: var(--k-r-sheet);
    background: var(--k-navy);
    color: var(--k-on-navy);
    box-shadow: var(--k-e1);
  }
  .k-check__total {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-areas: "label amount" "eur amount";
    align-items: center;
    column-gap: var(--k-3);
  }
  /* .summary-row.total keeps its classes and ids; its two spans become
     grid items of the total block. */
  .k-check__total > .summary-row.total { display: contents; }
  .k-check__total > .summary-row.total > span:first-child {
    grid-area: label;
    align-self: end;
    color: var(--k-slab-ink-2);
    font: 600 var(--k-t-sm)/var(--k-lh-sm) var(--k-font);
    text-transform: lowercase; /* "UKUPNO" arrives in caps: sentence case, copy unchanged */
  }
  .k-check__total > .summary-row.total > span:first-child::first-letter { text-transform: uppercase; }
  .k-check #summary-total {
    grid-area: amount;
    justify-self: end;
    min-width: 0;
    color: var(--k-on-navy);
    font: 700 var(--k-t-2xl)/var(--k-lh-2xl) var(--k-font);
    font-variant-numeric: tabular-nums lining-nums;
    white-space: nowrap;
  }
  .k-check #summary-eur {
    grid-area: eur;
    align-self: start;
    color: var(--k-slab-ink-2);
    font: 400 var(--k-t-meta)/var(--k-lh-meta) var(--k-font);
    font-variant-numeric: tabular-nums lining-nums;
    white-space: nowrap;
  }

  /* Pay grid: 6 columns. Tier 1 (Gotovina, Kartica): 3 columns each, 56px,
     17/600. Tier 2 (IPS QR, Online, Podeljeno): 2 columns each, 48px, 15/600
     condensed, raised navy with a 1px slab-edge so the key shape reads.
     Colours go through --k-pay-bg / --k-pay-fg so the .disabled override
     in LEGACY OVERRIDES keeps them. Press = colour only, no transform. */
  .k-check .pay-btn-grid {
    grid-template-columns: repeat(6, minmax(0, 1fr));
    gap: var(--k-2);
    margin-top: var(--k-3);
  }
  .k-check .pay-btn {
    --k-pay-bg: var(--k-navy-raised);
    --k-pay-fg: var(--k-on-navy);
    grid-column: span 2;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    gap: var(--k-2);
    min-width: 0;
    height: var(--k-h-key2);
    padding: 0 var(--k-1);
    border: 1px solid var(--k-slab-edge);
    border-radius: var(--k-r-control);
    background: var(--k-pay-bg);
    color: var(--k-pay-fg);
    font: 600 var(--k-t-sm)/var(--k-lh-sm) var(--k-font-tight);
    text-align: center;
    text-wrap: balance;
    box-shadow: none;
    transform: none;
    transition: none;
    -webkit-tap-highlight-color: transparent;
  }
  .k-check .pay-btn > i {
    flex-shrink: 0;
    font-size: 18px;
    line-height: 1;
  }
  .k-check .pay-btn > span {
    min-width: 0;
    overflow-wrap: break-word;
  }
  .k-check :is(#pay-cash, #pay-card) {
    grid-column: span 3;
    height: var(--k-h-key);
    padding: 0 var(--k-2);
    border: 0;
    font: 600 var(--k-t-md)/var(--k-lh-md) var(--k-font);
  }
  .k-check :is(#pay-cash, #pay-card) > i { font-size: 20px; }
  .k-check #pay-cash { --k-pay-bg: var(--k-brass); --k-pay-fg: var(--k-on-brass); }
  .k-check #pay-card { --k-pay-bg: var(--k-surface); --k-pay-fg: var(--k-ink); }
  @media (hover: hover) and (pointer: fine) {
    .k-check .pay-btn:hover { --k-pay-bg: var(--k-navy-hover); }
    .k-check #pay-cash:hover { --k-pay-bg: var(--k-brass-hover); }
    .k-check #pay-card:hover { --k-pay-bg: var(--k-paper); }
  }
  .k-check .pay-btn:active { --k-pay-bg: var(--k-navy); }
  .k-check #pay-cash:active { --k-pay-bg: var(--k-brass-press); }
  .k-check #pay-card:active { --k-pay-bg: var(--k-sunken-press); }
  /* Disabled (class only): the key dims but keeps its colours. */
  .k-check .pay-btn.disabled { opacity: .45; }
  /* #pay-online stays .disabled for good (togglePaymentButtons never lists
     it), yet it works: it looks enabled whenever Gotovina does. */
  .pay-btn-grid:has(#pay-cash:not(.disabled)) #pay-online.disabled { opacity: 1; }
  /* Simple payment mode: JS hides #pay-card and #pay-qr (inline
     display:none), so Gotovina takes the full row and Online + Podeljeno
     share the second. */
  .pay-btn-grid:has(> #pay-card[style*="none"]) #pay-cash { grid-column: span 6; }
  .pay-btn-grid:has(> #pay-card[style*="none"]) :is(#pay-online, #pay-split) { grid-column: span 3; }

  /* 6.8 Order lines (.cart-item-row, rendered by renderCart): ruled rows on
     white, no boxes, about 72px each. Grid areas "name price rm" /
     "meta qty rm"; .cart-item-info becomes transparent to the grid. */
  .cart-item-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto var(--k-hit);
    grid-template-areas: "name price rm" "meta qty rm";
    align-items: center;
    flex-shrink: 0;
    gap: 2px var(--k-2);
    padding: var(--k-2) var(--k-3);
    border: 0;
    border-bottom: 1px solid var(--k-line);
    border-radius: 0;
    background: transparent;
  }
  .cart-item-info { display: contents; }
  .cart-item-name {
    grid-area: name;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    overflow: hidden;
    color: var(--k-ink);
    font: 600 var(--k-t-sm)/var(--k-lh-sm) var(--k-font);
    overflow-wrap: anywhere;
  }
  .cart-item-details {
    grid-area: meta;
    min-width: 0;
    overflow: hidden;
    color: var(--k-ink-3);
    font: 400 var(--k-t-meta)/var(--k-lh-meta) var(--k-font);
    font-variant-numeric: tabular-nums lining-nums;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  /* Price: the tap target for editCartPrice. A 36px box (the spec's
     exemption floor) with a 19px layout footprint. */
  .cart-item-price {
    grid-area: price;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--k-1);
    min-width: 84px;
    height: 36px;
    margin: -9px 0 -8px;
    color: var(--k-ink);
    font: 700 var(--k-t-sm)/var(--k-lh-sm) var(--k-font);
    font-variant-numeric: tabular-nums lining-nums;
    white-space: nowrap;
  }
  .cart-item-price > i {
    color: var(--k-ink-3);
    font-size: 14px;
    line-height: 1;
  }
  /* Stepper: each key is a real 44x44 box laid out as 40x32 (negative
     margins); the visible key is a ::before. It sits above the price box,
     so a tap where the two meet goes to the stepper. */
  .cart-item-qty-control {
    grid-area: qty;
    justify-self: end;
    position: relative;
    z-index: 1;
    gap: 0;
  }
  .qty-btn {
    position: relative;
    isolation: isolate;
    width: var(--k-hit);
    height: var(--k-hit);
    margin: -6px -2px;
    padding: 0;
    border: 0;
    border-radius: var(--k-r-control);
    background: transparent;
    color: var(--k-ink);
    font-size: 0; /* the "-" / "+" text stays as the accessible name; the glyph is ::after */
    line-height: 1;
    -webkit-tap-highlight-color: transparent;
  }
  .qty-btn::after {
    content: "\eb0b"; /* ti-plus */
    font: 18px/1 "tabler-icons";
  }
  .cart-item-qty-control > .qty-btn:first-child::after { content: "\eaf2"; } /* ti-minus */
  .qty-btn::before {
    content: "";
    position: absolute;
    inset: 6px 2px;
    z-index: -1;
    border-radius: var(--k-r-control);
    background: var(--k-sunken);
    box-shadow: inset 0 0 0 1px var(--k-control-edge);
  }
  /* The legacy .qty-btn:hover (not hover-gated) would stick after a tap. */
  .qty-btn:hover { background: transparent; }
  @media (hover: hover) and (pointer: fine) {
    .qty-btn:hover::before { background: var(--k-sunken-press); }
  }
  .qty-btn:active { color: var(--k-on-navy); }
  .qty-btn:active::before { background: var(--k-navy); }
  .qty-btn:focus-visible { outline-offset: -2px; }
  /* Quantity: tap to type a decimal quantity (editCartQty); the dotted
     underline says it can be edited. A full 44x44 hit box. */
  .cart-item-qty-control > span {
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: var(--k-hit);
    height: var(--k-hit);
    margin: -6px 0;
    color: var(--k-ink);
    font: 700 var(--k-t-md)/1 var(--k-font);
    font-variant-numeric: tabular-nums lining-nums;
    text-decoration: underline dotted var(--k-line-strong);
    text-underline-offset: 4px;
  }
  /* Remove: a quiet 44x44 icon spanning both rows; danger on press. */
  .rm-btn {
    grid-area: rm;
    display: flex;
    align-items: center;
    justify-content: center;
    width: var(--k-hit);
    height: var(--k-hit);
    padding: 0;
    border-radius: var(--k-r-control);
    color: var(--k-slate);
    font-size: 20px;
    line-height: 1;
    -webkit-tap-highlight-color: transparent;
  }
  .rm-btn > i { font-size: 20px; }
  @media (hover: hover) and (pointer: fine) {
    .rm-btn:hover { background: var(--k-sunken); color: var(--k-ink); }
  }
  .rm-btn:active { background: var(--k-danger-tint); color: var(--k-danger); }

  /* 6.6 Category chips (buildCategoryChips, untouched; JS toggles
     .active): 44px, radius 6, white with a line-strong edge, 15/600
     condensed navy. Selected = navy fill + white (allure's .active rule,
     bridged; its glow goes in LEGACY OVERRIDES). The category icons are
     hidden: the name carries the meaning. The row scrolls sideways with a
     hidden scrollbar; its right edge fades as an overflow hint, and the
     end padding lets the last chip scroll clear of the fade. Chips are
     <span onclick> in a JS template, so they take no keyboard focus (R8).
     (0,2,0) after the inline <style> also beats its unguarded
     .category-chip:hover / :active lift and scale. */
  .k-chips {
    gap: var(--k-2);
    padding: 0 var(--k-6) 0 0;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
    -webkit-mask-image: linear-gradient(to right, black calc(100% - var(--k-6)), transparent);
    mask-image: linear-gradient(to right, black calc(100% - var(--k-6)), transparent);
  }
  .k-chips::-webkit-scrollbar { display: none; }
  .k-chips .category-chip {
    flex-shrink: 0;
    gap: 0;
    height: var(--k-hit);
    padding: 0 var(--k-4);
    border: 1px solid var(--k-line-strong);
    border-radius: var(--k-r-control);
    background: var(--k-surface);
    color: var(--k-ink);
    font: 600 var(--k-t-sm)/var(--k-lh-sm) var(--k-font-tight);
    box-shadow: none;
    transform: none;
    transition: none;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
  }
  .k-chips .category-chip > i { display: none; }
  @media (hover: hover) and (pointer: fine) {
    .k-chips .category-chip:hover { background: var(--k-sunken); }
  }
  .k-chips .category-chip:active { background: var(--k-sunken-press); }

  /* 6.7 Segmented control .k-seg (menu key size): a sunken track with
     44x44 segments. The track edge is an inset shadow, so it draws the 1px
     line without adding height (track = 48px, the search field's height).
     Selected (JS toggles .active on #size-btn-*): navy fill, white icon. */
  .k-seg {
    display: inline-flex;
    flex-shrink: 0;
    padding: 2px;
    border-radius: var(--k-r-control);
    background: var(--k-sunken);
    box-shadow: inset 0 0 0 1px var(--k-line);
  }
  .k-seg__btn {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: var(--k-hit);
    height: var(--k-hit);
    padding: 0;
    border: 0;
    border-radius: var(--k-r-control);
    background: transparent;
    color: var(--k-slate);
    line-height: 1;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }
  .k-seg__btn > i {
    font-size: 20px;
    line-height: 1;
  }
  .k-seg__btn.active {
    background: var(--k-navy);
    color: var(--k-on-navy);
    cursor: default;
  }
  @media (hover: hover) and (pointer: fine) {
    .k-seg__btn:not(.active):hover { background: var(--k-sunken-press); color: var(--k-ink); }
  }
  .k-seg__btn:not(.active):active { background: var(--k-sunken-press); color: var(--k-ink); }

  /* 6.9 Menu keys .k-key (renderMenu; renamed from .menu-card, so allure's
     .menu-card !important rules and the inline size rules no longer
     apply). White, 1px line, radius 6, no shadow. Name 15/600 in up to 3
     whole lines (the clamp never cuts a line in half); price 15/700 navy,
     tabular, at the foot of the key; VAT 13 ink-3 only in md and detail.
     The emoji is hidden in every size (D5; delete that one rule to bring
     it back). A press fills the key navy at once and fades back over
     120ms: the tap acknowledgement. Keys are template divs, so they take
     no keyboard focus (R8).
     Row height: the per-size minimum (--k-key-row) sits on the key, and
     each row is sized to its tallest key (max-content). With minmax(96px,
     auto) or auto rows, a row grows past its minimum only into free space
     left in the grid box, so once the grid scrolls, a 3-line name or a
     photo would spill out of its key. */
  #menu-grid {
    --k-key-min: 136px;
    --k-key-row: 96px;
    min-height: 0;
    margin-top: var(--k-1);
    padding: 0;
    grid-auto-rows: max-content;
    align-content: start;
    overscroll-behavior: contain;
    scrollbar-width: thin;
    scrollbar-color: var(--k-line-strong) transparent;
  }
  #menu-grid.grid-md { --k-key-min: 168px; --k-key-row: 120px; }
  #menu-grid.grid-lg { --k-key-min: 216px; --k-key-row: 120px; }
  #menu-grid.grid-detail { --k-key-min: 100%; --k-key-row: 56px; }
  .k-key {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: var(--k-1);
    min-width: 0;
    min-height: var(--k-key-row, 96px);
    padding: 10px var(--k-3);
    border: 1px solid var(--k-line);
    border-radius: var(--k-r-control);
    background: var(--k-surface);
    color: var(--k-ink);
    text-align: left;
    cursor: pointer;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
    transition:
      background-color var(--k-dur-fast) var(--k-ease),
      border-color var(--k-dur-fast) var(--k-ease),
      color var(--k-dur-fast) var(--k-ease);
  }
  .k-key__icon,
  .k-key__img,
  .k-key__vat { display: none; }
  .k-key__name {
    display: -webkit-box;
    flex-shrink: 0;
    overflow: hidden;
    font: 600 var(--k-t-sm)/var(--k-lh-sm) var(--k-font);
    overflow-wrap: anywhere;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    line-clamp: 3;
  }
  .k-key__price {
    flex-shrink: 0;
    margin-top: auto;
    font: 700 var(--k-t-sm)/var(--k-lh-sm) var(--k-font);
    font-variant-numeric: tabular-nums lining-nums;
    white-space: nowrap;
  }
  .k-key__vat {
    flex-shrink: 0;
    color: var(--k-ink-3);
    font: 400 var(--k-t-meta)/var(--k-lh-meta) var(--k-font);
    white-space: nowrap;
    transition: color var(--k-dur-fast) var(--k-ease);
  }
  @media (hover: hover) and (pointer: fine) {
    .k-key:hover { border-color: var(--k-line-strong); }
  }
  .k-key:active {
    border-color: var(--k-ink);
    background: var(--k-navy);
    color: var(--k-on-navy);
    transition: none;
  }
  .k-key:active .k-key__vat {
    color: var(--k-slab-ink-2);
    transition: none;
  }
  /* md: name, price, VAT. */
  #menu-grid.grid-md .k-key__vat { display: block; }
  /* lg: the 4:3 photo when the item has one, then name and price at 17. */
  #menu-grid.grid-lg .k-key { gap: var(--k-2); }
  #menu-grid.grid-lg .k-key__img {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 4 / 3;
    border-radius: var(--k-r-control);
    background: var(--k-sunken);
    object-fit: cover;
  }
  #menu-grid.grid-lg .k-key__name,
  #menu-grid.grid-lg .k-key__price {
    font-size: var(--k-t-md);
    line-height: var(--k-lh-md);
  }
  /* detail: one row per item, name left (one line, ellipsis), then VAT,
     then the price right-aligned in a fixed column. */
  #menu-grid.grid-detail .k-key {
    flex-direction: row;
    align-items: center;
    gap: var(--k-4);
    padding: 0 var(--k-4);
  }
  #menu-grid.grid-detail .k-key__name {
    display: block;
    flex: 1 1 auto;
    min-width: 0;
    text-overflow: ellipsis;
    white-space: nowrap;
    -webkit-line-clamp: none;
    line-clamp: none;
  }
  #menu-grid.grid-detail .k-key__vat {
    display: block;
    order: 1;
  }
  #menu-grid.grid-detail .k-key__price {
    order: 2;
    min-width: 96px;
    margin-top: 0;
    text-align: right;
  }

  /* 6.12 Više popover #k-more: a native popover (top layer, light dismiss,
     Esc), anchored under its trigger. It sits inside .pos-header in the DOM,
     so it inherits the bridged tokens (JS "on" colours var(--gold) and
     var(--blue) resolve to warn-fill and navy). The UA hides it while
     closed, so display is only set on :popover-open. */
  .k-menu {
    position: fixed;
    inset: auto;
    top: calc(var(--k-h-head) + var(--k-1));
    right: var(--k-3);
    width: 300px;
    max-width: calc(100vw - 2 * var(--k-3));
    max-height: calc(100vh - var(--k-h-head) - var(--k-5));
    margin: 0;
    padding: var(--k-2);
    overflow: auto;
    border: 1px solid var(--k-line);
    border-radius: var(--k-r-card);
    background: var(--k-surface);
    color: var(--k-ink);
    box-shadow: var(--k-e2);
  }
  .k-menu:popover-open {
    display: flex;
    flex-direction: column;
    animation: k-fade-in var(--k-dur-fast) var(--k-ease);
  }
  @supports (anchor-name: --k-a) {
    .k-bar__more { anchor-name: --k-more; }
    .k-menu {
      position-anchor: --k-more;
      top: anchor(bottom);
      right: anchor(right);
      margin-top: var(--k-1);
    }
  }
  /* Rows: 44px, icon 20 + 15/600 label. width:100% keeps the JS
     `display: inline-flex` of #absen-btn and #pos-admin-btn full width. */
  .k-menu__item {
    display: flex;
    align-items: center;
    gap: var(--k-3);
    flex-shrink: 0;
    width: 100%;
    min-height: var(--k-hit);
    padding: 0 var(--k-3);
    border: 0;
    border-radius: var(--k-r-control);
    background: transparent;
    color: var(--k-ink);
    font: 600 var(--k-t-sm)/var(--k-lh-sm) var(--k-font);
    text-align: left;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }
  .k-menu__item > i {
    flex-shrink: 0;
    width: 20px;
    font-size: 20px;
    line-height: 1;
    text-align: center;
  }
  .k-menu__item > span {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  /* Training and PDA: once JS has run, their "off" state is an inline
     background var(--bg3) (bridged to transparent), which a class rule
     cannot beat, so hover and press redefine --bg3 on the element itself. */
  @media (hover: hover) and (pointer: fine) {
    .k-menu__item:hover { background: var(--k-sunken); }
    #training-mode-toggle-btn:hover, #pda-mode-btn:hover { --bg3: var(--k-sunken); }
  }
  .k-menu__item:active { background: var(--k-sunken-press); }
  #training-mode-toggle-btn:active, #pda-mode-btn:active { --bg3: var(--k-sunken-press); }
  /* "Režim Obuke: ISKLJUČEN" arrives in caps: sentence case, copy unchanged. */
  #training-mode-toggle-label { text-transform: lowercase; }
  #training-mode-toggle-label::first-letter { text-transform: uppercase; }
  /* Server row: the dot carries the connection state (JS colours it); JS
     also writes a light status colour on the button, so its text stays navy. */
  #lsm-header-btn > :not(#lsm-header-dot) { color: var(--k-ink); }
  #lsm-header-dot {
    flex-shrink: 0;
    width: 8px;
    height: 8px;
    margin-left: auto;
    border-radius: 50%;
  }
  /* Language: a segmented control (6.7) filled by App.renderLanguageSelector.
     .lang-btn.active keeps allure's var(--blue) + white, which the bridge
     turns into navy; only its orange glow is removed. */
  .k-menu__lang {
    display: flex;
    align-items: center;
    gap: var(--k-3);
    margin-top: var(--k-1);
    padding: var(--k-2) var(--k-3) var(--k-1);
    border-top: 1px solid var(--k-line);
    color: var(--k-slate);
  }
  .k-menu__lang > i {
    width: 20px;
    font-size: 20px;
    line-height: 1;
    text-align: center;
  }
  #k-more .lang-switcher {
    display: inline-flex;
    gap: 0;
    padding: 2px;
    border: 1px solid var(--k-line);
    border-radius: var(--k-r-control);
    background: var(--k-sunken);
  }
  #k-more .lang-btn {
    width: var(--k-hit);
    height: var(--k-hit);
    padding: 0;
    border-radius: var(--k-r-control);
    color: var(--k-slate);
    font: 600 var(--k-t-sm)/1 var(--k-font);
    transition: none;
  }
  #k-more .lang-btn.active { box-shadow: none; }
  @media (hover: hover) and (pointer: fine) {
    #k-more .lang-btn:not(.active):hover { background: var(--k-sunken-press); color: var(--k-ink); }
  }
  .k-menu__foot {
    display: flex;
    flex-wrap: wrap;
    gap: var(--k-1);
    padding: var(--k-1) var(--k-3);
    color: var(--k-ink-3);
    font: 400 var(--k-t-meta)/var(--k-lh-meta) var(--k-font);
    font-variant-numeric: tabular-nums lining-nums;
  }
  /* Trigger: pressed look while the menu is open; an amber dot while
     training mode is on (the banner is the source of truth). */
  .k-bar:has(#k-more:popover-open) .k-bar__more {
    background: var(--k-sunken-press);
    color: var(--k-ink);
  }
  body:has(#training-mode-banner[style*="display: block"]) .k-bar__more::after {
    content: "";
    position: absolute;
    top: var(--k-2);
    right: var(--k-2);
    width: 8px;
    height: 8px;
    border: 1px solid var(--k-warn-line);
    border-radius: 50%;
    background: var(--k-warn-fill);
    box-shadow: 0 0 0 2px var(--k-surface);
  }
  /* The visible "Više" label (S8.2): where the header has the room (above
     1300px, outside PDA mode). Below that the key is icon-only; its name
     always comes from #k-label-more (aria-labelledby), in every language. */
  .k-bar__more-label { display: none; }
  @media (min-width: 1301px) {
    body:not(.pda-waiter-mode) .k-bar__more {
      width: auto;
      gap: var(--k-2);
      padding: 0 var(--k-3);
    }
    body:not(.pda-waiter-mode) .k-bar__more-label {
      display: inline;
      font: 600 var(--k-t-sm)/var(--k-lh-sm) var(--k-font-tight);
    }
    /* The training dot moves into the corner, clear of the label. */
    body:has(#training-mode-banner[style*="display: block"]):not(.pda-waiter-mode) .k-bar__more::after {
      top: var(--k-1);
      right: var(--k-1);
    }
  }
  /* Never above a locked till: the lock screens start or become
     display:flex, and #k-more is a new element JS never toggles. */
  body:has(#staff-lock-screen[style*="display: flex"]) #k-more,
  body:has(#staff-lock-screen[style*="display:flex"]) #k-more,
  body:has(#saas-expired-lockscreen[style*="display: flex"]) #k-more,
  body:has(#saas-expired-lockscreen[style*="display:flex"]) #k-more {
    display: none !important;
  }
  /* No popover support: the menu becomes a header row that scrolls sideways. */
  @supports not selector(:popover-open) {
    .k-bar__more { display: none; }
    .k-menu {
      position: static;
      display: flex;
      align-items: center;
      flex: 0 1 auto;
      min-width: 0;
      width: auto;
      max-width: none;
      max-height: none;
      padding: 0;
      overflow-x: auto;
      border: 0;
      background: transparent;
      box-shadow: none;
    }
    .k-menu__item { width: auto; }
    .k-menu__lang { margin: 0; padding: 0 var(--k-2); border: 0; }
    .k-menu__foot { display: none; }
  }

  /* 6.11 Modals .k-modal (non-fiscal only): white sheet, radius 14, e3; a
     64px head (title 21/600 + 44px close), a body that scrolls, a foot with
     the actions on the right (secondary before primary; payment sheets use
     one full-width 56px key). #fiscal-modal and #esir-info-modal keep
     today's look (D3, D7): they are excluded from the scrim below and never
     carry .k-modal. Visibility and opacity stay with the frozen
     .modal-overlay / .modal-overlay.active rules; the sheet settles 8px
     upward as it appears. Widths: 400 sm, 440 default, 480 split. */
  .modal-overlay:not(#fiscal-modal):not(#esir-info-modal) { background: var(--k-scrim); }
  .k-modal {
    --k-modal-w: 440px;
    display: flex;
    flex-direction: column;
    width: min(var(--k-modal-w), calc(100vw - 2 * var(--k-4)));
    max-height: calc(100vh - 96px);
    overflow: hidden;
    border-radius: var(--k-r-sheet);
    background: var(--k-surface);
    color: var(--k-ink);
    text-align: left;
    box-shadow: var(--k-e3);
    transform: translateY(8px);
    transition: transform var(--k-dur) var(--k-ease);
  }
  .modal-overlay.active > .k-modal { transform: none; }
  .k-modal--sm { --k-modal-w: 400px; }
  .k-modal--split { --k-modal-w: 480px; }
  .k-modal__head {
    display: flex;
    align-items: center;
    gap: var(--k-3);
    flex-shrink: 0;
    min-height: 64px;
    padding: 0 var(--k-4) 0 var(--k-5);
    border-bottom: 1px solid var(--k-line);
  }
  .k-modal__title {
    display: flex;
    align-items: center;
    gap: var(--k-2);
    flex: 1 1 auto;
    min-width: 0;
    margin: 0;
    color: var(--k-ink);
    font: 600 var(--k-t-lg)/var(--k-lh-lg) var(--k-font);
  }
  .k-modal__title > i {
    flex-shrink: 0;
    font-size: 24px;
    line-height: 1;
  }
  .k-modal__body {
    display: flex;
    flex-direction: column;
    gap: var(--k-4);
    min-height: 0;
    overflow-y: auto;
    padding: 20px var(--k-5);
    overscroll-behavior: contain;
  }
  .k-modal__foot {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: var(--k-2);
    flex-shrink: 0;
    padding: var(--k-4) var(--k-5);
    border-top: 1px solid var(--k-line);
  }
  .k-modal__text {
    margin: 0;
    color: var(--k-slate);
    font: 400 var(--k-t-sm)/1.4 var(--k-font);
  }
  .k-modal__section {
    display: flex;
    flex-direction: column;
    gap: var(--k-2);
    padding-top: var(--k-4);
    border-top: 1px solid var(--k-line);
  }
  /* Fields in sheets: 48px; number spinners go (touch till, and the arrows
     covered the right-aligned amounts). */
  .k-modal .k-field { height: var(--k-h-key2); }
  .k-modal .k-field[type="number"] {
    -moz-appearance: textfield;
    appearance: textfield;
  }
  .k-modal .k-field[type="number"]::-webkit-inner-spin-button,
  .k-modal .k-field[type="number"]::-webkit-outer-spin-button {
    -webkit-appearance: none;
    margin: 0;
  }
  .k-field--num { font-variant-numeric: tabular-nums lining-nums; }
  /* A label (13/600 slate, sentence case) above its field; groups side by
     side in a .k-row. */
  .k-group {
    display: flex;
    flex-direction: column;
    gap: var(--k-1);
    min-width: 0;
  }
  .k-label {
    display: block;
    margin: 0;
    color: var(--k-slate);
    font: 600 var(--k-t-meta)/var(--k-lh-meta) var(--k-font);
  }
  .k-row {
    display: flex;
    gap: var(--k-3);
  }
  .k-row__grow { flex: 1 1 0; }
  .k-row__pax { flex: 0 0 96px; }
  /* Field message: one reserved line, so the sheet does not jump. */
  .k-field-error {
    min-height: calc(var(--k-t-meta) * var(--k-lh-meta)); /* one line kept, so the sheet never jumps */
    margin: 0;
    color: var(--k-danger);
    font: 600 var(--k-t-meta)/var(--k-lh-meta) var(--k-font);
  }
  /* Empty and failure lines in lists: centred 15 slate. */
  .k-empty-line {
    padding: var(--k-6) var(--k-4);
    color: var(--k-slate);
    font: 400 var(--k-t-sm)/var(--k-lh-sm) var(--k-font);
    text-align: center;
  }
  /* Indeterminate progress (the EDC wait): a 3px navy bar sliding on a
     sunken track; it stands still under reduced motion. */
  .k-progress {
    position: relative;
    width: 100%;
    max-width: 240px;
    height: 3px;
    overflow: hidden;
    border-radius: var(--k-r-round);
    background: var(--k-sunken);
  }
  .k-progress__bar {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    width: 25%;
    border-radius: inherit;
    background: var(--k-navy);
    animation: k-indeterminate 1.4s var(--k-ease) infinite;
  }

  /* 6.13 Data tables .k-table (history, reservations): a white card that
     scrolls on both axes inside its view (the page never scrolls
     sideways), a sticky sunken header row (13/600 slate, sentence case),
     52px rows of 15/400 with line rules, figures tabular and right-aligned
     in their own columns. Row actions are 44px keys. */
  .k-table {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
    border: 1px solid var(--k-line);
    border-radius: var(--k-r-card);
    background: var(--k-surface);
    overscroll-behavior: contain;
    scrollbar-color: var(--k-line-strong) transparent;
    container-type: inline-size;
  }
  .k-table__grid {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    color: var(--k-ink);
    text-align: left;
  }
  .k-table__grid th {
    position: sticky;
    top: 0;
    z-index: 2;
    padding: var(--k-3) var(--k-2);
    border-bottom: 1px solid var(--k-line);
    background: var(--k-sunken);
    color: var(--k-slate);
    font: 600 var(--k-t-meta)/var(--k-lh-meta) var(--k-font);
    text-align: left;
    white-space: nowrap;
    text-transform: lowercase; /* "Br. Fakture", "Sto / Kasir": sentence case, copy unchanged */
  }
  .k-table__grid th::first-letter { text-transform: uppercase; }
  .k-table__grid td {
    height: 52px;
    padding: var(--k-1) var(--k-2);
    border-bottom: 1px solid var(--k-line);
    font: 400 var(--k-t-sm)/var(--k-lh-sm) var(--k-font);
    vertical-align: middle;
  }
  /* 16 at the card edges and 16 between columns (8 a side), so a history
     row keeps every cell to two lines in the 944px card at 1366 with the
     order column open. */
  .k-table__grid tr > :first-child { padding-left: var(--k-4); }
  .k-table__grid tr > :last-child { padding-right: var(--k-4); }
  .k-table__grid tbody tr:last-child > td { border-bottom: 0; }
  .k-table__grid .k-table__num {
    text-align: right;
    font-variant-numeric: tabular-nums lining-nums;
    white-space: nowrap;
  }
  .k-table__grid .k-table__nums {
    font-variant-numeric: tabular-nums lining-nums;
    white-space: nowrap;
  }
  /* Date and time ("24. 9. 2026. 05:58:14"): one line when there is room,
     otherwise the date over the time (never split inside the date). */
  .k-table__grid .k-table__when {
    min-width: 112px;
    font-variant-numeric: tabular-nums lining-nums;
  }
  .k-table__grid .k-table__end {
    text-align: right;
    white-space: nowrap;
  }
  /* Invoice numbers: the sans face, tabular, slashed zero where the font
     has it (no monospace outside the receipt). When the row is short of
     room "RLCLBVG8-RLCLBVG8-1287" wraps at its hyphens; the 8.25em floor
     keeps it to two lines ("RLCLBVG8-" over "RLCLBVG8-1287"). */
  .k-table__grid .k-table__invoice {
    min-width: 8.25em;
    font-variant-numeric: tabular-nums lining-nums;
    font-feature-settings: "zero";
  }
  /* History "Sto / kasir": when the card has the room (944 at 1366 with
     the order column open), a first and last name stay on one line, so
     every cell keeps to two lines and the row to 52px. Narrower cards let
     it wrap rather than scroll. */
  @container (min-width: 936px) {
    .k-table__grid .k-table__who { min-width: 8.5em; }
  }
  .k-table__grid .k-table__strong { font-weight: 600; }
  .k-table__grid .k-table__meta {
    margin-top: var(--k-1);
    color: var(--k-ink-3);
    font: 400 var(--k-t-meta)/var(--k-lh-meta) var(--k-font);
  }
  /* Status: 600 in the colour the template writes (bridged --green, --red,
     --gold: all AA on white) behind a status dot of the same colour. */
  .k-table__grid .k-table__status {
    font-weight: 600;
    white-space: nowrap;
  }
  .k-table__status::before {
    content: "";
    display: inline-block;
    width: 8px;
    height: 8px;
    margin-right: var(--k-2);
    border-radius: 50%;
    background: currentColor;
    vertical-align: 1px;
  }
  .k-table__actions > * + * { margin-left: var(--k-1); }
  .k-table__grid .k-table__select {
    display: inline-block;
    width: auto;
    min-width: 152px;
  }
  .k-table__grid .k-table__empty {
    height: auto;
    padding: var(--k-6) var(--k-4);
    color: var(--k-slate);
    text-align: center;
  }
  .k-table__grid .k-table__empty--error { color: var(--k-danger); }

  /* 6.15 Lock screens (#staff-lock-screen, #saas-expired-lockscreen): paper
     backdrop, no blur, and a white card (radius 14, e3, 400 wide, padding
     32). JS keeps the display and opacity toggles and the fade; the inline
     display:flex that the Više lock-hide rule reads stays in the markup. */
  .k-lock {
    padding: var(--k-4);
    background: var(--k-paper);
  }
  .k-lock__card {
    display: flex;
    flex-direction: column;
    gap: var(--k-4);
    width: min(400px, 100%);
    max-height: 100%;
    overflow-y: auto;
    padding: var(--k-6);
    border-radius: var(--k-r-sheet);
    background: var(--k-surface);
    color: var(--k-ink);
    box-shadow: var(--k-e3);
  }
  /* The logo lockup (icons/logo.jpg, pre-cached by sw.js): its white
     margin trimmed, and the tagline too (unreadable at this size). */
  .k-lock__logo {
    display: block;
    align-self: center;
    width: 120px;
    height: 80px;
    object-fit: cover;
    object-position: 50% 25%;
  }
  .k-lock__title {
    margin: 0;
    color: var(--k-ink);
    font: 600 var(--k-t-lg)/var(--k-lh-lg) var(--k-font);
    text-align: center;
  }
  .k-lock__desc {
    margin: calc(-1 * var(--k-2)) 0 0;
    color: var(--k-slate);
    font: 400 var(--k-t-sm)/1.4 var(--k-font);
    text-align: center;
  }
  .k-lock .k-field { height: var(--k-h-key2); }
  .k-lock__submit {
    width: 100%;
    margin-top: var(--k-1);
  }

  /* 6.15a Staff PIN on #staff-lock-screen (spec 2026-10-10-staff-pin-login-design §3.1): the keypad panel and the
     username panel, one shown at a time; [hidden] must win over their display:flex (and over .k-btn's). Keys are at
     least 64 px: thumb size in the PDA app. */
  #staff-lock-screen [hidden] { display: none !important; }
  .k-lock__panel,
  .k-pin {
    display: flex;
    flex-direction: column;
    gap: var(--k-4);
  }
  .k-pin__dots {
    display: flex;
    justify-content: center;
    gap: var(--k-4);
    padding: var(--k-2) 0;
  }
  .k-pin__dots > span {
    width: 16px;
    height: 16px;
    border: 2px solid var(--k-ink);
    border-radius: 50%;
  }
  .k-pin__dots > span.is-filled { background: var(--k-ink); }
  .k-pin__dots.is-shaking { animation: k-pin-shake 400ms var(--k-ease); }
  .k-pin__error {
    margin: 0;
    color: var(--k-danger);
    font: 600 var(--k-t-sm)/1.4 var(--k-font);
    text-align: center;
  }
  .k-pin__pad {
    display: grid;
    grid-template-columns: repeat(3, minmax(64px, 1fr));
    gap: var(--k-3);
  }
  .k-pin__key {
    min-width: 64px;
    min-height: 64px;
    border: 1px solid var(--k-line);
    border-radius: var(--k-r-control);
    background: var(--k-sunken);
    color: var(--k-ink);
    font: 600 var(--k-t-xl)/1 var(--k-font);
    cursor: pointer;
    touch-action: manipulation;
  }
  .k-pin__key:active { background: var(--k-sunken-press); }
  .k-lock__switch {
    align-self: center;
    min-height: var(--k-hit);
    padding: 0 var(--k-2);
    border: 0;
    background: none;
    color: var(--k-ink);
    font: 600 var(--k-t-sm)/1.4 var(--k-font);
    text-decoration: underline;
    cursor: pointer;
  }

  /* Sign-in backdrop (2.55.1 photo, 2.56.0 choice): #staff-lock-screen only; the subscription and
     till-limit screens keep the plain paper. Layers, bottom to top: the still photo (always there,
     the fallback), then a video / the slideshow / the cinemagraph still (js/kasir-lock-bg.js sets
     data-lockbg to foto | video | hidup | cine and fills them), the theme tint (::before) and the
     vignette (::after). Siblings that share one negative z-index paint in tree order, so each layer
     has its own. All media is bundled under assets/ and pre-cached by sw.js: it plays offline.
     The container keeps its inline position:fixed; isolation keeps the negative z-index layers
     inside it, so the card (position:relative) always paints on top. */
  #staff-lock-screen {
    overflow: hidden;
    isolation: isolate;
    --k-lock-tint: var(--k-navy);
    --k-lock-tint-opacity: .32;
    --k-lock-card-rgb: 255, 255, 255;
    --k-lock-hole: none;
  }
  html[data-theme="oranye-klasik"] #staff-lock-screen { --k-lock-card-rgb: 255, 253, 249; }
  html[data-theme="zaitun"] #staff-lock-screen { --k-lock-card-rgb: 255, 254, 250; }
  html[data-theme="malam"] #staff-lock-screen {
    --k-lock-tint: #060a12;
    --k-lock-tint-opacity: .62;
    --k-lock-card-rgb: 19, 26, 38;
  }
  .k-lock__bg, .k-lock__video, .k-lock__still, .k-lock__hidup, .k-lock__hidup-img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    pointer-events: none;
    user-select: none;
  }
  .k-lock__bg {
    z-index: -5;
    object-position: 50% 45%;
    transform: scale(1.04);          /* hides the soft edge the blur leaves */
    filter: blur(2.5px) saturate(.85) brightness(.92);
  }
  .k-lock__video { z-index: -4; display: none; transform: scale(1.02); filter: saturate(.9) brightness(.9); }
  .k-lock__hidup { z-index: -4; display: none; }
  .k-lock__still {
    z-index: -3;
    display: none;
    -webkit-mask-image: var(--k-lock-hole);
    mask-image: var(--k-lock-hole);
    filter: saturate(.9) brightness(.9);
  }
  #staff-lock-screen[data-lockbg="video"] .k-lock__video,
  #staff-lock-screen[data-lockbg="cine"] .k-lock__video { display: block; }
  #staff-lock-screen[data-lockbg="cine"] .k-lock__still[data-ready] { display: block; }
  #staff-lock-screen[data-lockbg="hidup"] .k-lock__hidup { display: block; }
  /* Žive fotografije: the active photo zooms slowly while the next fades in over it. */
  .k-lock__hidup-img {
    opacity: 0;
    transition: opacity 1.8s ease;
    filter: saturate(.9) brightness(.92);
    will-change: transform, opacity;
  }
  .k-lock__hidup-img.is-active { opacity: 1; animation: k-lock-kb-a 10s ease-out forwards; }
  .k-lock__hidup-img--alt.is-active { animation-name: k-lock-kb-b; }
  @keyframes k-lock-kb-a { from { transform: scale(1) translate(0, 0); } to { transform: scale(1.14) translate(-1.5%, 1%); } }
  @keyframes k-lock-kb-b { from { transform: scale(1.14) translate(1.5%, -1%); } to { transform: scale(1) translate(0, 0); } }
  #staff-lock-screen::before,
  #staff-lock-screen::after {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
  }
  #staff-lock-screen::before {
    z-index: -2;
    background: var(--k-lock-tint);
    opacity: var(--k-lock-tint-opacity);
  }
  #staff-lock-screen::after {
    z-index: -1;
    background:
      radial-gradient(70% 60% at 50% 0%, rgba(255, 214, 140, .16), transparent 70%),
      radial-gradient(120% 95% at 50% 55%, transparent 50%, rgba(0, 0, 0, .45));
  }
  /* The card: frosted glass over the backdrop (2.56.0). Visok kontrast keeps it solid. */
  #staff-lock-screen .k-lock__card {
    position: relative;
    background: rgba(var(--k-lock-card-rgb), .66);
    -webkit-backdrop-filter: blur(18px) saturate(1.3);
    backdrop-filter: blur(18px) saturate(1.3);
    border: 1px solid rgba(255, 255, 255, .42);
    box-shadow: 0 30px 60px rgba(0, 0, 0, .35), inset 0 1px 0 rgba(255, 255, 255, .55);
  }
  html[data-theme="kontras-tinggi"] #staff-lock-screen .k-lock__card {
    background: var(--k-surface);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    border: 2px solid var(--k-ink);
  }
  /* The transparent logo (icons/logo.png, square): the 120x80 window keeps the mark and the
     wordmark and crops the tagline, as the jpg crop did. */
  #staff-lock-screen .k-lock__logo { object-fit: cover; object-position: 50% 30%; }
  html[data-theme="malam"] #staff-lock-screen .k-lock__logo {
    padding: 6px 12px;
    border-radius: 14px;
    background: rgba(255, 255, 255, .94);   /* the navy mark needs a light ground on the dark glass */
  }
  /* The sign-in card's fields and key (2.56.0): one width, one height, one radius; an icon leads
     each field, the labels are small caps, the focus ring is brass. Only this screen. */
  #staff-lock-screen .k-lock__card { gap: var(--k-4); padding: var(--k-6); }
  #staff-lock-screen .k-lock__title { font-size: 22px; }
  #staff-lock-screen .k-lock__desc { margin-bottom: var(--k-1); }
  #staff-lock-screen .k-group { display: grid; gap: 6px; }
  #staff-lock-screen .k-label {
    margin: 0;
    color: var(--k-slate);
    font: 600 12px/1.2 var(--k-font);
    letter-spacing: .05em;
    text-transform: uppercase;
  }
  .k-lock__field { position: relative; }
  .k-lock__field > i {
    position: absolute;
    top: 50%;
    left: 14px;
    transform: translateY(-50%);
    font-size: 18px;
    line-height: 1;
    color: var(--k-ink-3);
    pointer-events: none;
  }
  #staff-lock-screen .k-field {
    height: 48px;
    padding-left: 42px;
    border-radius: 10px;
    border-color: var(--k-line-strong);
    background: rgba(var(--k-lock-card-rgb), .88);
    transition: border-color .15s ease, box-shadow .15s ease;
  }
  #staff-lock-screen .k-field:focus {
    outline: none;
    border-color: var(--k-brass);
    box-shadow: 0 0 0 3px rgba(201, 151, 59, .28);
  }
  #staff-lock-screen .k-lock__submit { height: 50px; margin-top: var(--k-2); border-radius: 10px; }
  html[data-theme="kontras-tinggi"] #staff-lock-screen .k-field { background: var(--k-surface); }
  @media (prefers-reduced-motion: reduce) {
    .k-lock__hidup-img.is-active { animation: none; transform: none; }
  }

  /* 6.16 Toasts and the message box (js/app.js, S8.1). app.js writes their
     whole look inline, because admin.html and dapur.html share it and do
     not load this file (its colours read these tokens first). Here they
     get what an inline style cannot give: the state glyph, the fade in,
     and pressed and hover colours. The focus ring is in 4.3. */
  .k-toast {
    display: flex;
    align-items: flex-start;
    gap: var(--k-3);
    font-variant-numeric: tabular-nums lining-nums;
    animation: k-fade-in var(--k-dur) var(--k-ease);
  }
  .k-toast::before {
    flex-shrink: 0;
    font: 20px/20px "tabler-icons";
  }
  .k-toast--info::before { content: "\eac5"; }    /* ti-info-circle */
  .k-toast--success::before { content: "\ea67"; } /* ti-circle-check */
  .k-toast--warning::before { content: "\ea06"; } /* ti-alert-triangle */
  .k-toast--error::before { content: "\ea05"; }   /* ti-alert-circle */
  /* Message box keys: app.js paints them with var(--k-msg-btn-bg, <fill>),
     so a state only has to redefine that property. Colour only, no
     transform (spec 6.1). */
  .k-msg__btn { -webkit-tap-highlight-color: transparent; }
  @media (hover: hover) and (pointer: fine) {
    .k-msg__btn--primary:hover { --k-msg-btn-bg: var(--k-navy-raised); }
    .k-msg__btn--danger:hover { --k-msg-btn-bg: var(--k-danger-ink); }
    .k-msg__btn--secondary:hover { --k-msg-btn-bg: var(--k-sunken); }
  }
  .k-msg__btn--primary:active { --k-msg-btn-bg: var(--k-navy-raised); }
  .k-msg__btn--danger:active { --k-msg-btn-bg: var(--k-danger-ink); }
  .k-msg__btn--secondary:active { --k-msg-btn-bg: var(--k-sunken-press); }


  /* 4.5 Surfaces (spec section 7) */

  /* #4 Training banner: warn fill, navy 15/600, left-aligned. JS replaces
     its textContent (the copy arrives in caps), so the icon comes from
     ::before and sentence case from CSS. Inline display:none and
     position:sticky stay in the markup. */
  #training-mode-banner {
    flex-shrink: 0;
    min-height: 36px;
    padding: var(--k-2) var(--k-4) var(--k-2) calc(var(--k-4) + 20px + var(--k-2));
    background: var(--k-warn-fill);
    color: var(--k-on-warn-fill);
    font: 600 var(--k-t-sm)/var(--k-lh-sm) var(--k-font);
    text-align: left;
    text-transform: lowercase;
  }
  #training-mode-banner::first-letter { text-transform: uppercase; }
  #training-mode-banner::before {
    content: "\ecf7"; /* ti-school */
    position: absolute;
    top: var(--k-2);
    left: var(--k-4);
    font: 20px/20px "tabler-icons";
    text-transform: none;
  }

  /* #5 L-PFR banner: the warning glyph (the overrides are in LEGACY
     OVERRIDES). A ::before, because the JS `background` shorthand would
     reset a background-image. White via currentColor. */
  #lpfr-alert-banner::before {
    content: "\ea06"; /* ti-alert-triangle */
    position: absolute;
    top: 10px;
    left: var(--k-4);
    font: 20px/21px "tabler-icons";
  }

  /* #6-7 Header .k-bar: 52px white row, 1px line below (allure's
     .pos-header border reads the bridged --border). Order: back, brand,
     status group, spacer, clock, Odjava, Više. */
  .k-bar {
    flex-wrap: nowrap;
    gap: var(--k-2);
    box-shadow: none;
    color: var(--k-ink);
  }
  .k-brand {
    display: flex;
    align-items: center;
    gap: var(--k-2);
    flex: 0 1000 auto; /* the shop name gives way first */
    min-width: 28px;
    margin: 0;
    font-size: var(--k-t-md);
    line-height: var(--k-lh-md);
  }
  .k-brand__mark {
    display: block;
    flex-shrink: 0;
    width: 28px;
    height: 28px;
  }
  .k-brand__shop {
    display: block;
    min-width: 0;
    max-width: 240px;
    overflow: hidden;
    color: var(--k-ink);
    font: 600 var(--k-t-md)/var(--k-lh-md) var(--k-font);
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .k-bar__status {
    display: flex;
    align-items: center;
    gap: var(--k-2);
    flex-shrink: 0;
  }
  .k-bar__spacer {
    flex: 1 1 0;
    min-width: 0;
  }
  .k-clock {
    flex-shrink: 0;
    color: var(--k-ink);
    font: 600 var(--k-t-md)/1 var(--k-font);
    font-variant-numeric: tabular-nums lining-nums;
  }
  /* The header touches the top edge of the page: -6px would clip the bubble.
     With a visible label, the bubble sits over extra right padding, not text. */
  .k-bar__alert .k-count { top: -4px; }
  .k-bar__alert { padding-right: var(--k-5); }
  .k-bar__logout {
    flex: 0 1 auto;
    min-width: var(--k-hit);
  }
  .k-bar__logout .k-btn__label { max-width: 160px; }
  /* L-PFR pill, by id (JS owns its className): ok = ok-ink on ok-tint,
     offline = solid danger with white text (an emergency). Neutralises
     .ml-auto from the className JS writes. */
  .k-bar #lpfr-status-badge {
    --k-pill-bg: var(--k-ok-tint);
    --k-pill-fg: var(--k-ok-ink);
    display: inline-flex;
    align-items: center;
    gap: var(--k-2);
    flex-shrink: 0;
    height: 32px;
    margin-left: 0;
    padding: 0 var(--k-3);
    border-radius: var(--k-r-round);
    font: 600 var(--k-t-sm)/1 var(--k-font-tight);
    white-space: nowrap;
  }
  .k-bar #lpfr-status-badge.badge-red {
    --k-pill-bg: var(--k-danger);
    --k-pill-fg: var(--k-on-danger);
  }
  /* The dot colour is JS inline var(--green) / var(--red) (bridged). */
  #lpfr-status-dot {
    flex-shrink: 0;
    width: 8px;
    height: 8px;
    margin: 0;
  }
  .k-bar #lpfr-status-badge.badge-red #lpfr-status-dot { box-shadow: 0 0 0 2px var(--k-on-danger); }
  .k-bar .k-pill { height: 32px; }
  /* Offline queue: the spinner is a real progress indicator (static under
     reduced motion). */
  #offline-sync-badge > i { animation: k-spin 1.2s linear infinite; }

  /* #12 View tabs: 48px strip (allure's .view-tabs paints it white with the
     bridged line below), scrolls sideways instead of wrapping. The selected
     tab gets a 3px navy inset bar: no border, so no 2px shift. */
  .k-tabs {
    flex-shrink: 0;
    align-items: stretch;
    gap: var(--k-1);
    height: var(--k-h-tabs);
    padding: 0 var(--k-3);
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x proximity;
    scrollbar-width: none;
  }
  .k-tabs::-webkit-scrollbar { display: none; }
  .k-tab {
    flex-shrink: 0;
    gap: var(--k-2);
    min-height: var(--k-hit);
    padding: 0 var(--k-3);
    border: 0;
    border-radius: var(--k-r-control) var(--k-r-control) 0 0;
    background: transparent;
    color: var(--k-slate);
    font: 600 var(--k-t-sm)/var(--k-lh-sm) var(--k-font-tight);
    white-space: nowrap;
    scroll-snap-align: start;
    -webkit-tap-highlight-color: transparent;
  }
  .k-tab > i {
    font-size: 18px;
    line-height: 1;
  }
  /* "Mapa Stolova", "Istorija Transakcija": sentence case, copy unchanged. */
  .k-tab > span { text-transform: lowercase; }
  .k-tab > span::first-letter { text-transform: uppercase; }
  .k-tab.active {
    border: 0;
    background: transparent;
    color: var(--k-ink);
    box-shadow: inset 0 -3px 0 var(--k-ink);
  }
  @media (hover: hover) and (pointer: fine) {
    .k-tab:hover { background: var(--k-sunken); }
  }
  .k-tab:active { background: var(--k-sunken-press); }
  /* The strip scrolls sideways (a clipping box): the ring goes inside the tab. */
  .k-tabs .k-tab:focus-visible { outline-offset: -2px; }

  /* #8-11 Order column: white and flat, 360 / 396 / 440px wide at 1024 /
     1366 / 1920 (--k-cart). The collapse keeps its behaviour (the inline
     .cart-sidebar.hidden `width: 0 !important` still wins) but is instant:
     no 0.35s per-frame reflow, no wrong-tap window. Allure paints the
     background and right edge from the bridged --nav and --border. */
  .cart-sidebar {
    width: var(--k-cart);
    box-shadow: none;
    color: var(--k-ink);
    transition: none;
  }

  /* #8 Order header: table (17/700 navy) and waiter (13 slate); Očisti is
     a danger-ghost button. */
  .cart-header {
    flex-shrink: 0;
    gap: var(--k-3);
    min-height: 60px;
    padding: var(--k-2) var(--k-3);
    border-bottom: 1px solid var(--k-line);
    background: var(--k-surface);
  }
  .k-cart-id {
    flex: 1 1 auto;
    min-width: 0;
  }
  .k-cart-id__table {
    margin: 0;
    overflow: hidden;
    color: var(--k-ink);
    font: 700 var(--k-t-md)/var(--k-lh-md) var(--k-font);
    font-variant-numeric: tabular-nums lining-nums;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .k-cart-id__waiter {
    display: block;
    overflow: hidden;
    color: var(--k-slate);
    font: 400 var(--k-t-meta)/var(--k-lh-meta) var(--k-font);
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .k-cart-id__waiter strong { font-weight: 600; }

  /* #9 Order lines: the list scrolls; rows are styled in 6.8. */
  .cart-items {
    min-height: 0;
    padding: 0;
    gap: 0;
    overscroll-behavior: contain;
  }
  .k-cart-empty {
    padding: 48px var(--k-4);
    color: var(--k-ink-3);
    text-align: center;
  }
  .k-cart-empty > i {
    display: block;
    margin-bottom: var(--k-3);
    font-size: 32px;
    line-height: 1;
  }
  .k-cart-empty > p {
    margin: 0;
    color: var(--k-slate);
    font: 400 var(--k-t-sm)/var(--k-lh-sm) var(--k-font);
  }

  /* #10 Footer, top to bottom: extras, VAT, discount row, actions, the
     check. White (the grey band is gone). position:relative anchors the
     fiscal-fields sheet, which opens upward over the order lines. */
  .cart-footer {
    position: relative;
    flex-shrink: 0;
    padding: var(--k-2) 0 0;
    border-top: 1px solid var(--k-line);
    background: var(--k-surface);
  }
  .k-extras {
    display: flex;
    gap: var(--k-2);
    margin-bottom: var(--k-2);
    padding: 0 var(--k-3);
  }
  .k-fiscal {
    flex: 1 1 0;
    min-width: 0;
  }
  .k-disclosure {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--k-2);
    height: var(--k-hit);
    padding: 0 var(--k-2) 0 var(--k-3);
    border-radius: var(--k-r-control);
    background: var(--k-sunken);
    color: var(--k-ink);
    font: 600 var(--k-t-sm)/var(--k-lh-sm) var(--k-font);
    list-style: none;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }
  .k-disclosure::-webkit-details-marker { display: none; }
  .k-disclosure > i {
    flex-shrink: 0;
    color: var(--k-slate);
    font-size: 20px;
    line-height: 1;
  }
  .k-disclosure__label {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  /* CSS chevron (last flex item): up while closed, because the sheet opens
     upward; down while open. */
  .k-disclosure::before {
    content: "\ea62"; /* ti-chevron-up */
    order: 1;
    flex-shrink: 0;
    color: var(--k-slate);
    font: 18px/1 "tabler-icons";
  }
  .k-fiscal[open] > .k-disclosure::before { content: "\ea5f"; } /* ti-chevron-down */
  .k-fiscal[open] > .k-disclosure { background: var(--k-sunken-press); }
  @media (hover: hover) and (pointer: fine) {
    .k-disclosure:hover { background: var(--k-sunken-press); }
  }
  .k-disclosure:active { background: var(--k-sunken-press); }
  /* Fiscal data entered: a navy dot on the icon, visible with the sheet
     closed. */
  #fiscal-fields:has(#fiscal-buyer-id:not(:placeholder-shown), #fiscal-buyer-optional:not(:placeholder-shown), #fiscal-referent:not(:placeholder-shown), #fiscal-avans:checked) > .k-disclosure::after {
    content: "";
    position: absolute;
    top: var(--k-dot-top, var(--k-2));
    left: var(--k-dot-left, 28px);
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--k-navy);
    box-shadow: 0 0 0 2px var(--k-sunken);
  }
  /* The sheet: e2, anchored 8px above the footer, never taller than the
     room above it (100% here is the footer's height). */
  .k-fiscal[open] > .k-fiscal__sheet {
    position: absolute;
    right: var(--k-2);
    bottom: calc(100% + var(--k-2));
    left: var(--k-2);
    z-index: 2;
    display: flex;
    flex-direction: column;
    gap: var(--k-2);
    max-height: calc(100vh - var(--k-h-head) - 100% - var(--k-4));
    overflow-y: auto;
    padding: var(--k-3);
    border: 1px solid var(--k-line);
    border-radius: var(--k-r-card);
    background: var(--k-surface);
    box-shadow: var(--k-e2);
  }
  .k-fiscal__check {
    display: flex;
    align-items: center;
    gap: var(--k-3);
    flex-shrink: 0;
    min-height: var(--k-hit);
    color: var(--k-ink);
    font: 400 var(--k-t-sm)/var(--k-lh-sm) var(--k-font);
    cursor: pointer;
  }
  .k-fiscal__check > [type="checkbox"] {
    flex-shrink: 0;
    width: 20px;
    height: 20px;
    margin: 0;
    accent-color: var(--k-ink);
  }
  /* JS flips its inline display between none and flex. */
  .k-fiscal__dt {
    flex-direction: column;
    gap: var(--k-1);
    flex-shrink: 0;
    color: var(--k-slate);
    font: 600 var(--k-t-meta)/var(--k-lh-meta) var(--k-font);
  }
  .k-fiscal__sheet > .k-field { flex-shrink: 0; }
  /* Partial advance (spec §8): one row per VAT rate of the cart, the amount field on the right. */
  .k-fiscal__advlines { display: flex; flex-direction: column; gap: var(--k-1); }
  .k-fiscal__advrow {
    display: flex;
    align-items: center;
    gap: var(--k-2);
    color: var(--k-ink);
    font: 400 var(--k-t-sm)/var(--k-lh-sm) var(--k-font);
  }
  .k-fiscal__advrow > span { flex: 1 1 auto; min-width: 0; }
  .k-fiscal__advrow > .k-field { flex: 0 0 132px; width: 132px; }
  .k-fiscal__hint { color: var(--k-slate); font: 600 var(--k-t-meta)/var(--k-lh-meta) var(--k-font); }
  /* Buyer id (spec §4): the TU 9.8 code picker beside the number. */
  .k-fiscal__buyer { display: flex; gap: var(--k-2); flex-shrink: 0; }
  .k-fiscal__buyer > select { flex: 0 0 38%; min-width: 0; }
  .k-fiscal__buyer > input { flex: 1 1 auto; min-width: 0; }
  .k-fiscal__firm { align-self: flex-start; flex-shrink: 0; }
  .k-firm-prompt { align-self: center; margin-top: var(--k-2); }
  /* Popust key beside the fiscal disclosure (openDiscountSheet): 44px, its
     badge shows the total taken off the bill. */
  .k-discount {
    flex: 0 0 auto;
    height: var(--k-hit);
    padding: 0 var(--k-3);
  }
  #discount-key-badge {
    height: 28px;
    margin-left: var(--k-1);
    font-variant-numeric: tabular-nums lining-nums;
  }
  /* A discounted order line: the original price struck through, the new
     price, and the discount as a small green tag. */
  .cart-item-details s { color: var(--k-ink-3); text-decoration: line-through; }
  .k-discount-tag {
    display: inline-block;
    padding: 0 var(--k-1);
    border-radius: var(--k-r-control);
    background: var(--k-ok-tint);
    color: var(--k-ok-ink);
  }
  /* Text segments in the discount sheet (the icon segments stay 44x44);
     three preset keys in a row. */
  .k-seg--text { align-self: flex-end; }
  .k-seg__btn--text {
    width: auto;
    padding: 0 var(--k-3);
    font: 600 var(--k-t-sm)/var(--k-lh-sm) var(--k-font);
  }
  .k-quick--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .k-quick--3 > .k-quick__key {
    height: auto;
    min-height: 52px;
    padding: var(--k-2);
    font-size: var(--k-t-meta);
    line-height: var(--k-lh-meta);
    white-space: normal;
    text-align: center;
  }

  /* VAT rows (renderVatSummary, untouched): 13px ink-3, amounts right in
     tabular figures; one column below 1300px (4.6 makes it two above). */
  #summary-vat-rows {
    margin-bottom: var(--k-2);
    padding: 0 var(--k-3);
  }
  #summary-vat-rows:empty { display: none; }
  #summary-vat-rows > .summary-row {
    align-items: baseline;
    gap: var(--k-2);
    margin: 0;
    color: var(--k-ink-3);
    font: 400 var(--k-t-meta)/var(--k-lh-meta) var(--k-font);
    font-variant-numeric: tabular-nums lining-nums;
  }
  /* A long label (id: "Dasar Pengenaan PDV Е 10%") wraps rather than
     losing its rate to an ellipsis. */
  #summary-vat-rows > .summary-row > span:first-child {
    min-width: 0;
    overflow-wrap: break-word;
  }
  #summary-vat-rows > .summary-row > span:last-child {
    flex-shrink: 0;
    white-space: nowrap;
  }
  /* Discount row (renderDiscountSummary): ok colour; JS flips its inline
     display. The line prices already carry the discount. */
  .k-discount-row {
    gap: var(--k-2);
    margin: 0 0 var(--k-2);
    padding: 0 var(--k-3);
    color: var(--k-ok);
    font: 600 var(--k-t-sm)/var(--k-lh-sm) var(--k-font);
    font-variant-numeric: tabular-nums lining-nums;
  }

  /* #11 Actions, above the check: save draft (secondary, flexible),
     predračun and storno (44px icon keys; storno only for Administrator). */
  .k-actions {
    display: flex;
    gap: var(--k-2);
    margin-bottom: var(--k-2);
    padding: 0 var(--k-3);
  }
  .k-actions__save {
    flex: 1 1 auto;
    min-width: 0;
  }
  /* "Sačuvaj Račun (Nacrt)": sentence case, copy unchanged. */
  .k-actions__save .k-btn__label { text-transform: lowercase; }
  .k-actions__save .k-btn__label::first-letter { text-transform: uppercase; }

  /* #13 Floor plan (renderFloorplan): tables at their admin-set positions
     and sizes on the paper floor. A free table is white with a line-strong
     edge; an open bill is SOLID NAVY with a white label and a white total,
     so from across the room the navy shapes are the tables still owing.
     The canvas keeps position:relative, no padding, no transform/zoom and a
     1px border (colour in LEGACY OVERRIDES); it scrolls instead of
     clipping, so tables past the right edge stay reachable when the order
     column is open. */
  .k-floor {
    gap: var(--k-3);
    padding: var(--k-3);
  }
  #floorplan-canvas {
    border-radius: 0;
    overflow: auto;
    overscroll-behavior: contain;
    scrollbar-color: var(--k-line-strong) transparent;
  }

  /* 6.10 Tables. JS rebuilds the className on every render (shape, free /
     occ, draggable) and writes left/top/width/height inline. Each table is
     a size container, so its label scales with the admin-set size. */
  .floor-table {
    border: 1.5px solid var(--k-line-strong);
    border-radius: var(--k-r-card);
    background: var(--k-surface);
    color: var(--k-ink);
    box-shadow: none;
    transition: none;
    -webkit-tap-highlight-color: transparent;
  }
  .floor-table:not(.line-h, .line-v) { container-type: size; }
  /* Dining mode: a pan that starts on a table scrolls the floor (the
     inline <style> sets touch-action:none for the layout-edit drag). */
  .floor-table:not(.draggable) { touch-action: manipulation; }
  /* No status dot and no infinite pulse: the fill carries the state. */
  .floor-table.free::before,
  .floor-table.occ::before {
    content: none;
    animation: none;
  }
  /* An invisible 1px point 12px past each table's corner, so the canvas
     scrolls a little beyond the last table instead of stopping flush on
     its edge (the canvas itself takes no padding). */
  .floor-table::after {
    content: "";
    position: absolute;
    right: calc(-1 * var(--k-3));
    bottom: calc(-1 * var(--k-3));
    width: 1px;
    height: 1px;
    pointer-events: none;
  }
  .floor-table.free { border-color: var(--k-line-strong); }
  .floor-table-label {
    max-width: 100%;
    overflow: hidden;
    color: inherit;
    font: 600 clamp(var(--k-t-sm), 18cqmin, var(--k-t-lg))/1.2 var(--k-font-tight);
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .floor-table-seats {
    max-width: 100%;
    overflow: hidden;
    color: var(--k-ink-3);
    font: 400 var(--k-t-meta)/var(--k-lh-meta) var(--k-font);
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  /* Open bill: .occ, or a bill on the table while the status lags. */
  .floor-table:is(.occ, :has(.table-bill-badge)) {
    border-color: var(--k-ink);
    background: var(--k-navy);
    color: var(--k-on-navy);
    box-shadow: var(--k-e1);
  }
  /* The waiter line ("By: Milica", frozen copy). */
  .floor-table:is(.occ, :has(.table-bill-badge)) .floor-table-seats {
    color: var(--k-slab-ink-2);
    font: 600 var(--k-t-meta)/var(--k-lh-meta) var(--k-font-tight);
  }
  /* The bill: plain white figures, "RSD" quieter; no pill, no receipt icon
     (brass stays reserved for money actions). */
  .table-bill-badge {
    display: flex;
    align-items: baseline;
    max-width: 100%;
    color: var(--k-on-navy);
    font: 700 clamp(var(--k-t-sm), 16cqmin, var(--k-t-md))/1.2 var(--k-font);
    font-variant-numeric: tabular-nums lining-nums;
    white-space: nowrap;
  }
  .table-bill-badge > i { display: none; }
  /* Figures first; the RSD unit stands beside them only when it fits
     whole. Otherwise it wraps to a second row that is clipped away, so a
     narrow table shows "12.340", never "12.340 R...". */
  .table-bill-badge > span {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: center;
    justify-content: safe center;
    row-gap: 1em;
    min-width: 0;
    max-height: 1.2em;
    max-height: 1lh;
    overflow: hidden;
  }
  .table-bill-badge > span > span {
    margin-left: var(--k-1);
    color: var(--k-slab-ink-2);
    font: 600 var(--k-t-meta)/1 var(--k-font);
  }
  @media (hover: hover) and (pointer: fine) {
    .floor-table.free:hover { border-color: var(--k-slate); }
  }
  .floor-table.free:active { background: var(--k-sunken); }
  .floor-table:is(.occ, :has(.table-bill-badge)):active {
    border-color: var(--k-navy-raised);
    background: var(--k-navy-raised);
  }
  /* Reservation time: an info chip inside the top-right corner. */
  .k-res-chip {
    position: absolute;
    top: var(--k-1);
    right: var(--k-1);
    z-index: 1;
    display: flex;
    flex-shrink: 0;
    align-items: center;
    gap: var(--k-1);
    height: 20px;
    padding: 0 var(--k-1);
    border-radius: var(--k-r-control);
    background: var(--k-info-tint);
    color: var(--k-info);
    font: 700 var(--k-t-meta)/1 var(--k-font);
    font-variant-numeric: tabular-nums lining-nums;
    white-space: nowrap;
  }
  .k-res-chip > i {
    font-size: 14px;
    line-height: 1;
  }
  /* The label and the bill never shrink (the label's overflow:hidden would
     otherwise let a crowded column squash and clip it). */
  .floor-table-label,
  .table-bill-badge { flex-shrink: 0; }
  /* Corner chip: it owns a 28px band at the top of the table (4 inset +
     20 chip + 4 gap). The label's top margin is that band, so the stack
     is centred in the space below it and can never run under the chip. */
  .k-res-chip ~ .floor-table-label { margin-top: calc(20px + 2 * var(--k-1)); }
  /* A sale paid while the server was out of reach, not fiscalized yet (2.20.2): the table is
     not free. Amber outline while no new bill sits on it; a warn chip in the bottom-left corner
     in every case (a new guests' bill on the same table shows navy plus the chip). */
  .floor-table.queued {
    border-color: var(--k-warn-line);
    border-style: dashed;
    background: var(--k-warn-tint);
    color: var(--k-warn-ink);
  }
  .floor-table.queued .floor-table-seats { color: var(--k-warn-ink); }
  /* The chip (2.21.1): the clock and ONE label that fits whole. The full text shows only on tables
     at least 148px wide (the longest language, "awaiting fiscalization"); below that the short word
     ("čeka"), below 60px the clock alone (container rules below). A label that still does not fit
     (a longer language) wraps onto a second row that is clipped away, so the chip never shows a
     cut word; the full text is the chip's title and aria-label. */
  .k-queued-chip {
    position: absolute;
    left: var(--k-1);
    bottom: var(--k-1);
    z-index: 1;
    display: flex;
    flex-wrap: wrap;
    flex-shrink: 0;
    align-items: center;
    justify-content: center;
    column-gap: var(--k-1);
    row-gap: 20px;
    max-width: calc(100% - 2 * var(--k-1));
    height: 20px;
    padding: 0 var(--k-1);
    overflow: hidden;
    border-radius: var(--k-r-control);
    background: var(--k-warn-fill);
    color: var(--k-on-warn-fill);
    font: 600 var(--k-t-meta)/20px var(--k-font-tight);
  }
  .k-queued-chip > i { font-size: 14px; line-height: 20px; }
  .k-queued-chip > span { white-space: nowrap; }
  .k-queued-chip__full { display: none; }
  /* Tall rect tables: the chip owns a 28px band at the bottom (4 inset + 20 chip + 4 gap), like the
     reservation chip at the top; the stack is centred above it and never runs under the chip. */
  .floor-table:not(.round) > :has(+ .k-queued-chip) { margin-bottom: calc(20px + 2 * var(--k-1)); }
  /* Round tables (the box corner lies outside the circle): the chip is the last line of the
     centred stack, inside the circle, as the reservation chip is the first. */
  .floor-table.round > .k-queued-chip {
    position: static;
    margin-top: var(--k-1);
  }
  /* Sales paid offline waiting too long (over an hour): a red bar under the header, with Retry. */
  .k-offline-banner {
    display: flex;
    align-items: center;
    gap: var(--k-3);
    padding: var(--k-2) var(--k-4);
    background: var(--k-danger);
    color: var(--k-on-danger);
    font: 600 var(--k-t-md)/var(--k-lh-body) var(--k-font);
  }
  .k-offline-banner > i { font-size: 20px; line-height: 1; }
  .k-offline-banner > span { flex: 1 1 auto; min-width: 0; }
  .k-offline-banner .k-btn { background: var(--k-surface); color: var(--k-ink); border-color: var(--k-surface); }
  /* Local queue rows in Open orders: a sale paid offline, or a bill saved offline, not synced yet. */
  .k-oq-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--k-3);
    align-items: center;
    justify-content: space-between;
    padding: 12px 16px;
    border: 1px solid var(--k-warn-line);
    border-radius: 10px;
    background: var(--k-warn-tint);
    color: var(--k-ink);
  }
  .k-oq-row__main { flex: 1 1 260px; min-width: 0; }
  .k-oq-row__title { font: 700 15px/1.3 var(--k-font); }
  .k-oq-row__reason { margin-top: 8px; width: fit-content; max-width: 100%; padding: 2px 8px; border-radius: 6px; background: var(--k-warn-fill); color: #000; font: 600 13px/1.35 var(--k-font); }
  .k-oq-row__reason--error { background: var(--k-danger-tint); color: var(--k-danger); }
  .k-oq-row__meta { margin-top: 8px; color: var(--k-slate); font: 400 13px/1.3 var(--k-font); font-variant-numeric: tabular-nums; }
  /* Round tables (the box corner lies outside the circle): the chip is the
     first line of the centred stack instead, sitting at the top of the
     circle; flex items cannot overlap, so it never covers the label. */
  .floor-table.round > .k-res-chip {
    position: static;
    margin-bottom: var(--k-1);
  }
  .floor-table.round > .k-res-chip ~ .floor-table-label { margin-top: 0; }
  /* Walls: bars (fill in LEGACY OVERRIDES); the name sits on a white tag. */
  .floor-table:is(.line-h, .line-v) { border-radius: 2px; }
  .k-wall-label {
    padding: 0 var(--k-2);
    border: 1px solid var(--k-line);
    border-radius: var(--k-r-control);
    background: var(--k-surface);
    color: var(--k-slate);
    font: 600 var(--k-t-meta)/20px var(--k-font);
    white-space: nowrap;
    pointer-events: none;
  }
  /* Small tables: seats (or the waiter line) go below 64px of height, the
     RSD unit and the chip's clock below 72px of width, so label, bill and
     time keep their room. */
  @container (max-height: 64px) {
    .floor-table-seats { display: none; }
  }
  @container (max-width: 72px) {
    .table-bill-badge > span > span,
    .k-res-chip > i { display: none; }
  }
  /* Reserved short tables (64px or less inside, such as the 65x55 and
     75x60 default tables) have no room for a corner band plus two lines:
     the chip joins the stack there too, as on round tables, at 16px with
     tight lines, so time, label and bill fit one above the other down to
     a 55x50 bar table (47px inside). */
  @container (max-height: 64px) {
    .k-res-chip { position: static; }
    :is(.floor-table, .floor-table.round) > .k-res-chip {
      height: 16px;
      margin-bottom: 1px;
    }
    .k-res-chip ~ .floor-table-label { margin-top: 0; }
    .k-res-chip ~ :is(.floor-table-label, .table-bill-badge) { line-height: 1; }
  }
  /* A reservation on a table with an open bill: the waiter line gives way
     first (label, bill and time are what the cashier needs) until the
     table is tall enough for all four lines: 88px inside for a rect table,
     116px for a round one, whose circle narrows towards top and bottom. */
  @container (max-height: 88px) {
    .k-res-chip ~ .floor-table-seats:has(~ .table-bill-badge) { display: none; }
  }
  @container (max-height: 116px) {
    .floor-table.round > .k-res-chip ~ .floor-table-seats:has(~ .table-bill-badge) { display: none; }
  }
  /* A round table up to 96px across drops the chip's clock (the chip is
     then about 40px) and the RSD unit, because the circle narrows above
     and below its middle: chip and bill stay on the navy, never on paper. */
  @container (max-width: 96px) {
    .floor-table.round > .k-res-chip > i,
    .floor-table.round > .table-bill-badge > span > span { display: none; }
  }
  /* "čeka fiskalizaciju" (2.21.1): the full text from 148px across (180px on a round table, whose
     circle narrows towards the chip at the bottom), the clock alone below 60px. */
  @container (min-width: 148px) {
    .k-queued-chip__full { display: inline; }
    .k-queued-chip__short { display: none; }
  }
  @container (min-width: 148px) and (max-width: 179px) {
    .floor-table.round > .k-queued-chip > .k-queued-chip__full { display: none; }
    .floor-table.round > .k-queued-chip > .k-queued-chip__short { display: inline; }
  }
  @container (max-width: 59px) {
    .k-queued-chip__short { display: none; }
  }
  /* Short rect tables (88px or less inside) have no room for the corner band: the chip joins the
     stack as its last line, and on a table with new guests' bill the waiter line gives way first
     (label, bill and the chip are what the cashier needs). */
  @container (max-height: 88px) {
    .k-queued-chip { position: static; margin-top: var(--k-1); }
    .floor-table:not(.round) > :has(+ .k-queued-chip) { margin-bottom: 0; }
    .floor-table-seats:has(~ .table-bill-badge):has(~ .k-queued-chip) { display: none; }
  }
  /* A round table up to 80px across: the seats line gives way, so the chip stays inside the circle
     where it narrows towards the bottom; with a reservation chip above as well, the clock alone. */
  @container (max-width: 80px) {
    .floor-table.round > .floor-table-seats:has(~ .k-queued-chip) { display: none; }
    .floor-table.round > .k-res-chip ~ .k-queued-chip > .k-queued-chip__short { display: none; }
  }

  /* Legend: a flat 36px row on the floor with real swatches. */
  .k-legend {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    flex-shrink: 0;
    gap: var(--k-1) var(--k-5);
    min-height: 36px;
    padding: 0 var(--k-1);
    color: var(--k-slate);
    font: 600 var(--k-t-meta)/var(--k-lh-meta) var(--k-font);
  }
  .k-legend__item {
    display: inline-flex;
    align-items: center;
    gap: var(--k-2);
  }
  /* "Slobodan Sto": sentence case, copy unchanged. */
  .k-legend__item > [data-i18n] { text-transform: lowercase; }
  .k-legend__item > [data-i18n]::first-letter { text-transform: uppercase; }
  .k-legend__swatch {
    flex-shrink: 0;
    width: 24px;
    height: 18px;
    border-radius: var(--k-r-control);
  }
  .k-legend__swatch--free {
    border: 1.5px solid var(--k-line-strong);
    background: var(--k-surface);
  }
  .k-legend__swatch--occ { background: var(--k-navy); }
  .k-legend__chip {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 24px;
    height: 20px;
    border-radius: var(--k-r-control);
    background: var(--k-info-tint);
    color: var(--k-info);
    font-size: 14px;
    line-height: 1;
  }
  .k-legend__mode {
    margin-left: auto;
    color: var(--k-ink-3);
  }

  /* #13b Room tabs (renderFloorRoomTabs in index.html, markup from js/floor-rooms.js
     renderRoomTabs): one design-system Chip per floor plan room above the floor, in the admin's
     order, each "Sala  3" with the number of occupied tables as a quiet figure, not a badge. The
     selected room is a navy fill with on-navy text and selected-edge border (a real edge only in
     Malam). The row is [hidden] with a single room, so the floor looks as before rooms existed.
     It scrolls sideways (PDA at 412px) with a hidden scrollbar and the chip row's 32px end fade;
     the chips are <button>s with aria-pressed, so the focus ring goes inside (the row clips) and
     turns gold-light on the navy chip. (0,3,0) beats the (0,2,1) base focus ring. */
  .k-rooms {
    display: flex;
    flex-shrink: 0;
    gap: var(--k-2);
    padding: 0 var(--k-6) 0 0;
    overflow-x: auto;
    overflow-y: hidden;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
    -webkit-mask-image: linear-gradient(to right, black calc(100% - var(--k-6)), transparent);
    mask-image: linear-gradient(to right, black calc(100% - var(--k-6)), transparent);
  }
  .k-rooms[hidden] { display: none; }
  .k-rooms::-webkit-scrollbar { display: none; }
  .k-room {
    display: inline-flex;
    flex-shrink: 0;
    align-items: center;
    gap: var(--k-2);
    height: var(--k-hit);
    margin: 0;
    padding: 0 var(--k-4);
    border: 1px solid var(--k-line-strong);
    border-radius: var(--k-r-control);
    background: var(--k-surface);
    color: var(--k-ink);
    font: 600 var(--k-t-sm)/var(--k-lh-sm) var(--k-font-tight);
    white-space: nowrap;
    cursor: pointer;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
  }
  .k-room__count {
    color: var(--k-ink-3);
    font: 600 var(--k-t-sm)/1 var(--k-font);
    font-variant-numeric: tabular-nums lining-nums;
  }
  @media (hover: hover) and (pointer: fine) {
    .k-room:hover { background: var(--k-sunken); }
  }
  .k-room:active { background: var(--k-sunken-press); }
  .k-room[aria-pressed="true"] {
    background: var(--k-navy);
    color: var(--k-on-navy);
    border-color: var(--k-selected-edge);
  }
  .k-room[aria-pressed="true"]:active { background: var(--k-navy-raised); }
  .k-room[aria-pressed="true"] .k-room__count { color: var(--k-slab-ink-2); }
  .k-rooms .k-room:focus-visible { outline-offset: -2px; }
  .k-rooms .k-room[aria-pressed="true"]:focus-visible { outline-color: var(--k-focus-on-slab); }
  /* end room tabs */

  /* #14-16 Menu view: toolbar (search + key size), category chips, keys.
     Panel padding 12 (24 at 1600px and up); 8 between the two filter
     rows, 12 above the keys. JS flips the view's inline display. */
  .k-menuview {
    gap: var(--k-2);
    padding: var(--k-3);
  }
  .k-menuview__bar {
    display: flex;
    align-items: center;
    flex-shrink: 0;
    gap: var(--k-3);
  }
  /* #14 Search: also the USB barcode scanner's input (Enter on an exact
     GTIN adds the item), hence the quiet barcode glyph on the right. The
     icons are centred by the flex row (no top offset) and let taps through
     to the field. */
  .k-search {
    position: relative;
    display: flex;
    align-items: center;
    flex: 1 1 auto;
    min-width: 0;
  }
  .k-search__input {
    height: var(--k-h-key2);
    padding: 0 calc(var(--k-3) + 20px + var(--k-2));
  }
  .k-search__icon,
  .k-search__scan {
    position: absolute;
    z-index: 1;
    color: var(--k-ink-3);
    font-size: 20px;
    line-height: 1;
    pointer-events: none;
  }
  .k-search__icon { left: var(--k-3); }
  .k-search__scan { right: var(--k-3); }
  /* PDA table picker: a 48px row above the toolbar (display in LEGACY
     OVERRIDES, PDA mode only). */
  .k-pda-table {
    flex-shrink: 0;
    align-items: center;
    gap: var(--k-3);
  }
  .k-pda-table__label {
    flex-shrink: 0;
    margin: 0;
    color: var(--k-slate);
    font: 600 var(--k-t-sm)/var(--k-lh-sm) var(--k-font);
    white-space: nowrap;
  }
  .k-pda-table .k-field {
    flex: 1 1 auto;
    width: auto;
    height: var(--k-h-key2);
  }

  /* #17-18 Reservations and history views: title (21/600) and its action
     or filter row, then the table card. Panel padding 12 (24 at 1600px and
     up). The filter row wraps cleanly when the order column is open. JS
     flips the views' inline display. */
  .k-dataview {
    gap: var(--k-3);
    padding: var(--k-3);
  }
  .k-dataview__bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    flex-shrink: 0;
    gap: var(--k-3);
  }
  .k-view-title {
    display: flex;
    align-items: center;
    gap: var(--k-2);
    margin: 0;
    color: var(--k-ink);
    font: 600 var(--k-t-lg)/var(--k-lh-lg) var(--k-font);
    white-space: nowrap;
  }
  .k-view-title > i {
    color: var(--k-slate);
    font-size: 24px;
    line-height: 1;
  }
  /* The search field takes the slack (up to 320px), so on its own line at
     1024 the filter row still holds search, both dates and Filter. */
  .k-filter {
    display: flex;
    flex: 1 1 auto;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: var(--k-2);
  }
  .k-filter__search {
    flex: 1 1 128px;
    width: auto;
    max-width: 320px;
  }
  .k-filter__date {
    width: 164px;
    font-variant-numeric: tabular-nums lining-nums;
  }
  .k-filter__sep {
    color: var(--k-slate);
    font: 400 var(--k-t-sm)/var(--k-lh-sm) var(--k-font);
  }

  /* #25 Cash sheet (spec 5.6): amount due 28/700, the typed amount 28/700
     in a 56px field, quick keys 52px, the change due as the largest number
     on the sheet (36/700 ok-ink on ok-tint: it is read aloud), and the one
     brass key. JS writes opacity, pointer-events and disabled on it. */
  .k-due {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--k-3);
  }
  .k-due__label {
    color: var(--k-slate);
    font: 600 var(--k-t-sm)/var(--k-lh-sm) var(--k-font);
  }
  .k-due__amount {
    color: var(--k-ink);
    font: 700 var(--k-t-xl)/var(--k-lh-xl) var(--k-font);
    font-variant-numeric: tabular-nums lining-nums;
    white-space: nowrap;
  }
  .k-field.k-field--cash {
    height: var(--k-h-key);
    padding: 0 var(--k-4);
    font: 700 var(--k-t-xl)/var(--k-lh-xl) var(--k-font);
    font-variant-numeric: tabular-nums lining-nums;
    text-align: right;
  }
  .k-quick {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: var(--k-2);
  }
  .k-quick__key {
    height: 52px;
    padding: 0 var(--k-2);
    font-size: var(--k-t-md);
    line-height: var(--k-lh-md);
    font-variant-numeric: tabular-nums lining-nums;
  }
  .k-change {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--k-3);
    padding: var(--k-3) var(--k-4);
    border-radius: var(--k-r-card);
    background: var(--k-ok-tint);
    color: var(--k-ok-ink);
  }
  .k-change__label { font: 600 var(--k-t-sm)/var(--k-lh-sm) var(--k-font); }
  .k-change__amount {
    font: 700 var(--k-t-2xl)/var(--k-lh-2xl) var(--k-font);
    font-variant-numeric: tabular-nums lining-nums;
    white-space: nowrap;
  }

  /* #26 EDC wait sheet: centred, no head; the icon is styled by id because
     JS replaces its className (card / QR). */
  .k-modal--wait .k-modal__body {
    align-items: center;
    gap: var(--k-3);
    padding: var(--k-6) var(--k-5);
    text-align: center;
  }
  .k-modal--wait .k-modal__title {
    flex: 0 0 auto;
    justify-content: center;
  }
  #edc-icon {
    color: var(--k-ink);
    font-size: 48px;
    line-height: 1;
  }
  .k-modal--wait .k-progress { margin-top: var(--k-2); }

  /* #27 Split sheet: rows of method + amount (48px fields, addSplitRow)
     and a 44px remove key; the remainder line (JS writes its border colour,
     tint and the amount colour: green when balanced, red otherwise). The
     brass confirm enables once the rows balance. */
  .k-split-rows {
    display: flex;
    flex-direction: column;
    gap: var(--k-2);
  }
  .k-remainder {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--k-3);
    padding: var(--k-3) var(--k-4);
    border: 1px solid var(--k-line);
    border-radius: var(--k-r-card);
  }
  .k-remainder__label {
    color: var(--k-ink);
    font: 600 var(--k-t-sm)/var(--k-lh-sm) var(--k-font);
  }
  .k-remainder__amount {
    color: var(--k-danger);
    font: 700 var(--k-t-lg)/var(--k-lh-lg) var(--k-font);
    font-variant-numeric: tabular-nums lining-nums;
    white-space: nowrap;
  }

  /* #29-30 Open orders and pending SDC: their shells and js/open-orders.js
     renderList stay as they are, so they are styled by id scope. The panel
     (.modal-content, defined nowhere else: today it is a bare box on the
     backdrop) becomes a white sheet like .k-modal; padding and max-width
     come from the markup. */
  :is(#open-orders-modal, #pending-fiscal-modal) .modal-content {
    display: flex;
    flex-direction: column;
    width: min(760px, calc(100vw - 2 * var(--k-4)));
    max-height: calc(100vh - 96px);
    overflow-y: auto;
    border-radius: var(--k-r-sheet);
    background: var(--k-surface);
    color: var(--k-ink);
    box-shadow: var(--k-e3);
    overscroll-behavior: contain;
    transform: translateY(8px);
    transition: transform var(--k-dur) var(--k-ease);
  }
  :is(#open-orders-modal, #pending-fiscal-modal).active .modal-content { transform: none; }
  :is(#open-orders-modal, #pending-fiscal-modal) .modal-content > h2 {
    display: flex;
    align-items: center;
    gap: var(--k-2);
    font: 600 var(--k-t-lg)/var(--k-lh-lg) var(--k-font);
  }
  :is(#open-orders-modal, #pending-fiscal-modal) .modal-content > h2 > i {
    flex-shrink: 0;
    font-size: 24px;
    line-height: 1;
  }
  #open-orders-modal .modal-content > p { line-height: var(--k-lh-meta); }
  /* The markup already spaces them (list margin 20 + actions margin 16),
     so no rule is drawn above the keys. */
  :is(#open-orders-modal, #pending-fiscal-modal) .modal-actions {
    display: flex;
    justify-content: flex-end;
    gap: var(--k-2);
    flex-shrink: 0;
  }
  /* Their legacy .btn / .btn-ghost keys (allure paints them with
     !important from var(--blue), var(--bg2), var(--border), var(--r-sm)):
     44px, 15/600 condensed, and the colours through the variables allure
     reads, so no !important is needed. */
  :is(#open-orders-modal, #pending-fiscal-modal) .btn {
    --r-sm: var(--k-r-control);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--k-2);
    min-height: var(--k-hit);
    padding: 0 var(--k-3);
    font-family: var(--k-font-tight);
    font-size: var(--k-t-sm);
    line-height: var(--k-lh-sm);
    box-shadow: none;
    transition: none;
    -webkit-tap-highlight-color: transparent;
  }
  :is(#open-orders-modal, #pending-fiscal-modal) .btn:active { transform: none; }
  :is(#open-orders-modal, #pending-fiscal-modal) .btn > i {
    font-size: 20px;
    line-height: 1;
  }
  :is(#open-orders-modal, #pending-fiscal-modal) .btn-ghost {
    --bg2: var(--k-surface);
    --bg3: var(--k-sunken);
    --border: var(--k-line-strong);
    --text3: var(--k-slate);
  }
  /* Rows (js/open-orders.js renderList, S8.3): white with a 1px line, the
     reason as a tinted tag (colours from the tokens, AA). The row reads
     --bg3, the source tag --bg2. */
  #open-orders-list [data-oo-row] {
    --bg3: var(--k-surface);
    --bg2: var(--k-sunken);
  }
  /* The table picker ("Izaberite sto"), as a 44px field (17px text from
     the inline var(--k-t-md)). */
  #open-orders-list select.input {
    min-height: var(--k-hit);
    padding: 0 calc(var(--k-3) + 20px) 0 var(--k-3);
    border: 1px solid var(--k-line-strong);
    border-radius: var(--k-r-control);
    background-color: var(--k-surface);
    background-image:
      linear-gradient(45deg, transparent 50%, var(--k-slate) 50%),
      linear-gradient(135deg, var(--k-slate) 50%, transparent 50%);
    background-position:
      calc(100% - var(--k-3) - 10px) 50%,
      calc(100% - var(--k-3) - 4px) 50%;
    background-size: 6px 6px;
    background-repeat: no-repeat;
    color: var(--k-ink);
    font-family: var(--k-font);
    -webkit-appearance: none;
    appearance: none;
    cursor: pointer;
  }
  /* Pending SDC rows (renderPendingFiscalList): white, a 4px amber bar;
     table name 15/700 with the time below (13 ink-3), the total 17/700 on
     the right. */
  .k-pending-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: "table total" "time total";
    align-items: center;
    gap: var(--k-1) var(--k-4);
    padding: var(--k-3) var(--k-4);
    border: 1px solid var(--k-line);
    border-left: 4px solid var(--k-warn-line);
    border-radius: var(--k-r-card);
    background: var(--k-surface);
  }
  .k-pending-row__main { display: contents; }
  .k-pending-row__table {
    grid-area: table;
    min-width: 0;
    overflow: hidden;
    color: var(--k-ink);
    font: 700 var(--k-t-sm)/var(--k-lh-sm) var(--k-font);
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .k-pending-row__total {
    grid-area: total;
    color: var(--k-ink);
    font: 700 var(--k-t-md)/var(--k-lh-md) var(--k-font);
    font-variant-numeric: tabular-nums lining-nums;
    white-space: nowrap;
  }
  .k-pending-row__time {
    grid-area: time;
    color: var(--k-ink-3);
    font: 400 var(--k-t-meta)/var(--k-lh-meta) var(--k-font);
    font-variant-numeric: tabular-nums lining-nums;
  }

  /* #32 SaaS lock: the lock card with a danger title (the copy arrives in
     caps: sentence case, copy unchanged) and a navy key back to the portal.
     allure paints every heading var(--fg) !important, so the title
     redefines --fg. */
  .k-saas {
    align-items: center;
    text-align: center;
  }
  .k-saas__icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 64px;
    height: 64px;
    border-radius: 50%;
    background: var(--k-danger-tint);
    color: var(--k-danger);
    font-size: 32px;
    line-height: 1;
  }
  .k-saas__title {
    --fg: var(--k-danger);
    margin: 0;
    font: 600 var(--k-t-lg)/var(--k-lh-lg) var(--k-font);
    text-transform: lowercase;
  }
  .k-saas__title::first-letter { text-transform: uppercase; }


  /* 4.6 Responsive (1300px and 899px header breakpoints, 1600px grid) */

  /* Header at 1300px and below (spec 5.4): the alert buttons become icon
     plus count and Odjava becomes icon-only (labels stay in the
     accessibility tree); the shop name gets an ellipsis at 180px. */
  @media (max-width: 1300px) {
    .k-brand__shop { max-width: 180px; }
    .k-bar__alert-label,
    .k-bar__logout .k-btn__label {
      position: absolute;
      width: 1px;
      height: 1px;
      margin: -1px;
      overflow: hidden;
      clip: rect(0 0 0 0);
      clip-path: inset(50%);
      white-space: nowrap;
    }
    .k-bar__alert { padding-right: var(--k-3); }
    .k-bar__logout { padding: 0; }
  }

  /* VAT rows at 1300px and above: base and VAT of one label side by side,
     13px condensed (spec 5.1); a single "no tax table" row spans both. */
  @media (min-width: 1300px) {
    #summary-vat-rows {
      display: grid;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      column-gap: var(--k-4);
    }
    #summary-vat-rows > .summary-row { font: 600 var(--k-t-meta)/var(--k-lh-meta) var(--k-font-tight); }
    #summary-vat-rows > .summary-row:only-child { grid-column: 1 / -1; }
  }

  /* Pay keys at 1309px and below (order column under 380px): tier-2 icons
     go so their labels fit, and Kartica's too, so the brass Gotovina key
     alone keeps its icon. */
  @media (max-width: 1309px) {
    .k-check .pay-btn:not(#pay-cash) > i { display: none; }
    /* The disclosure's label gets the icon's room; the "fiscal data
       entered" dot moves to the corner. */
    .k-disclosure > i { display: none; }
    .k-disclosure { --k-dot-top: var(--k-1); --k-dot-left: var(--k-1); }
  }

  /* Floor, menu and data views at 1600px and above: the panel padding grows
     to 24; small menu keys get 152px columns (9 across at 1920). */
  @media (min-width: 1600px) {
    .k-floor,
    .k-menuview,
    .k-dataview { padding: var(--k-5); }
    #menu-grid { --k-key-min: 152px; }
  }

  /* History filter on a phone (PDA, 599px and below): two tidy rows
     instead of a ragged wrap, search beside Filter, then from "do" to. */
  @media (max-width: 599px) {
    .k-filter {
      display: grid;
      grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
      grid-template-areas: "search search go" "from sep to";
      width: 100%;
    }
    .k-filter__search { grid-area: search; max-width: none; }
    .k-filter > .k-btn { grid-area: go; }
    #history-from-date { grid-area: from; }
    .k-filter__sep { grid-area: sep; }
    #history-to-date { grid-area: to; }
    .k-filter__date { width: 100%; min-width: 0; }
  }

  /* Header at 899px and below (spec 5.5): the L-PFR pill keeps only its dot
     (title "L-PFR"), the queue pill only its spinner, the clock goes, and
     the shop name takes whatever room is left. */
  @media (max-width: 899px) {
    .k-bar #lpfr-status-text,
    .k-bar #offline-sync-text {
      position: absolute;
      width: 1px;
      height: 1px;
      margin: -1px;
      overflow: hidden;
      clip: rect(0 0 0 0);
      clip-path: inset(50%);
      white-space: nowrap;
    }
    .k-clock { display: none; }
    .k-brand__shop { max-width: none; }
  }


  /* 4.7 PDA waiter mode (body.pda-waiter-mode) */

  /* Header in PDA mode (spec 5.5), at any width: the same reductions as
     899px plus the 1300px ones (icon-only alerts and Odjava). */
  body.pda-waiter-mode .k-bar__alert-label,
  body.pda-waiter-mode .k-bar__logout .k-btn__label,
  body.pda-waiter-mode .k-bar #lpfr-status-text,
  body.pda-waiter-mode .k-bar #offline-sync-text {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
  }
  body.pda-waiter-mode .k-bar__alert { padding-right: var(--k-3); }
  body.pda-waiter-mode .k-bar__logout { padding: 0; }
  body.pda-waiter-mode .k-clock { display: none; }
  body.pda-waiter-mode .k-brand__shop { max-width: none; }
  /* Menu in PDA mode: the narrow search field gives the barcode glyph's
     room to the placeholder (a waiter's phone has no USB scanner). The
     keys keep their sm/md/lg/detail rules (two sm columns at 412px). */
  body.pda-waiter-mode .k-search__scan { display: none; }
  body.pda-waiter-mode .k-search__input { padding-right: var(--k-3); }
  /* The Korpa tab, the table picker and the panel's 48px offset are in
     LEGACY OVERRIDES. No height override is needed for .pos-layout: body
     is a 100vh flex column and .pos-layout is flex: 1 (0 basis) with
     overflow: hidden, so the inline `height: calc(100vh - 60px)
     !important` does not size it: an open training or L-PFR banner
     shortens the panel instead of pushing the check off the bottom of the
     screen (checked at 412x915). */

  /* PDA mode on a tablet or the till (700px and up): the order sheet is
     one centred 640px column on paper, instead of lines stretched across
     the whole screen (name and price 1,200px apart at 1366). Allure paints
     the panel background from var(--nav), redefined here. */
  @media (min-width: 700px) {
    body.pda-waiter-mode .cart-sidebar {
      --nav: var(--k-paper);
      align-items: center;
    }
    body.pda-waiter-mode .cart-sidebar > * {
      width: 100%;
      max-width: 640px;
      border-right: 1px solid var(--k-line);
      border-left: 1px solid var(--k-line);
      background: var(--k-surface);
    }
    /* The 640px column has room for every key icon, which the 1309px rule
       drops for the narrow docked column. */
    body.pda-waiter-mode .k-check .pay-btn:not(#pay-cash) > i,
    body.pda-waiter-mode .k-disclosure > i { display: inline-block; }
    body.pda-waiter-mode .k-disclosure { --k-dot-top: initial; --k-dot-left: initial; }
  }

}


/* ── 5. Reduced motion ───────────────────────────────────────────────────────
   Nothing animates, except inside the frozen fiscal and ESIR-info modals. Safe for JS:
   it only ever writes `pulse …` or `none` into inline animation styles, and
   no code waits for transitionend/animationend. */
@media screen and (prefers-reduced-motion: reduce) {
  :not(#fiscal-modal, #fiscal-modal *, #esir-info-modal, #esir-info-modal *),
  :not(#fiscal-modal, #fiscal-modal *, #esir-info-modal, #esir-info-modal *)::before,
  :not(#fiscal-modal, #fiscal-modal *, #esir-info-modal, #esir-info-modal *)::after {
    animation: none !important;
    transition: none !important;
  }
}

/* ═══ Themes (from the AllurePOS Design System tokens.json; colour and shadow only) ═══
   Applied as <html data-theme="…"> by js/kasir-theme.js. Navy & Emas is :root above and needs no
   attribute. Never follows prefers-color-scheme. The fiscal receipt, #fiscal-modal and
   #esir-info-modal never read --k-* tokens, so no theme reaches them. */
html[data-theme="oranye-klasik"] {
  --k-navy: #2b2118;
  --k-navy-raised: #4a392c;
  --k-navy-hover: #5b4737;
  --k-brass: #ff8c2d;
  --k-brass-hover: #ffa052;
  --k-brass-press: #e8791f;
  --k-paper: #f5efe4;
  --k-surface: #fffdf9;
  --k-sunken: #efe7d9;
  --k-sunken-press: #e4d8c5;
  --k-ink: var(--k-navy);
  --k-slate: #5e4b3d;
  --k-ink-3: #6f5d4e;
  --k-line: #e2d9cb;
  --k-line-strong: #8c7a69;
  --k-slab-ink-2: #d9c9b7;
  --k-slab-edge: #9d8672;
  --k-focus: #1f5fd0;
  --k-focus-on-slab: #ffb565;
  --k-on-navy: var(--k-surface);
  --k-on-brass: var(--k-navy);
  --k-on-warn-fill: var(--k-navy);
  --k-on-danger: var(--k-surface);
  --k-control-edge: transparent;
  --k-selected-edge: transparent;
  --k-sheet-edge: transparent;
  --k-ok: #1b7a46;
  --k-ok-ink: #17613a;
  --k-ok-tint: #e7f4ec;
  --k-warn-fill: #f4c04f;
  --k-warn-ink: #6b4600;
  --k-warn-tint: #fff1cf;
  --k-warn-line: #b07a08;
  --k-warn-hover: #fde6a8;
  --k-danger: #b3261e;
  --k-danger-ink: #8c1d16;
  --k-danger-tint: #fcebea;
  --k-info: #1a4fa8;
  --k-info-tint: #e8f0fc;
  --k-scrim: rgba(43, 33, 24, 0.48);
  --k-e1: 0 1px 2px rgba(43, 33, 24, 0.10);
  --k-e2: 0 6px 16px rgba(43, 33, 24, 0.14);
  --k-e3: 0 24px 48px rgba(43, 33, 24, 0.28);
}
html[data-theme="malam"] {
  color-scheme: dark;
  --k-navy: #3a62a8;
  --k-navy-raised: #4169ae;
  --k-navy-hover: #4a72b8;
  --k-brass: #e6bc68;
  --k-brass-hover: #efc97e;
  --k-brass-press: #cfa152;
  --k-paper: #0a0f18;
  --k-surface: #131a26;
  --k-sunken: #1b2433;
  --k-sunken-press: #253043;
  --k-ink: #e9eef6;
  --k-slate: #b7c1d2;
  --k-ink-3: #98a4b8;
  --k-line: #283346;
  --k-line-strong: #6d7a91;
  --k-slab-ink-2: #e6ecf7;
  --k-slab-edge: #afc3e8;
  --k-focus: #8ab4ff;
  --k-focus-on-slab: #f5cf7a;
  --k-on-navy: #ffffff;
  --k-on-brass: #0e1420;
  --k-on-warn-fill: #0e1420;
  --k-on-danger: #1a0707;
  --k-control-edge: transparent;
  --k-selected-edge: var(--k-slab-edge);
  --k-sheet-edge: var(--k-line-strong);
  --k-ok: #5ccb8b;
  --k-ok-ink: #93e2b5;
  --k-ok-tint: #0f2c1d;
  --k-warn-fill: #f4c04f;
  --k-warn-ink: #ffd37a;
  --k-warn-tint: #33270a;
  --k-warn-line: #b8871c;
  --k-warn-hover: #45350f;
  --k-danger: #ff8a80;
  --k-danger-ink: #ffb4ab;
  --k-danger-tint: #3a1414;
  --k-info: #8db4f5;
  --k-info-tint: #15264a;
  --k-scrim: rgba(0, 0, 0, 0.64);
  --k-e1: 0 1px 2px rgba(0, 0, 0, 0.40);
  --k-e2: 0 6px 16px rgba(0, 0, 0, 0.50);
  --k-e3: 0 24px 48px rgba(0, 0, 0, 0.64);
}
html[data-theme="zaitun"] {
  --k-navy: #173024;
  --k-navy-raised: #264634;
  --k-navy-hover: #325843;
  --k-brass: #c9973b;
  --k-brass-hover: #d4a54b;
  --k-brass-press: #bd8c3a;
  --k-paper: #f3f1e8;
  --k-surface: #fffefa;
  --k-sunken: #ebe8dc;
  --k-sunken-press: #dcd8c8;
  --k-ink: var(--k-navy);
  --k-slate: #4b5746;
  --k-ink-3: #5b6655;
  --k-line: #d8d4c4;
  --k-line-strong: #7a826e;
  --k-slab-ink-2: #c3d3c5;
  --k-slab-edge: #7f9d88;
  --k-focus: #1f5fd0;
  --k-focus-on-slab: #e6b85c;
  --k-on-navy: var(--k-surface);
  --k-on-brass: var(--k-navy);
  --k-on-warn-fill: var(--k-navy);
  --k-on-danger: var(--k-surface);
  --k-control-edge: transparent;
  --k-selected-edge: transparent;
  --k-sheet-edge: transparent;
  --k-ok: #1b7a46;
  --k-ok-ink: #17613a;
  --k-ok-tint: #e7f4ec;
  --k-warn-fill: #f4c04f;
  --k-warn-ink: #6b4600;
  --k-warn-tint: #fff1cf;
  --k-warn-line: #b07a08;
  --k-warn-hover: #fde6a8;
  --k-danger: #b3261e;
  --k-danger-ink: #8c1d16;
  --k-danger-tint: #fcebea;
  --k-info: #1a4fa8;
  --k-info-tint: #e8f0fc;
  --k-scrim: rgba(23, 48, 36, 0.48);
  --k-e1: 0 1px 2px rgba(23, 48, 36, 0.10);
  --k-e2: 0 6px 16px rgba(23, 48, 36, 0.14);
  --k-e3: 0 24px 48px rgba(23, 48, 36, 0.28);
}
html[data-theme="kontras-tinggi"] {
  --k-navy: #061430;
  --k-navy-raised: #1a3163;
  --k-navy-hover: #243f78;
  --k-brass: #f2c35b;
  --k-brass-hover: #f7d27a;
  --k-brass-press: #dcab45;
  --k-paper: #ffffff;
  --k-surface: #ffffff;
  --k-sunken: #eef1f6;
  --k-sunken-press: #dfe4ec;
  --k-ink: var(--k-navy);
  --k-slate: #26324a;
  --k-ink-3: #39455c;
  --k-line: #6b7486;
  --k-line-strong: #3e4a60;
  --k-slab-ink-2: #dde5f3;
  --k-slab-edge: #8ea3cc;
  --k-focus: #0038b8;
  --k-focus-on-slab: #ffd166;
  --k-on-navy: var(--k-surface);
  --k-on-brass: var(--k-navy);
  --k-on-warn-fill: var(--k-navy);
  --k-on-danger: var(--k-surface);
  --k-control-edge: var(--k-line-strong);
  --k-selected-edge: transparent;
  --k-sheet-edge: transparent;
  --k-ok: #0b5a2e;
  --k-ok-ink: #064222;
  --k-ok-tint: #e3f4ea;
  --k-warn-fill: #ffd24d;
  --k-warn-ink: #553700;
  --k-warn-tint: #fff4d6;
  --k-warn-line: #8a5e00;
  --k-warn-hover: #ffe699;
  --k-danger: #9b0d0d;
  --k-danger-ink: #700808;
  --k-danger-tint: #fdecec;
  --k-info: #0b3c8c;
  --k-info-tint: #e6eefb;
  --k-scrim: rgba(0, 0, 0, 0.6);
  --k-e1: 0 1px 2px rgba(0, 0, 0, 0.10);
  --k-e2: 0 6px 16px rgba(0, 0, 0, 0.14);
  --k-e3: 0 24px 48px rgba(0, 0, 0, 0.28);
}

/* Selected navy fills carry selected-edge (a real edge only in Malam, where navy alone is under
   3:1 on its ground); modal sheets carry sheet-edge (Malam: a dark sheet on a near-black scrim). */
@media screen {
  .k-chips .category-chip.active,
  .k-seg__btn.active,
  #k-more .lang-btn.active,
  .k-progress__bar { box-shadow: inset 0 0 0 1px var(--k-selected-edge) !important; }
  .k-modal { box-shadow: 0 0 0 1px var(--k-sheet-edge), var(--k-e3); }
}

/* Više > Tema: five 44px swatch keys (the theme's navy and brass on its own paper). The swatch
   colours are fixed literals on purpose: a swatch shows its theme, not the current one. */
@media screen {
  .k-menu__theme {
    display: flex;
    align-items: center;
    gap: var(--k-3);
    padding: var(--k-1) var(--k-3) var(--k-1);
    color: var(--k-slate);
  }
  .k-menu__theme > i { width: 20px; font-size: 20px; line-height: 1; text-align: center; }
  .k-theme-list { display: flex; gap: 2px; }
  .k-theme-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--k-hit);
    height: var(--k-hit);
    padding: 0;
    border: 0;
    border-radius: var(--k-r-control);
    background: transparent;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }
  .k-theme-swatch {
    display: inline-flex;
    gap: 2px;
    width: 28px;
    height: 28px;
    padding: 4px;
    border-radius: var(--k-r-control);
    box-shadow: inset 0 0 0 1px var(--k-line-strong);
  }
  .k-theme-swatch > span { flex: 1 1 0; border-radius: 2px; }
  @media (hover: hover) and (pointer: fine) {
    .k-theme-btn:hover { background: var(--k-sunken); }
  }
  .k-theme-btn:active { background: var(--k-sunken-press); }
  .k-theme-btn.active { box-shadow: inset 0 0 0 2px var(--k-ink); }
  /* Više > Pozadina prijave (2.56.0): thumbnails of the sign-in backdrops, the Tema row's style. */
  .k-menu__lockbg {
    display: flex;
    align-items: flex-start;
    gap: var(--k-3);
    padding: var(--k-1) var(--k-3) var(--k-2);
    color: var(--k-slate);
  }
  .k-menu__lockbg > i { width: 20px; font-size: 20px; line-height: 1; text-align: center; margin-top: 6px; }
  .k-lockbg-list { display: flex; flex-wrap: wrap; gap: 2px; }
  .k-lockbg-btn {
    display: block;
    padding: 4px;
    border: 0;
    border-radius: var(--k-r-control);
    background: transparent;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }
  .k-lockbg-btn > img {
    display: block;
    width: 56px;
    height: 32px;
    object-fit: cover;
    border-radius: 4px;
    box-shadow: inset 0 0 0 1px var(--k-line-strong);
  }
  @media (hover: hover) and (pointer: fine) {
    .k-lockbg-btn:hover { background: var(--k-sunken); }
  }
  .k-lockbg-btn:active { background: var(--k-sunken-press); }
  .k-lockbg-btn.active { box-shadow: inset 0 0 0 2px var(--k-ink); }
}
/* The logo mark is a fixed navy-and-gold image: on Malam's dark header it sits on a white plate
   (design system, Logos: never recolour the logo, give it a light plate on dark grounds). */
@media screen {
  html[data-theme="malam"] .k-brand__mark { padding: 2px; border-radius: var(--k-r-control); background: #ffffff; }
}
/* The Malam theme sets color-scheme on <html>; the accredited fiscal modals keep the default scheme
   (no dark scrollbars or native controls inside the receipt). */
#fiscal-modal, #esir-info-modal { color-scheme: normal; }
/* ESIR Info (TAP ch. 111, lib/esirIdentity.js: product, manufacturer, serial number, ESIR broj,
   versions). The frozen markup gives its panel (.modal-content) no background, so since the light
   theme its dark text sat on the dark backdrop and could not be read. The panel becomes a plain
   white sheet in fixed colours (the fiscal modals never read --k-* tokens, so no theme reaches it);
   the markup, its inline styles and the backdrop are untouched. */
@media screen {
  #esir-info-modal .modal-content {
    width: min(480px, calc(100vw - 32px));
    box-sizing: border-box;
    border-radius: 16px;
    background: #ffffff;
    color: #1f2640;
    box-shadow: 0 20px 50px rgba(0, 0, 0, 0.35);
  }
  #esir-info-modal #esir-info-body strong { color: #1f2640; word-break: break-all; text-align: right; }
}
