/* components.css — reusable component library: KPI/stat tiles, cards,
   status pills, tables, forms, empty states/notices/messages, tabs, code
   blocks, and the self-contained per-app sections (auth, stockai-forecast,
   ios) that don't share a @media block with anything in app.css. Loaded
   after app.css in base.html. */

/* ===== Stat cards ===== */
.stat-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:14px;margin-bottom:28px}
.stat-card{background:var(--surface);border:1px solid var(--border);border-radius:13px;padding:16px 18px;box-shadow:var(--shadow-card)}
.stat-card .row{display:flex;align-items:center;gap:8px}
.stat-card .dot{width:8px;height:8px;border-radius:50%;flex:0 0 8px}
.stat-card .label{font:600 12.5px var(--font);color:var(--text-2)}
.stat-card .value{font:700 28px var(--mono);color:var(--text);line-height:1;margin-top:9px}
.stat-card--ok .value{color:var(--ok-text)}
.stat-card--warn .value{color:var(--warn-text)}

/* tone dots */
.tone-ok{background:var(--ok)} .tone-info{background:var(--info)} .tone-neutral{background:var(--neutral)}
.tone-warn{background:var(--warn)} .tone-err{background:var(--err)}

/* ===== App cards (dashboard) ===== */
.app-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(330px,1fr));gap:18px}
.app-card{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-card);
  box-shadow:var(--shadow-card);padding:20px 22px;display:flex;flex-direction:column;gap:16px}
.app-card__top{display:flex;align-items:center;justify-content:space-between;gap:12px}
.app-card__id{display:flex;align-items:center;gap:12px;min-width:0}
.app-card__name{font:700 17px var(--font);color:var(--text);letter-spacing:-.2px}
/* margin-top:auto pushes the button to the card's bottom edge; grid stretches
   cards in a row to equal height, so the buttons line up regardless of how many
   lines the name wraps to. */
.app-card .btn{align-self:flex-start;margin-top:auto}
.app-card .btn[aria-disabled="true"]{opacity:.6;cursor:default;pointer-events:none}

/* ===== Filters (toolbar) — reused for every GET-param filter row (suppliers
   list, StockAI ops filters, automations audit toolbar). All direct controls
   (selects, date/search inputs, the .lang-toggle segmented control) share one
   consistent height so mixed control types line up instead of looking like
   mismatched buttons. */
.filters{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:28px}
.filters .lang-toggle{height:40px;box-sizing:border-box}
.filters .lang-toggle__opt{height:100%;padding:0 14px;display:inline-flex;align-items:center}

/* ===== Form fields ===== */
.field{margin-bottom:16px}
fieldset legend{font-size:13px;font-weight:600;color:var(--text-2);padding:0 6px}
.field label{display:block;font-size:13px;font-weight:600;color:var(--text-strong);margin-bottom:7px}
.field input[type=search],.field input[type=text],.field input[type=date],.field input[type=time],
.field input[type=datetime-local],.field select,.field textarea{
  width:100%;padding:11px 13px;border-radius:var(--radius-btn);border:1px solid var(--input-border);background:#fff;
  font:13.5px var(--font);color:var(--text-strong);outline:none}
.field input[type=file]{width:100%;padding:10px 12px;border-radius:var(--radius-btn);border:1px solid var(--input-border);background:#fff;
  font:500 13.5px var(--font);color:var(--text-strong)}
