/* 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__attention{display:inline-flex;align-items:center;margin-left:6px;padding:1px 6px;border-radius:var(--radius-pill);background:var(--warn-bg);color:var(--warn-text);font-size:11px;font-weight:700}
.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}
/* "Zadnje IOS obrade" only (NOT the shared .ios-table floor — the other IOS
   tables on this page keep 720px for their own wider content, e.g. the
   review queue's action buttons). At 1280px this table sits in one half of
   .ios-section-grid's two-column layout — measured live at a 410px scroll
   wrapper — and the shared 720px floor pushed its whole Status column,
   including the "Čeka potvrdu u razgovoru" badge, off-screen.
   FIX history (2026-09-01): a first pass lowered the min-width, betting on
   table-layout:auto to shrink-wrap the pills on its own. Measured live,
   that did NOT work: an auto-layout table NEVER renders narrower than the
   sum of each column's own minimum content width (CSS2.1 §17.5.2.2) — and
   with real content, that structural floor (~472px: two email addresses
   plus the badge's own full, deliberately un-wrapped text) sits ABOVE the
   410px this column actually has, regardless of any min-width/max-width
   set on the <table> itself (confirmed by forcing max-width:400px on the
   live element and observing zero change in rendered width). Stacking the
   pills vertically (.ios-status-stack below) is still correct and kept,
   but could not by itself close that gap.
   The actual fix is table-layout:fixed with explicit column widths (same
   documented precedent as .suppliers-table--settings): a fixed table DOES
   respect the width it's given regardless of content, at the cost of
   truncating whatever no longer fits. The Status column gets enough width
   for the FULL badge text unclipped (non-negotiable — this table's whole
   point); the other three columns' secondary detail lines (source/email,
   note) ellipsize via .ios-batches-cell__line and keep a title= attribute
   so the full value is still one hover away. */
.ios-table--batches{table-layout:fixed;min-width:0}
.ios-table--batches th:nth-child(1),.ios-table--batches td:nth-child(1){width:27%}
.ios-table--batches th:nth-child(2),.ios-table--batches td:nth-child(2){width:17%}
.ios-table--batches th:nth-child(3),.ios-table--batches td:nth-child(3){width:12%}
.ios-table--batches th:nth-child(4),.ios-table--batches td:nth-child(4){width:44%}
.ios-batches-cell__line{display:inline-block;max-width:100%;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap;vertical-align:top}
/* Always-stacked status pills for the "Zadnje IOS obrade" row (used only by
   the .ios-table--batches instance) — see the fix note above. Deliberately
   flex-direction:column, not flex-wrap: the latter only wraps once its own
   width is constrained smaller than the pills' combined width, which is
   exactly the fragile, content/viewport-dependent behavior this replaces.
   A column stack always shows one pill per line, in every browser and at
   every width, and shrink-wraps to the width of its widest pill (each pill
   keeps its own white-space:nowrap, so pill TEXT never breaks mid-word —
   only the pills themselves stack). */
.ios-status-stack{display:flex;flex-direction:column;align-items:flex-start;gap:4px}
.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}

/* Chat attachments (dokAI PDF intake via the paperclip) — chip list sits
   between the message log and the composer, empty/hidden until a file is
   staged. */
.assistant-chat__attachments{list-style:none;display:flex;flex-wrap:wrap;
  gap:8px;margin:0 0 10px;padding:0}
.assistant-chat__attachments:empty{display:none}
.assistant-chat__chip{display:inline-flex;align-items:center;gap:6px;
  max-width:240px;padding:5px 6px 5px 8px;border:1px solid var(--input-border);
  border-radius:var(--radius-pill);background:var(--surface-tint);
  font:500 12.5px var(--font);color:var(--text-2)}
/* Destination tag (IOS chat-intake part C): every chip is tagged with its
   module — DOKAI/IOS chats can both stage a document, so an unlabelled chip
   would leave the destination ambiguous. Small mono/uppercase pill borrowed
   from the .mono-tile identity-tile color pair (--accent-soft/--accent-ink)
   rather than a new palette. */
.assistant-chat__chip-tag{flex:0 0 auto;font:700 10px var(--mono);letter-spacing:.03em;
  text-transform:uppercase;color:var(--accent-ink);background:var(--accent-soft);
  border-radius:5px;padding:2px 5px}