.field--narrow{max-width:280px}
.field textarea{min-height:118px;resize:vertical;font-family:var(--mono);font-size:13px;line-height:1.6;background:#FBFCFD}
.field input:focus,.field select:focus,.field textarea:focus{border-color:var(--primary);background:#fff}
.filters input[type=search],.filters input[type=date],.filters input[type=time],.filters input[type=datetime-local],
.filters select{height:40px;padding:0 13px;border-radius:var(--radius-btn);border:1px solid var(--input-border);
  background:#fff;font:500 13.5px var(--font);color:var(--text-strong);outline:none;box-sizing:border-box}
input[type=date]::-webkit-calendar-picker-indicator,input[type=time]::-webkit-calendar-picker-indicator,
input[type=datetime-local]::-webkit-calendar-picker-indicator{cursor:pointer}

/* ===== Status pills ===== */
.status-pill{display:inline-flex;align-items:center;gap:6px;padding:4px 10px;border-radius:var(--radius-pill);
  font-size:11.5px;font-weight:600;white-space:nowrap}
.status-pill .dot{width:6px;height:6px;border-radius:50%;flex:0 0 6px}
.status-pill--ok{background:var(--ok-bg);color:var(--ok-text)} .status-pill--ok .dot{background:var(--ok)}
.status-pill--info{background:var(--info-bg);color:var(--info-text)} .status-pill--info .dot{background:var(--info)}
.status-pill--neutral{background:var(--neutral-bg);color:var(--neutral-text)} .status-pill--neutral .dot{background:var(--neutral)}
.status-pill--warn{background:var(--warn-bg);color:var(--warn-text)} .status-pill--warn .dot{background:var(--warn)}
.status-pill--err{background:var(--err-bg);color:var(--err-text)} .status-pill--err .dot{background:var(--err)}
.pill{display:inline-flex;align-items:center;gap:4px;padding:3px 9px;border-radius:var(--radius-pill);
  border:1px solid var(--border);background:var(--surface-tint);color:var(--text-2);font:700 11.5px var(--font);
  white-space:nowrap}
.pill.direction-positive{background:var(--ok-bg);color:var(--ok-text);border-color:var(--ok-border)}
.pill.direction-negative{background:var(--warn-bg);color:var(--warn-text);border-color:#F0DCBE}

/* ===== Table ===== */
/* overflow stays visible so .cell-pop panels can escape the box; the rounded
   corners are compensated on the corner cells below */
.table-wrap{background:var(--surface);border:1px solid var(--border);border-radius:14px;overflow:visible;box-shadow:var(--shadow-card)}
table.data{border-collapse:collapse;width:100%}
.table-wrap > table.data thead th:first-child{border-top-left-radius:14px}
.table-wrap > table.data thead th:last-child{border-top-right-radius:14px}
.table-wrap > table.data tbody tr:last-child td{border-bottom:0}
.table-wrap > table.data tbody tr:last-child td:first-child{border-bottom-left-radius:14px}
.table-wrap > table.data tbody tr:last-child td:last-child{border-bottom-right-radius:14px}
table.data thead th{background:var(--surface-tint);border-bottom:1px solid var(--border-2);text-align:left;
  font-size:11px;font-weight:600;letter-spacing:.6px;text-transform:uppercase;color:var(--text-muted);padding:13px 18px}
table.data tbody td{border-bottom:1px solid #F0F2F6;padding:14px 18px;font-size:13px;color:var(--text-strong)}
table.data tbody tr:hover td{background:#FAFBFD}
/* Opt-in readability modifiers for dense, spreadsheet-like data grids. */
table.data--gridlines > thead > tr > th,
table.data--gridlines > tbody > tr > td,
table.data--gridlines > tfoot > tr > th,
table.data--gridlines > tfoot > tr > td{border-bottom:1px solid var(--input-border)}
table.data--gridlines > thead > tr > th{background:var(--accent-soft)}
table.data--gridlines > thead > tr > th:not(:last-child),
table.data--gridlines > tbody > tr > td:not(:last-child),
table.data--gridlines > tfoot > tr > th:not(:last-child),
table.data--gridlines > tfoot > tr > td:not(:last-child){border-right:1px solid var(--border)}
table.data--zebra > tbody > tr:nth-child(even):not(.data__detail-row):not(.is-selected) > td{background:var(--surface-tint)}
table.data--zebra > tbody > tr:hover:not(.data__detail-row) > td{background:var(--info-tint)}
table.data--zebra > tbody > tr.is-selected > td{background:var(--info-bg)}
table.data--zebra > tbody > tr.data__detail-row > td{background:var(--info-tint)}
table.data details summary{cursor:pointer;color:var(--primary-ink);font-weight:600;font-size:12.5px;list-style:none}
table.data details summary::-webkit-details-marker{display:none}
table.data details pre{white-space:pre-wrap;margin:8px 0 0;font-family:var(--mono);font-size:12px;color:var(--text-2)}

/* ===== Wide-table scroll pattern (canonical — see design-conventions.md) =====
   A table wider than its card scrolls INSIDE the card, never the page. Add
   .table-wrap--scroll to any .table-wrap whose table can exceed the
   workspace at laptop widths (1280-1680px). Keeps every column — nothing is
   hidden — the wide/full-width layout is preserved; only the table's own box
   grows a horizontal scrollbar. */
.table-wrap--scroll{overflow:auto;-webkit-overflow-scrolling:touch;
  scrollbar-width:thin;scrollbar-color:#C4CCD8 var(--surface-tint)}
/* Always-visible styled scrollbar: macOS overlay scrollbars only appear while
   scrolling, which hid the one signal the box scrolls at all. Custom webkit
   scrollbars are classic (always painted when the table overflows, never for
   a fitting table); the scrollbar-width/-color pair above is the Firefox
   equivalent. Lives inside the card, so the wrap's border-radius keeps the
   bottom corners rounded around it. */
.table-wrap--scroll::-webkit-scrollbar{height:10px;width:10px}
.table-wrap--scroll::-webkit-scrollbar-track{background:var(--surface-tint);border-top:1px solid var(--border-2)}
.table-wrap--scroll::-webkit-scrollbar-thumb{background:#C4CCD8;border-radius:var(--radius-pill);
  border:2px solid var(--surface-tint);background-clip:padding-box}
.table-wrap--scroll::-webkit-scrollbar-thumb:hover{background:#A8B3C2}
/* Reduce the target more before a wide table needs to scroll at all. */
@media (max-width:1680px){
  table.data thead th{padding:12px 12px}
  table.data tbody td{padding:12px 12px;font-size:12.5px}
}

/* ===== Wide-table scroll shadows/chevrons (static/js/tables.js) =====
   tables.js wraps each .table-wrap--scroll in a `.table-scroll-shell` — OUTSIDE
   .table-wrap, never between it and its <table>, so the `.table-wrap >
   table.data` corner-radius rules above keep matching — and hangs the edge
   overlays + chevron buttons off the shell as siblings of .table-wrap. Because
   they live outside the scrolling box (not inside it), they never scroll away
   with the table content. tables.js measures real overflow with a
   ResizeObserver + scroll listener and reflects it back as state classes:
   `.is-overflowing` + `.can-scroll-left`/`-right` on `.table-wrap` (the
   sticky-actions rules below key off those) and the same `can-scroll-*`
   pair mirrored onto the shell for the overlay rules here — plain
   descendant selectors, deliberately no `:has()`: Chrome's paint-side style
   invalidation proved unreliable with `:has()` on these overlays (stale
   frames), and this also works in browsers without `:has()` support. Both
   overlays stay invisible when the table fits and never overflows.
   z-index layering (low to high): table cells (auto) < sticky actions column
   (5, see below) < these shadows/chevrons (6) < .cell-pop__panel (40) — so an
   open popover always floats above everything else here. */
.table-scroll-shell{position:relative}
/* Soft scrim marking where content disappears: at the card's right edge on
   plain tables, at the pinned boundary (shifted left by --sticky-w — the
   total pinned width, set by tables.js, unset → 0 elsewhere) on sticky
   tables, where it overlays the pinned columns' own drop shadow so the two
   read as one soft depth zone rather than two seams. */
.table-scroll-shell__edge{position:absolute;top:0;bottom:0;width:56px;z-index:6;
  pointer-events:none;opacity:0;visibility:hidden;transition:opacity .15s ease,visibility .15s}
.table-scroll-shell__edge--left{left:0;background:linear-gradient(to right,rgba(16,24,40,.10),rgba(16,24,40,0))}
.table-scroll-shell__edge--right{right:var(--sticky-w,0px);background:linear-gradient(to left,rgba(16,24,40,.10),rgba(16,24,40,0))}
.table-scroll-shell.can-scroll-left .table-scroll-shell__edge--left,
.table-scroll-shell.can-scroll-right .table-scroll-shell__edge--right{opacity:1;visibility:visible}
/* solid arrow buttons — fully visible whenever their direction has hidden
   content, gone otherwise (no translucent in-between); shadow tones match
   --shadow-pop. Both buttons sit fully OUTSIDE the card, in the grey margin
   the .content padding leaves beside it (owner decision 2026-07-08): flush to
   the card's outer left/right edges, never over a scrolling cell or the
   pinned Status/Akcije pair. Portal ancestors (.content/.content__inner/.main)
   don't clip horizontally, so the buttons paint on the page background. Below
   880px the content padding drops to 18px — not enough room — so they hide and
   the always-visible scrollbar + swipe carry the scroll. */
.table-scroll-shell__chevron{position:absolute;top:50%;z-index:6;
  width:36px;height:36px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;
  background:#fff;border:1px solid var(--input-border);color:var(--text-strong);
  box-shadow:0 4px 14px rgba(16,24,40,.16);cursor:pointer;opacity:0;visibility:hidden;pointer-events:none;
  transform:translateY(-50%);
  transition:opacity .15s ease,visibility .15s,border-color .15s ease,box-shadow .15s ease}
.table-scroll-shell__chevron--left{left:-36px}
.table-scroll-shell__chevron--right{right:-36px}
.table-scroll-shell.can-scroll-left .table-scroll-shell__chevron--left,
.table-scroll-shell.can-scroll-right .table-scroll-shell__chevron--right{opacity:1;visibility:visible;pointer-events:auto}
.table-scroll-shell__chevron:hover{border-color:var(--primary);box-shadow:0 6px 18px rgba(16,24,40,.22)}
.table-scroll-shell__chevron:active{transform:translateY(-50%) scale(.92)}
@media (max-width:880px){.table-scroll-shell__chevron{display:none}}
.table-scroll-shell__chevron--right:active{transform:translate(50%,-50%) scale(.92)}

/* ===== Sticky actions column (opt-in, pair with .table-wrap--scroll) =====
   Pins the table's last column (the row's action buttons, e.g. .row-actions)
   to the right edge of the scroll container so it stays reachable while the
   rest of the row scrolls underneath it. tables.js toggles `.is-overflowing`
   on `.table-wrap` once it measures real horizontal overflow — the pinned
   styles only apply under that class, so a table that fits its card renders
   100% normally (no pinning reserved, no shadow) instead of always reserving
   the column's width. Add .table-wrap--sticky-2 ALONGSIDE it to pin the last
   TWO columns (Status + Akcije — reorder the template so Status sits
   immediately before the actions column): the second-to-last cell sticks at
   right:var(--sticky-w1) (the last column's width, published by tables.js).
   Only the LEFTMOST pinned column carries the boundary hairline/drop shadow;
   the seam between two pinned columns stays a plain cell edge. z-index:5 —
   see the layering note above. */
.table-wrap--sticky-actions.is-overflowing table.data th:last-child,
.table-wrap--sticky-actions.is-overflowing table.data td:last-child{
  position:sticky;right:0;z-index:5;background:var(--surface)}
.table-wrap--sticky-2.is-overflowing table.data th:nth-last-child(2),
.table-wrap--sticky-2.is-overflowing table.data td:nth-last-child(2){
  position:sticky;right:var(--sticky-w1,0px);z-index:5;background:var(--surface)}
.table-wrap--sticky-actions.is-overflowing table.data thead th:last-child,
.table-wrap--sticky-2.is-overflowing table.data thead th:nth-last-child(2){background:var(--surface-tint)}
.table-wrap--sticky-actions.is-overflowing table.data tbody tr:hover td:last-child,
.table-wrap--sticky-2.is-overflowing table.data tbody tr:hover td:nth-last-child(2){background:#FAFBFD}
/* boundary hairline on the leftmost pinned column only */
.table-wrap--sticky-actions.is-overflowing:not(.table-wrap--sticky-2) table.data th:last-child,
.table-wrap--sticky-actions.is-overflowing:not(.table-wrap--sticky-2) table.data td:last-child,
.table-wrap--sticky-2.is-overflowing table.data th:nth-last-child(2),
.table-wrap--sticky-2.is-overflowing table.data td:nth-last-child(2){
  box-shadow:-1px 0 0 var(--border);transition:box-shadow .15s ease}
/* while content is still hidden underneath the pinned boundary (tables.js:
   `.can-scroll-right`, i.e. not scrolled all the way right yet), give it a
   stronger drop shadow so it reads as floating above the row; once scrolled
   fully right there's nothing left underneath it, so the shadow fades back to
   the hairline separator above */
.table-wrap--sticky-actions.is-overflowing.can-scroll-right:not(.table-wrap--sticky-2) table.data td:last-child,
.table-wrap--sticky-2.is-overflowing.can-scroll-right table.data td:nth-last-child(2){
  box-shadow:-6px 0 10px -4px rgba(16,24,40,.20)}

/* ===== Empty state + notices ===== */
.empty-state{display:flex;flex-direction:column;align-items:center;text-align:center;background:var(--surface);
  border:1px solid var(--border);border-radius:14px;padding:44px 24px 48px;box-shadow:var(--shadow-card)}
.empty-state__icon{width:48px;height:48px;border-radius:14px;background:var(--accent-soft);color:var(--accent-ink);
  display:inline-flex;align-items:center;justify-content:center}
.empty-state .title{font-size:15.5px;font-weight:600;color:#3F4A59;margin-top:15px}
.empty-state p{margin:7px 0 18px;font-size:13.5px;line-height:1.5;color:var(--text-muted);max-width:380px}

/* ===== Module gate card ("not enabled" / "needs setup" states, see
   docs/design-conventions.md) — composed from .card + the .empty-state
   center-column idiom, sized like a normal content card instead of the
   full-bleed .empty-state so it reads as the module's body, not a blank
   placeholder. */
.module-gate{display:flex;flex-direction:column;align-items:center;text-align:center;
  max-width:520px;margin:0 auto;padding:40px 28px 44px}
.module-gate__title{font-size:16px;font-weight:700;color:var(--text-strong)}
.module-gate__text{margin:9px 0 0;font-size:13.5px;line-height:1.55;color:var(--text-muted);max-width:380px}
.module-gate__actions{display:flex;gap:10px;flex-wrap:wrap;justify-content:center;margin-top:18px}
.notice--err{padding:12px 15px;border-radius:11px;background:var(--err-bg);border:1px solid #F2C9C9;color:var(--err-text);font-size:13.5px;margin-bottom:18px}
.notice--warn{padding:12px 15px;border-radius:11px;background:var(--warn-bg);border:1px solid #F0DCBE;color:var(--warn-text);font-size:13.5px;margin-bottom:18px}
.muted{color:var(--text-muted)}
small{color:var(--text-muted)}
/* key/value pairs inside an expandable result/detail cell */
table.data details dl{margin:8px 0 0;display:grid;grid-template-columns:auto 1fr;gap:4px 14px;font-size:12.5px}
table.data details dl dt{font-weight:600;color:var(--text-2)}
table.data details dl dd{margin:0;color:var(--text)}

/* ===== Cell popover =====
   Expandable cell content (Rezultat / Detalj / Prikaži / Uredi) opens as an
   anchored floating panel instead of squeezing into its column. Use
   .cell-pop--right on columns near the table's right edge, .cell-pop--wide
   for panels holding tables/forms. */
table.data details.cell-pop{position:relative}
table.data details.cell-pop .cell-pop__panel{position:absolute;left:0;top:calc(100% + 8px);z-index:40;
  min-width:340px;max-width:min(520px,72vw);background:var(--surface);border:1px solid var(--border);
  border-radius:12px;box-shadow:var(--shadow-pop);padding:14px 16px;text-align:left;font-weight:400;
  overflow-wrap:anywhere}
table.data details.cell-pop--right .cell-pop__panel{left:auto;right:0}
table.data details.cell-pop--wide .cell-pop__panel{min-width:520px;max-width:min(760px,86vw)}
.cell-pop__panel > :first-child{margin-top:0}
.cell-pop__panel > :last-child{margin-bottom:0}
.cell-pop__panel pre{max-height:280px;overflow:auto}
.cell-pop__panel ul,.cell-pop__panel ol{margin:0;padding-left:18px}

/* ===== Row actions =====
   Stacked per-row action buttons in a table's last column — equal width and
   centered labels whatever the locale ("Kreiraj"/"Create", "Odustani"/"Cancel"). */
.row-actions{display:flex;flex-direction:column;gap:8px;align-items:stretch;width:max-content;min-width:96px}
.row-actions .btn{justify-content:center;white-space:nowrap}
/* csrf forms around buttons act as pass-through so every button is a direct
   flex item and stretches to the same width */
.row-actions form{display:contents}
.row-actions small{white-space:nowrap}
.row-actions input[type=file]{font:12px var(--font);color:var(--text-2);max-width:170px}

.actions{display:flex;gap:10px;margin-top:18px}
.section-gap{margin-bottom:28px}

/* ===== Auth (login) — ported from design system LoginScreen ===== */
.auth{width:100%}
.auth__logo{display:flex;justify-content:center;margin-bottom:24px}
.auth__logo img{height:56px;width:auto;object-fit:contain}
.auth-card{background:var(--surface);border:1px solid var(--border);border-radius:16px;
  padding:30px 30px 28px;box-shadow:0 10px 30px rgba(16,24,40,.08)}
.auth-card__eyebrow{text-align:center;font:700 11px var(--font);letter-spacing:1.5px;
  text-transform:uppercase;color:var(--primary)}
.auth-card__title{margin:8px 0 4px;text-align:center;font-size:22px;font-weight:700;
  letter-spacing:-.3px;color:var(--text)}
.auth-card__sub{margin:0 0 22px;text-align:center;font-size:13.5px;line-height:1.5;color:var(--text-2)}
.auth-form{display:flex;flex-direction:column;gap:15px}
.auth-form .auth-field{display:flex;flex-direction:column;gap:6px}
.auth-form label{font:600 13px var(--font);color:var(--text)}
.auth-form input{width:100%;padding:10px 13px;border:1px solid var(--border);border-radius:var(--radius-btn);
  background:#fff;font:14px var(--font);color:var(--text);outline:none}
.auth-form input:focus{border-color:var(--primary);box-shadow:0 0 0 3px rgba(22,131,198,.12)}
.auth-submit{margin-top:7px;width:100%;justify-content:center;box-shadow:var(--shadow-primary)}
.auth-error{background:var(--err-bg);color:var(--err-text);border-radius:10px;padding:10px 12px;
  font-size:13px;margin-bottom:16px}
.field-error{color:var(--err-text);font-size:12px}
.auth-links{margin:-4px 0 0;text-align:right;font-size:12.5px}
.auth-links a{color:var(--primary);font-weight:600;text-decoration:none}
.auth-links a:hover{text-decoration:underline}
.auth-footer{margin:20px 0 0;text-align:center;font-size:12px;color:var(--text-muted)}

/* ===== KPI widgets (dashboard) — replaces the unstyled raw-text card ===== */
.kpi-section{margin:0 0 28px}                 /* gap before the app tiles (#9) */
.kpi-card{padding:20px 22px}
.kpi-card__title{font:700 12px var(--font);text-transform:uppercase;letter-spacing:.7px;
  color:var(--text-muted);margin:0 0 16px}
.metric-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:14px}
.metric{display:flex;flex-direction:column;gap:3px;padding:14px 16px;background:var(--surface-tint);
  border:1px solid var(--border-2);border-radius:11px}
.metric .value{font:700 26px var(--mono);color:var(--text);line-height:1.1}
.metric .label{font:600 12.5px var(--font);color:var(--text-2)}
.metric .note{margin:1px 0 0;font-size:11.5px;color:var(--text-muted)}

/* ===== Flash messages (Django messages) — replaces raw <li> bullets ===== */
.messages{list-style:none;margin:0 0 22px;padding:0;display:flex;flex-direction:column;gap:10px}
.message{padding:12px 15px;border-radius:11px;font:500 13.5px var(--font);border:1px solid transparent}
.message--success{background:var(--ok-bg);color:var(--ok-text);border-color:#CDE7D6}
.message--error{background:var(--err-bg);color:var(--err-text);border-color:#F2C9C9}
.message--warning{background:var(--warn-bg);color:var(--warn-text);border-color:#F0DCBE}
.message--info,.message--debug{background:var(--info-bg);color:var(--info-text);border-color:#CFE3F3}

/* ===== In-app forms (onboarding / edit) — style raw widget rows ===== */
.form-row{margin-bottom:16px}
.form-row>label{display:block;font-size:13px;font-weight:600;color:var(--text-strong);margin-bottom:7px}
.form-row input[type=text],.form-row input[type=email],.form-row input[type=url],
.form-row input[type=number],.form-row input[type=date],.form-row input[type=time],
.form-row input[type=password],
.form-row input[type=datetime-local],.form-row select,.form-row textarea{width:100%;padding:11px 13px;
  border-radius:var(--radius-btn);border:1px solid var(--input-border);background:#fff;font:13.5px var(--font);
  color:var(--text-strong);outline:none}
.form-row input:focus,.form-row select:focus,.form-row textarea:focus{border-color:var(--primary)}
.form-row ul{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:10px}
.form-row ul li label{display:flex;align-items:center;gap:7px;font:500 13.5px var(--font);
  padding:8px 12px;border:1px solid var(--border);border-radius:var(--radius-pill);background:var(--surface-tint)}
.form-row .helptext{display:block;margin-top:6px;font-size:12px;color:var(--text-muted)}
/* Inline checkbox option belonging to the field above it (e.g. "clear this
   stored secret") — deliberately NOT styled like .form-row>label, which is a
   field's own heading. */
.form-row>label.checkbox{display:flex;align-items:center;gap:7px;margin:8px 0 0;
  font-size:12.5px;font-weight:500;color:var(--text-muted);cursor:pointer}
.form-row>label.checkbox input{width:auto;margin:0}
/* Generate / show controls injected next to a secret field (js/secret-fields.js). */
.secret-actions{display:flex;align-items:center;flex-wrap:wrap;gap:8px;margin-top:8px}
.secret-actions__note{font-size:12px;color:var(--text-muted)}
.form-actions{display:flex;gap:10px;margin-top:22px}
.form-divider{height:1px;background:var(--border-2);border:0;margin:8px 0 20px}
.errorlist{list-style:none;margin:6px 0 0;padding:0;color:var(--err-text);font-size:12.5px}
.field-readonly{font:500 13.5px var(--font);color:var(--text-2);padding:11px 0}

/* StockAI forecast */
.stockai-forecast-head{display:grid;grid-template-columns:minmax(0,1fr);gap:18px;align-items:start}
.forecast-build-actions{display:flex;gap:10px;flex-wrap:wrap;justify-content:flex-start;align-items:flex-end;width:100%}
.stockai-forecast-head--company .forecast-build-actions{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:end}
.stockai-forecast-head .forecast-build-form--company{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:12px;align-items:end;min-width:0}
.stockai-forecast-head .forecast-build-actions>form:not(:first-child){flex:0 0 auto}
.forecast-period-form{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px;align-items:end;width:100%;margin-bottom:0}
.forecast-period-form .field{margin-bottom:0}
.forecast-period-form input{width:100%}
.forecast-delta-note{margin-top:10px;color:var(--text-2)}
.stockai-forecast-layout{display:grid;grid-template-columns:minmax(280px,420px) minmax(0,1fr);gap:18px;align-items:start}
.forecast-actions{display:flex;align-items:center;justify-content:flex-end;gap:10px;flex-wrap:wrap;margin:14px 0 12px}
.forecast-table{min-width:1280px}
.forecast-table td{vertical-align:top}
.forecast-table tbody tr.tone-ok{background:transparent}
.forecast-table tbody tr.tone-ok > td{background:var(--ok-tint)}
.forecast-table tbody tr.tone-warn{background:transparent}
.forecast-table tbody tr.tone-warn > td{background:var(--warn-tint)}
.forecast-location-active{background:var(--info-tint)}
@media (max-width:1100px){
  .stockai-forecast-head,.stockai-forecast-layout{grid-template-columns:1fr}
  .forecast-build-actions{justify-content:flex-start}
  .stockai-forecast-head--company .forecast-build-actions,
  .stockai-forecast-head .forecast-build-form--company{grid-template-columns:1fr}
}

/* ===== Clickable table rows (e.g. client list) ===== */
table.data tbody tr.row-link{cursor:pointer}
table.data tbody tr.row-link td:last-child{text-align:right;color:var(--primary-ink);font-weight:600}

/* ===== Tabs (section nav inside an app, e.g. ItemAI Pregled/Postavke) =====
   Generic sibling of .stockai-tabs — reuse this for any new tabbed module. */
.tabs{display:flex;gap:4px;flex-wrap:wrap;border-bottom:1px solid var(--border);margin-bottom:24px}
.tab{padding:10px 16px;font:600 13px var(--font);color:var(--text-2);
  border-bottom:2px solid transparent;margin-bottom:-1px;border-radius:8px 8px 0 0}
.tab:hover{color:var(--text);background:#F7F9FB}
.tab.is-active{color:var(--primary-ink);border-bottom-color:var(--primary)}

/* ===== Code / JSON preview block inside a card ===== */
.code-block{white-space:pre-wrap;max-height:280px;overflow:auto;margin:0;
  padding:14px 16px;background:var(--surface-tint);border:1px solid var(--border-2);border-radius:11px;
  font-family:var(--mono);font-size:12px;line-height:1.55;color:var(--text-2)}

/* IOS — send-rules editor (replaces inline styles; rule 4) */
.admin-client-card,.admin-user-card{max-width:none;margin-top:24px}
.admin-user-table{margin-top:20px}
.admin-feature-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:10px 14px;margin-top:10px}
.admin-feature-grid label{display:flex;align-items:center;gap:7px;font:600 13px var(--font);color:var(--text-strong)}
.admin-user-feature-table th,.admin-user-feature-table td{vertical-align:top}
.admin-user-feature-list{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:6px 10px}
.admin-user-feature-list label{display:flex;align-items:center;gap:6px;font:600 12.5px var(--font);color:var(--text-2)}
.module-access-picker .admin-user-feature-list{display:flex;flex-wrap:wrap;gap:8px 18px;margin:2px 0 6px}
.module-access-option{cursor:pointer}
.module-access-picker>.muted{margin:0}
.admin-user-detail-row>td{padding:0 16px 16px;background:var(--surface-soft)}
.admin-user-details{border:1px solid var(--line);border-radius:8px;background:var(--surface);padding:12px 14px}
.admin-user-details>summary{cursor:pointer;list-style:none;font-weight:700;color:var(--primary-ink)}
.admin-user-details>summary::-webkit-details-marker{display:none}
.admin-user-details>summary::before{content:"";display:inline-block;width:0;height:0;margin-right:8px;border-left:6px solid var(--text-2);border-top:5px solid transparent;border-bottom:5px solid transparent;vertical-align:middle}
.admin-user-details[open]>summary{margin-bottom:14px}
.admin-user-details[open]>summary::before{transform:rotate(90deg)}
.admin-user-sections{display:grid;grid-template-columns:repeat(2,minmax(280px,1fr));gap:14px;align-items:start}
.admin-user-section{border:1px solid var(--line);border-radius:8px;background:var(--surface-soft);padding:14px}
.admin-user-section h3{margin:0 0 12px;font-size:15px}
.admin-user-section--wide{grid-column:1/-1}
.admin-user-edit-form--sections{display:contents}
.admin-user-form-grid{display:grid;grid-template-columns:repeat(2,minmax(180px,1fr));gap:12px}
.admin-user-form-grid .form-row{margin-bottom:0}
.admin-user-check{display:flex;align-items:center;gap:8px;font-weight:700;color:var(--text-strong)}
@media (max-width:1100px){.admin-user-sections,.admin-user-form-grid{grid-template-columns:1fr}}
.inline-form{display:inline}
/* .lang-toggle (app.css) is also always wrapped in .inline-form (topbar
   language switch, audit period toggle) so the <form> renders inline within
   its row — but since components.css loads after app.css, the plain
   `display:inline` above would otherwise win the cascade at equal specificity
   and silently collapse the segmented-pill's flex layout (no gap, no equal
   button sizing). Restore it explicitly for that combination. */
.inline-form.lang-toggle{display:inline-flex}
/* Admin role-change row: the two .table-select controls sit inline with the
   "Spremi ulogu" button, vertically centred and aligned to one baseline —
   same intent as the topbar client-picker + button row. */
.role-change-form{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.role-change-form .table-select{width:auto;min-width:150px}
/* Generic utility: fully removed from layout. Used to keep a role-change
   row's Save button hidden until its selection actually differs from the
   saved value (revealed via JS). */
.is-hidden{display:none !important}
.ios-workspace{display:flex;flex-direction:column;gap:18px}
.ios-summary-grid{display:grid;grid-template-columns:repeat(2,minmax(280px,1fr));gap:14px}
.ios-action-grid{display:grid;grid-template-columns:minmax(360px,1fr) minmax(360px,1fr);gap:18px}
.ios-section-grid{display:grid;grid-template-columns:minmax(420px,1fr) minmax(420px,1fr);gap:18px}
.ios-action-card h2,.ios-panel__head h2,.ios-details>summary h2{
  margin:0;font-size:18px;font-weight:700;letter-spacing:-.2px}
.ios-action-card p{margin:6px 0 16px;font-size:13.5px;line-height:1.55;color:var(--text-2)}
.ios-form{display:flex;flex-direction:column;gap:0}
.ios-form .form-actions{margin-top:8px}
.ios-log-grid{display:grid;grid-template-columns:minmax(160px,220px) 1fr;gap:12px}
.ios-panel{padding:20px}
.ios-panel__head{display:flex;align-items:center;justify-content:space-between;margin-bottom:14px}
.ios-table{min-width:720px}
.ios-details{padding:18px 20px}
.ios-details>summary{cursor:pointer;list-style:none;display:flex;align-items:center;gap:10px}
.ios-details>summary::-webkit-details-marker{display:none}
.ios-details>summary::before{content:"";width:0;height:0;border-left:6px solid var(--text-2);
  border-top:5px solid transparent;border-bottom:5px solid transparent;transition:transform .15s ease}
.ios-details[open]>summary::before{transform:rotate(90deg)}
.ios-details[open]>summary{margin-bottom:14px}
.ios-rules-grid{display:grid;grid-template-columns:repeat(3,minmax(180px,1fr));gap:12px}
.ios-rules-grid .form-row{margin-bottom:0}
.ios-rules-grid .form-row input+input{margin-top:8px}
.ios-day-list{display:flex;flex-wrap:wrap;gap:8px}
.ios-day-list label{
  display:inline-flex;align-items:center;gap:6px;margin:0;font:600 12.5px var(--font);color:var(--text-2)}
@media (max-width:1100px){
  .ios-summary-grid,.ios-action-grid,.ios-section-grid{grid-template-columns:1fr}
  .ios-rules-grid{grid-template-columns:repeat(2,minmax(180px,1fr))}
}
@media (max-width:700px){
  .ios-log-grid,.ios-rules-grid{grid-template-columns:1fr}
}

/* ===== Shared components (redizajn 2026-07 — used across later phases) ===== */

/* eyebrow (mono uppercase label) */
.eyebrow{font:500 12px var(--mono);letter-spacing:1.5px;text-transform:uppercase;color:var(--primary)}

/* success/ok notice — sibling of .notice--warn / .notice--err */
.notice--ok{padding:12px 15px;border-radius:11px;background:var(--ok-bg);
  border:1px solid #CDE6D6;color:var(--ok-text);font-size:13.5px;margin-bottom:18px}

/* consistent section header (h2 + sub + optional right-aligned meta) */
.section-head{display:flex;align-items:flex-end;justify-content:space-between;
  gap:16px;flex-wrap:wrap;margin:0 0 16px}
.section-head h2{margin:0;font:600 18px var(--font);letter-spacing:-.2px;color:var(--text)}
.section-head__sub{margin:4px 0 0;font-size:13.5px;line-height:1.5;color:#6B7888}
.section-head__meta{font:600 12.5px var(--font);color:var(--text-muted);white-space:nowrap}

/* Spacing wrapper around a page section that opens with a .section-head —
   same precedent as .audit-group: .section-head only carries a bottom
   margin, so when one section's content (e.g. a full review card) ends
   right above the next section's heading, they read as glued together
   without a top gap of their own. Generous on purpose: these cards are
   large, so a small gap still reads as "same group". The hairline echoes
   the divider already used elsewhere (.form-divider) to make the break
   readable even at a glance/fast scroll, not just via whitespace. */
.review-section{margin-top:40px;padding-top:24px;border-top:1px solid var(--border-2)}
.review-section:first-of-type{margin-top:0;padding-top:0;border-top:0}

/* mono / icon tile — one class, three sizes */
.mono-tile{display:inline-flex;align-items:center;justify-content:center;
  border-radius:11px;background:var(--accent-soft);color:var(--accent-ink);
  font:600 15px var(--font);width:46px;height:46px;flex:0 0 46px}
.mono-tile--sm{width:34px;height:34px;flex-basis:34px;border-radius:9px;font-size:13px}
.mono-tile--lg{width:56px;height:56px;flex-basis:56px;border-radius:14px;font-size:18px}

/* page-header identity icon (app landing headers) */
.page-header__icon{width:56px;height:56px;flex:0 0 56px;border-radius:14px;
  background:var(--accent-soft);color:var(--accent-ink);
  display:inline-flex;align-items:center;justify-content:center;font:600 18px var(--font)}
.page-header__id{display:flex;align-items:center;gap:16px}

/* dark help / hero card */
.card--dark{background:var(--panel-dark);border:0;color:#fff;border-radius:14px;padding:22px}
.help-card__icon{width:42px;height:42px;border-radius:11px;background:#16263C;color:#7FC4EC;
  display:inline-flex;align-items:center;justify-content:center;margin-bottom:14px}
.help-card h3{margin:0 0 8px;font:600 16px var(--font);color:#fff}
.help-card p{margin:0 0 16px;font-size:13.5px;line-height:1.55;color:#AEBBCC}
.help-card__contact{display:flex;align-items:center;gap:10px;margin:0 0 10px;
  font-size:13px;color:#C6D4E4}
.help-card__contact .ico{color:#7FC4EC;display:inline-flex;flex:0 0 18px}
.help-card .btn{width:100%;justify-content:center}
.dash-help{max-width:380px;margin-top:28px}

/* dashed file-drop / upload trigger */
.file-drop{display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:8px;padding:18px;border:1.5px dashed #C7D0DB;border-radius:11px;background:#FBFCFD;
  color:var(--primary-ink);font:600 13px var(--font);cursor:pointer;text-align:center}
.file-drop input[type=file]{font:13px var(--font);color:var(--text-2);text-align:center}
.file-drop:focus-within{outline:2px solid var(--primary);outline-offset:2px}

/* day-toggle pills (IOS send-days) — selected = primary fill.
   position:relative added (not in spec literal) so the visually-hidden
   absolutely-positioned checkbox stays inside the pill instead of escaping
   to the nearest positioned ancestor. */
.day-toggle{position:relative;display:inline-flex;align-items:center;gap:6px;margin:0;cursor:pointer;
  padding:7px 12px;border-radius:999px;border:1px solid var(--border);background:var(--surface-tint);
  font:600 12.5px var(--font);color:var(--text-2)}
.day-toggle:has(input:checked){background:var(--primary);border-color:var(--primary);color:#fff}
.day-toggle:has(input:focus-visible){outline:2px solid var(--primary);outline-offset:2px}
.day-toggle input{position:absolute;opacity:0;width:0;height:0}

/* constrained-width form card (suppliers/form, client_form, client_users) */
.card--form{max-width:720px}
.form-fieldset{border:1px solid var(--border);border-radius:11px;padding:14px 16px;margin:14px 0}

/* numbered explainer steps ("Kako radi…") */
.steps-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:14px;margin-bottom:28px}
.step-card{background:var(--surface);border:1px solid var(--border);border-radius:14px;
  padding:18px 18px 16px;box-shadow:var(--shadow-card)}
.step-card__num{display:inline-flex;align-items:center;justify-content:center;
  width:30px;height:30px;border-radius:9px;background:var(--accent-soft);color:var(--primary-ink);
  font:600 13px var(--mono);margin-bottom:12px}
.step-card h3{margin:0 0 6px;font:600 14px var(--font);color:var(--text)}
.step-card p{margin:0;font-size:13px;line-height:1.5;color:var(--text-2)}

/* one canonical KPI tile (replaces 5 StockAI families) */
.kpi-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:14px;margin-bottom:28px}
.kpi-tile{background:var(--surface);border:1px solid var(--border);border-radius:13px;
  padding:18px 20px;box-shadow:var(--shadow-card)}
.kpi-tile__label{font:600 12.5px var(--font);color:var(--text-2)}
.kpi-tile__value{font:700 26px var(--mono);line-height:1.1;margin-top:8px;color:var(--text)}
.kpi-tile__value--ok{color:var(--ok-text)} .kpi-tile__value--warn{color:var(--warn-text)}
.kpi-tile__value--err{color:var(--err-text)}
.kpi-tile__value--pending{font:500 15px var(--font);color:var(--text-muted)}
.kpi-tile__note{margin:4px 0 0;font-size:12px;color:var(--text-muted)}
/* chip tone helpers reuse existing bg/text tokens */
.chip-ok{background:var(--ok-bg);color:var(--ok-text)} .chip-warn{background:var(--warn-bg);color:var(--warn-text)}
.chip-err{background:#FBECEC;color:#C0392B} .chip-info{background:var(--info-bg);color:var(--info-text)}

/* amount coloring (IOS review Iznos) */
.amount--neg{color:#B23B30;font-weight:600} .amount--zero{color:#7C89A0}

/* app-card enrichments (home) */
.app-card:hover{border-color:#C9D6E5;box-shadow:0 8px 24px rgba(16,24,40,.08)}

/* two-column teaser + help-card layout (ItemAI rules teaser) */
.split-2{display:grid;grid-template-columns:1.3fr 1fr;gap:18px;align-items:start}
@media (max-width:1100px){.split-2{grid-template-columns:1fr}}
.itemai-rules-list{margin:0 0 16px;padding:0;list-style:none;display:flex;flex-direction:column;gap:8px}
.itemai-rules-list li{font-size:13.5px;color:var(--text-2);padding-left:16px;position:relative}
.itemai-rules-list li::before{content:"";position:absolute;left:0;top:8px;width:6px;height:6px;border-radius:50%;background:var(--primary)}

/* the currently-UNDEFINED StockAI classes — define once here */
.panel{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-card);
  box-shadow:var(--shadow-card);padding:20px 22px}
.stack{display:flex;flex-direction:column;gap:18px}
.split-layout{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:18px;align-items:start}
.meta{font-size:12.5px;color:var(--text-muted)}
@media (max-width:1100px){.split-layout{grid-template-columns:1fr}}

/* automations audit dashboard — spacing wrapper around each client group;
   .section-head only carries a bottom margin, so consecutive groups need a
   top gap of their own to stay visually separated */
.audit-group{margin-top:32px}
.audit-group:first-of-type{margin-top:0}

/* automations audit dashboard — per-module accordion (native <details>, no
   JS). Collapsed by default; the view adds the `open` attribute when the
   module GET filter matches. Chevron rotate-on-open mirrors the existing
   .admin-user-details/.ios-details pattern for visual consistency across the
   portal's other disclosure widgets. */
.audit-module{border:1px solid var(--border);border-radius:11px;background:var(--surface)}
.audit-module + .audit-module{margin-top:12px}
.audit-module:hover{border-color:#C9D6E5}
.audit-module__summary{cursor:pointer;list-style:none;display:flex;align-items:center;
  gap:12px;padding:14px 18px}
.audit-module__summary::-webkit-details-marker{display:none}
.audit-module__summary::before{content:"";flex:0 0 auto;width:0;height:0;
  border-left:6px solid var(--text-2);border-top:5px solid transparent;border-bottom:5px solid transparent;
  transition:transform .15s ease}
.audit-module[open]>.audit-module__summary::before{transform:rotate(90deg)}
.audit-module[open]>.audit-module__summary{border-bottom:1px solid var(--border);margin-bottom:16px}
.audit-module__name{margin:0;font:600 15px var(--font);color:var(--text)}
.audit-module__pills{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-left:auto}
.audit-module__body{padding:0 18px 18px}

/* automations manage page — the workflow-picker search box the JS inserts
   in front of #id_n8n_workflow_id (progressive enhancement; degrades to the
   plain text input alone when this class/script never applies) */
.automations-picker-search{margin-bottom:8px}
.automations-picker-search:disabled{opacity:.6;cursor:not-allowed}

/* ===== Pagination (shared prev/next pager) ===== */
.pagination{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin:18px 0 0}
.pagination__info{font-size:13px;color:var(--text-2)}

/* itemai queue nav bar only (the plain .pagination above is also used by
   automations/executions.html with a different prev-info-next order —
   these two modifiers are additive and scoped to the queue's own markup,
   never touching the shared base rule). Rendered twice (top + bottom) from
   itemai/_queue_pagination.html, always with the info line, so the split
   layout puts the count on the left and the buttons on the right. */
.pagination--split{justify-content:space-between}
.pagination__nav{display:flex;gap:8px}

/* ===== Assistant chat (NOS AI asistent — AI Kanali) ===== */
.assistant-chat{margin-bottom:22px}
.assistant-chat__header{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:14px}
.assistant-chat__header h2{margin:0}
.assistant-chat__header p{margin:4px 0 0;font-size:13px;color:var(--text-2)}
.assistant-chat__messages{list-style:none;margin:0 0 14px;padding:2px;display:flex;flex-direction:column;gap:10px;max-height:420px;overflow-y:auto}
.assistant-chat__messages:empty{display:none}
.assistant-chat__msg{max-width:82%;padding:10px 14px;border-radius:12px;font-size:13.5px;line-height:1.5;white-space:pre-wrap;overflow-wrap:anywhere}
.assistant-chat__msg--user{align-self:flex-end;background:var(--info-bg);color:var(--info-text)}
.assistant-chat__msg--assistant{align-self:flex-start;background:var(--surface-tint);border:1px solid var(--border-2);color:var(--text)}
.assistant-chat__msg--system{align-self:flex-start;background:var(--warn-bg);color:var(--warn-text);font-size:12.5px}
.assistant-chat__tool{align-self:flex-start;font:500 12px var(--font);color:var(--text-muted);padding:0 4px}
.assistant-chat__typing{align-self:flex-start;font:500 12.5px var(--font);color:var(--text-muted);padding:0 4px}
.assistant-chat__composer{display:flex;gap:10px;align-items:flex-end}
.assistant-chat__composer textarea{flex:1;resize:vertical;min-height:44px}

/* ===== Results line — total filtered row count above a table, always
   visible even on a single page (e.g. executions list). ===== */
.results-line{font-size:13px;color:var(--text-2);margin:0 0 10px}

/* ===== AI fix suggestion card (executions popup + AI prijedlozi) ===== */
.fix-card{margin-top:10px;display:flex;flex-direction:column;gap:8px}
.fix-card__body{display:flex;flex-direction:column;gap:8px}
.fix-card__actions{display:flex;gap:8px;flex-wrap:wrap;margin-top:4px}