.assistant-chat__chip-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.assistant-chat__chip-size{flex:0 0 auto;color:var(--text-muted);font-size:11.5px}
.assistant-chat__chip-remove{flex:0 0 auto;width:20px;height:20px;padding:0;
  border:0;border-radius:50%;background:transparent;color:var(--text-muted);
  font-size:15px;line-height:1;cursor:pointer}
.assistant-chat__chip-remove:hover{background:var(--err-bg);color:var(--err-text)}
.assistant-chat__chip-remove:focus-visible{outline:2px solid var(--primary);outline-offset:2px}
/* A chip for a file being uploaded — server hasn't confirmed it yet, so it
   carries no remove button (nothing to cancel/remove server-side) and a
   pulsing dot borrowed from the ItemAI "working" status idiom instead. */
.assistant-chat__chip--pending{opacity:.75;border-style:dashed}
.assistant-chat__chip-dot{flex:0 0 auto;width:6px;height:6px;border-radius:50%;
  background:var(--text-muted);animation:itemai-working-pulse 1.25s ease-in-out infinite}
/* Wraps the paperclip button so the destination menu (two stageable
   modules — dokAI and IOS) can anchor to it; a single stageable module
   renders the same plain button with no wrap-specific styling needed. */
.assistant-chat__attach-wrap{position:relative;flex:0 0 auto}
.assistant-chat__attach{flex:0 0 auto;display:inline-flex;align-items:center;
  justify-content:center;width:40px;height:40px;border:1px solid var(--input-border);
  border-radius:var(--radius-btn);background:var(--surface);color:var(--text-2);
  cursor:pointer}
.assistant-chat__attach:hover{border-color:#C9D6E5;color:var(--text)}
.assistant-chat__attach:disabled{opacity:.6;cursor:not-allowed}
.assistant-chat__attach:focus-visible{outline:2px solid var(--primary);outline-offset:2px}
/* Destination menu — same floating-panel tokens as .cell-pop__panel
   (surface/border/radius/shadow-pop) for visual consistency with the
   portal's other anchored popovers, opened/closed by JS (not a native
   <details>: Escape-to-close + focus-return need real keydown handling). */
.assistant-chat__attach-menu{position:absolute;left:0;bottom:calc(100% + 8px);z-index:40;
  list-style:none;margin:0;padding:6px;width:max-content;max-width:min(320px,70vw);
  background:var(--surface);border:1px solid var(--border);border-radius:12px;
  box-shadow:var(--shadow-pop)}
.assistant-chat__attach-menu[hidden]{display:none}
.assistant-chat__attach-menu-item{display:block;width:100%;text-align:left;
  padding:9px 10px;border:0;border-radius:8px;background:transparent;color:var(--text);
  font:500 13px var(--font);cursor:pointer}
.assistant-chat__attach-menu-item:hover,
.assistant-chat__attach-menu-item:focus-visible{background:var(--surface-tint);outline:none}
.assistant-chat__attach-menu-item:focus-visible{box-shadow:inset 0 0 0 2px var(--primary)}

/* ===== 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}
/* ===== Automations — Serveri (server cards, legend, report frame) =====
   Status dots reuse .status-pill--ok/--warn/--neutral (green/orange/grey). */
.server-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:14px;margin-bottom:28px}
.server-card{display:flex;flex-direction:column;gap:10px;padding:18px 20px;background:var(--surface);
  border:1px solid var(--border);border-radius:var(--radius-card);color:inherit;text-decoration:none}
.server-card:hover{border-color:var(--primary)}
.server-card__head{display:flex;align-items:center;justify-content:space-between;gap:10px}
.server-card__name{margin:0;font:700 15px var(--font);color:var(--text)}
.server-card__host{font-family:var(--mono);font-size:12px;color:var(--text-2)}
.server-card__row{display:flex;align-items:center;justify-content:space-between;gap:10px}
.server-card__label{font-size:13px;color:var(--text-2)}
.server-card__counts{display:flex;flex-wrap:wrap;gap:6px}
.server-legend{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 18px}
.code-block--tall{max-height:520px}
.server-report{width:100%;min-height:360px;border:1px solid var(--border-2);border-radius:11px;background:var(--surface)}
table.data tbody tr.is-selected > td{background:var(--info-bg)}
