/* ============================================================
   0. RESET & BASE
   ============================================================ */

/* ------------------------------------------------------------------
   FONTOVI — hostujemo ih SAMI (14.08.2026)

   Do sad su stizali sa `fonts.googleapis.com`. Taj `<link>` je bio
   stylesheet SA TUĐEG DOMENA u `<head>`-u, dakle resurs koji zaustavlja
   iscrtavanje dok se ne preuzme — poslednji takav posle popravke
   `NO_FCP`. Uz to su `fonts.googleapis.com` i `fonts.gstatic.com` morali
   u CSP listu (`TODO.md`), a svaka poseta je javljala Google-u da je
   neko otvorio aplikaciju.

   Fajlovi su u `fonts/`, jedan `woff2` po težini, sa SPOJENIM
   podskupovima (`cyrillic` + `latin` + `latin-ext` u istom fajlu). Zato
   ovde NEMA `unicode-range`: on postoji da bi se jedna težina podelila
   na više fajlova pa pregledač preuzeo samo potreban komad — kad je sve
   u jednom fajlu, nema šta da se deli.

   ⚠️ `latin-ext` nije izbor nego uslov: `č ć ž š đ` su tamo, ne u
   `latin`. `cyrillic` je zbog naziva artikala sa fiskalnih računa, koji
   umeju da stignu ćirilicom. Space Grotesk ćirilicu nema i ne treba mu —
   njime se pišu iznosi, a cifre su u `latin`.

   ⚠️ PUTANJA JE `fonts/`, NE `../fonts/`. Generator (google-webfonts-
   helper) pretpostavlja da CSS stoji u podfolderu `css/`; kod nas je
   `main.css` u korenu, uz sam folder `fonts/`. Na `kucnibilans.rs/` bi i
   `../fonts/` slučajno radilo (pregledač višak `..` na korenu odbaci),
   ali bi puklo pri deployu u podfolder — a njega projekat izričito
   podržava (`vite.config.js`, `base: "./"`).

   Ovde stoje TAČNO one težine koje se koriste. Preuzeti su bili i
   Manrope 200/300 i Space Grotesk 300/400/500; njihovi `@font-face`
   blokovi su uklonjeni, jer deklarisan a nekorišćen font niko ne
   preuzme ali se fajl svejedno šalje na server pri svakom deployu.

   ⚠️ Space Grotesk NEMA 800, a `.brand-title` ga traži. Pregledač tad
   sam podebljava 700 — isto kao i dosad preko Google-a, dakle nije
   regresija; zapisano da se ne traži fajl koji ne postoji.
   ------------------------------------------------------------------ */

/* Space Grotesk — iznosi, brojevi i naslovi. */
/* space-grotesk-600 - latin_latin-ext */
@font-face {
  font-display: swap;
  font-family: "Space Grotesk";
  font-style: normal;
  font-weight: 600;
  src: url("fonts/space-grotesk-v22-latin_latin-ext-600.woff2") format("woff2");
}
/* space-grotesk-700 - latin_latin-ext */
@font-face {
  font-display: swap;
  font-family: "Space Grotesk";
  font-style: normal;
  font-weight: 700;
  src: url("fonts/space-grotesk-v22-latin_latin-ext-700.woff2") format("woff2");
}

/* Manrope — sav ostali tekst. Težinu 500 koristi admin panel (`admin.js`). */
/* manrope-regular - cyrillic_latin_latin-ext */
@font-face {
  font-display: swap;
  font-family: "Manrope";
  font-style: normal;
  font-weight: 400;
  src: url("fonts/manrope-v20-cyrillic_latin_latin-ext-regular.woff2") format("woff2");
}
/* manrope-500 - cyrillic_latin_latin-ext */
@font-face {
  font-display: swap;
  font-family: "Manrope";
  font-style: normal;
  font-weight: 500;
  src: url("fonts/manrope-v20-cyrillic_latin_latin-ext-500.woff2") format("woff2");
}
/* manrope-600 - cyrillic_latin_latin-ext */
@font-face {
  font-display: swap;
  font-family: "Manrope";
  font-style: normal;
  font-weight: 600;
  src: url("fonts/manrope-v20-cyrillic_latin_latin-ext-600.woff2") format("woff2");
}
/* manrope-700 - cyrillic_latin_latin-ext */
@font-face {
  font-display: swap;
  font-family: "Manrope";
  font-style: normal;
  font-weight: 700;
  src: url("fonts/manrope-v20-cyrillic_latin_latin-ext-700.woff2") format("woff2");
}
/* manrope-800 - cyrillic_latin_latin-ext */
@font-face {
  font-display: swap;
  font-family: "Manrope";
  font-style: normal;
  font-weight: 800;
  src: url("fonts/manrope-v20-cyrillic_latin_latin-ext-800.woff2") format("woff2");
}

*,
*::before,
*::after {
  box-sizing: border-box;
}
html,
body {
  margin: 0;
  padding: 0;
}
body {
  min-height: 100dvh;
  background: #000000;
  font-family:
    "Manrope",
    -apple-system,
    BlinkMacSystemFont,
    sans-serif;
  -webkit-font-smoothing: antialiased;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  overscroll-behavior: none;
}

/* SAMO stranica aplikacije (index.html) — workflow.md #162.
   Pravne stranice koriste isti `main.css` i MORAJU da se skroluju, pa ovo ne
   sme da ide na goli `body`.

   BAG koji rešava: `body` je imao `min-height: 100dvh`, a `.app-shell`
   `min-height: 100dvh` PORED `height: calc(var(--real-vh) * 100)`. Kad god je
   `100dvh` ispao veći od stvarno vidljive visine (a na telefonu ispada — dvh
   se menja dok se traka pregledača skuplja, a `--real-vh` se osvežava tek na
   `resize`, koji iOS ne šalje pouzdano), `min-height` je pobeđivao `height`:
   ljuska postane viša od ekrana, STRANICA počne da se skroluje, i zaglavlje
   ode gore a donja navigacija dole. Tačno ono što se videlo na slici.

   Sad je visina JEDNA vrednost, bez `min-height` koji je može nadjačati, a
   `overflow: hidden` znači da stranica nema šta ni da skroluje — skroluje
   isključivo srednji deo (`.screen`, koji ima svoj `overflow-y: auto`). */
body.app-page {
  /* `position: fixed` + `inset: 0` (workflow.md #165) — jedina mera koja
     STVARNO zaustavlja skrolovanje stranice na telefonu.

     Prethodna verzija je zadavala visinu (`100dvh` / `--real-vh`) uz
     `overflow: hidden`. To sprečava skrol SADRŽAJA, ali element i dalje
     učestvuje u normalnom toku dokumenta — pa ako je izmerena visina i za
     piksel veća od stvarno vidljive (a jeste: `window.innerHeight` se menja
     dok se traka pregledača skuplja, i meri se u pogrešnom trenutku), ostane
     mali višak koji se može „povući". Tačno ono što se vidi na snimku: dođeš
     do kraja liste i ide još malo.

     Fiksiran element se meri prema vidljivom delu ekrana i NE MOŽE da se
     pomeri — nema šta ni da se povuče. Uz to, pošto koren dokumenta više
     nema šta da skroluje, traka pregledača se ne skuplja, pa visina prestaje
     da se menja u hodu (što je bio izvor cele zavrzlame).

     `--real-vh` ostaje u upotrebi za `.sheet` (max-visina modala). */
  position: fixed;
  inset: 0;
  overflow: hidden;
  min-height: 0;
  overscroll-behavior: none;
}
button,
input,
select,
textarea {
  font-family: inherit;
  color: inherit;
}
button {
  cursor: pointer;
  background: none;
  border: none;
}
input,
select,
textarea {
  outline: none;
}
ul {
  list-style: none;
  margin: 0;
  padding: 0;
}
h1,
h2,
h3,
h4,
p {
  margin: 0;
}
svg {
  display: block;
}
::selection {
  background: rgba(124, 156, 255, 0.35);
}

/* ============================================================
   0a. PRISTUPAČNOST (WCAG 2.1 AA / EN 301 549)
   ============================================================ */

/* Vidljiv fokus. Tri piksela i tamna „senka" ispod: sam plavi okvir se gubi na
   plavim dugmadima (`.btn-primary`), gde je najpotrebniji. `outline` je izabran
   namerno umesto `box-shadow` — jedini prati oblik elementa i preživljava
   režim visokog kontrasta. */
:focus-visible {
  outline: 3px solid #9db4ff;
  outline-offset: 2px;
  border-radius: 8px;
  box-shadow: 0 0 0 5px rgba(4, 5, 9, 0.85);
}

/* Sadržaj SAMO za čitače ekrana. Ne `display: none` i ne `visibility: hidden` —
   oba bi ga uklonila i iz čitača. Ovo ga sklanja sa ekrana, a ostavlja u
   dokumentu. */
.sr-only {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* „Preskoči na glavni sadržaj" — nevidljiv dok ne dobije fokus (prvi Tab). */
.skip-link {
  position: fixed;
  top: -100px;
  left: 12px;
  z-index: 200;
  padding: 12px 18px;
  border-radius: 0 0 12px 12px;
  background: #7c9cff;
  color: #0b0d14;
  font-weight: 700;
  font-size: 15px;
  text-decoration: none;
  transition: top 0.15s ease;
}
.skip-link:focus {
  top: 0;
}

/* ============================================================
   1. DESIGN TOKENS
   ============================================================ */
:root {
  --bg: #090a0f;
  --bg-soft: #141622;
  --surface: rgba(255, 255, 255, 0.04);
  --surface-2: rgba(255, 255, 255, 0.08);
  --border: rgba(255, 255, 255, 0.09);
  --border-soft: rgba(255, 255, 255, 0.045);

  --text: #ffffff;
  --text-dim: #a0a4ba;
  --text-dimmer: #64677a;

  --blue: #4c7eff;
  --blue-soft: rgba(76, 126, 255, 0.16);
  --pink: #f5568c;
  --pink-soft: rgba(245, 86, 140, 0.16);

  --accent: #7c9cff;
  --good: #3ed598;
  --warn: #ffc05aa2;
  /* ŽUTA ZA SIGNAL „nešto dospeva" (21.08.2026, korisnikov zahtev) — ikonica
     „Pregled" u dnu navigacije. Namerno NIJE `--warn`: on nosi providnost
     (`a2` = 64%), pa kroz `drop-shadow` daje bled narandžast oreol koji se na
     tamnoj pozadini jedva razlikuje od ugašene ikonice. Ovo je puna, neprozirna
     žuta — jedina boja u navigaciji koja se ne meša ni sa plavom
     (informacija) ni sa crvenom (greška). */
  --signal-yellow: #ffd93d;
  /* Crvena za "prekoračeno/greška" — ISTA koju već koristi .btn-danger.
     Postoji kao promenljiva jer je `var(--warn, #FF6B5E)` bio tiha greška:
     fallback iza zareza se aktivira SAMO ako promenljiva NE postoji, a
     --warn postoji (i narandžast je) — pa se crveno nikad nije prikazalo. */
  --bad: #ff6b5e;

  --r-lg: 24px;
  --r-md: 18px;
  --r-sm: 12px;
  --r-pill: 999px;

  /* ---- MERE KOJE SE MENJAJU PO ŠIRINI EKRANA (16.08.2026) --------------
     Postoje kao promenljive isključivo zato što su SPREGNUTE: bar dva
     nepovezana pravila u fajlu moraju da nose istu vrednost, a razlaz se ne
     vidi kao greška nego kao sadržaj koji viri iz kartice.

       --pad-screen  → `.screen` (bočni padding svakog ekrana)
       --pad-card    → `.card` I negativna margina `.chip-row`-a, koji „probija"
                       karticu do ivice. Kad bi bleed ostao veći od paddinga,
                       pilule bi izašle IZ kartice.
       --pad-sheet   → `.sheet` (modal koji klizi odozdo)
       --row-icon    → `.bill-icon`/`.notif-icon` (krug sa ikonicom u redu)
       --row-icon-gap→ razmak između tog kruga i teksta (`.bill-row-top`)
       --row-indent  → uvlačenje DONJEG sprata reda (`.bill-row-bottom`,
                       `.garancija-meta`, `.garancija-note`) tako da se poklopi
                       sa tekstom iznad. Ranije je bilo upisano kao 62px na tri
                       mesta, uz komentar „48px ikonica + 14px razmak" — sad se
                       stvarno računa iz njih.

     Vrednosti se menjaju SAMO u sekciji „MALI TELEFONI" na kraju fajla. */
  --pad-screen: 20px;
  --pad-card: 20px;
  --pad-sheet: 22px;
  --row-icon: 48px;
  --row-icon-gap: 14px;
  --row-indent: calc(var(--row-icon) + var(--row-icon-gap));

  --shadow-1: 0 8px 32px rgba(0, 0, 0, 0.4);
  --shadow-2: 0 20px 50px rgba(0, 0, 0, 0.45);

  --ease: cubic-bezier(0.25, 1, 0.3, 1);
}

/* ============================================================
   2. APP FRAME (mobile-first; phone mockup on desktop)
   ============================================================ */

/* Centrira sadržaj ekrana za prijavu/dobrodošlicu. Bezbedno je da ima
   height:100% jer se #authMount eksplicitno SAKRIJE (display:none) posle
   prijave (auth.js completeLogin()) — inače bi, čak i prazan, nastavio da
   zauzima ceo prostor u .app-shell-ovom flex rasporedu i survao ostatak app-a. */
#authMount {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  overflow-y: auto;
  /* Isti razlog kao kod `.screen` (workflow.md #165) — welcome ekran je duži
     od ekrana, pa se baš na njemu najlakše vidi višak na kraju skrola. */
  overscroll-behavior: contain;
  /* Prostor za sistemsku traku na dnu telefona — bez ovoga poslednje dugme
     na dugačkom ekranu (welcome) završi ispod nje. */
  padding-bottom: env(safe-area-inset-bottom);
}
/* BAG (workflow.md #151): ovde je stajalo `justify-content: center`.
   Dok je sadržaj bio kraći od ekrana (login forma) to je radilo. Welcome
   ekran je viši od ekrana, a centriranje VIŠAK deli na obe strane — pa je
   vrh završio IZNAD početka kontejnera i postao nedostupan (skrol ne ide u
   minus). Isto pravilo je već zapisano kao „bag na čekanju" u
   sledeci-koraci.md posle #141.

   Auto margine rade isto centriranje, ali SAMO kad ima viška prostora: kad
   sadržaj prelazi visinu, svedu se na 0 i ništa ne ispada iznad vrha. */
#authMount > *:first-child {
  margin-top: auto;
}
#authMount > *:last-child {
  margin-bottom: auto;
}

.app-shell {
  position: relative;
  width: 100%;

  /* Visina se NASLEĐUJE od `body.app-page` (koji je tačno vidljiva visina) —
     ovde više NEMA `min-height`, jer je baš on obarao raspored (vidi komentar
     uz `body.app-page`). `max-height` je pojas i tregeri: ljuska ne sme da
     preraste ekran ni ako neki sadržaj to zatraži. */
  height: 100%;
  max-height: 100%;
  min-height: 0;
  background: var(--bg);
  color: var(--text);
  /* `clip` umesto `hidden`, sa `hidden` kao rezervom za starije pregledače.
     Razlika je jedino u tome što `hidden` OSTAJE skrolabilan programski: kad
     bilo šta pozove `focus()`/`scrollIntoView()` nad elementom pri dnu modala,
     pregledač pomeri i ovu ljusku, a nje nema čime da se vrati — ekran ostane
     odgurnut nagore, sa crnom prazninom ispod. `clip` uopšte ne pravi
     skrol-kontejner, pa taj kvar postaje nemoguć. Pozivi su ispravljeni
     (`preventScroll`), ovo je druga brana za svaki sledeći. */
  overflow: hidden;
  overflow: clip;
  display: flex;
  flex-direction: column;
  isolation: isolate;
}
@media (min-width: 560px) {
  body {
    /* padding: 40px 16px; */
    align-items: center;
  }
  .app-shell {
    height: 100%;
    max-height: 100%;
    min-height: 0;
    border-radius: 40px;
    border: 8px solid #1a1c29;
    box-shadow: 0 40px 100px rgba(0, 0, 0, 0.8);
  }
}

/* ambient background glow orbs */
.bg-orbs {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
  /* `contain: paint` (workflow.md #165) — obećanje pregledaču da ništa odavde
     ne crta van ovih granica, pa promena u pozadini ne obara ceo ekran u
     ponovno crtanje. */
  contain: paint;
}
.orb {
  position: absolute;
  border-radius: 50%;
  filter: blur(70px);
  opacity: 0.25;
  /* Stalan sopstveni sloj (#165). Bez ovoga pregledač sam odlučuje kad da
     orb promoviše, a ta odluka se menja čim se iznad umetne nov element
     preko celog ekrana (modal) — pa se zamućenje od 70px računa iznova. */
  will-change: transform;
}
.orb-blue {
  width: 300px;
  height: 300px;
  background: var(--blue);
  top: -100px;
  left: -100px;
  animation: float1 15s ease-in-out infinite;
}
.orb-pink {
  width: 280px;
  height: 280px;
  background: var(--pink);
  bottom: 100px;
  right: -100px;
  animation: float2 18s ease-in-out infinite;
}
.orb-mint {
  width: 180px;
  height: 180px;
  background: var(--good);
  bottom: -60px;
  left: 30%;
  opacity: 0.15;
  animation: float1 20s ease-in-out infinite reverse;
}
/* BEZ `scale()` (workflow.md #165). Pomeranje (`translate`) kompozitor uradi
   sam, bez ijednog ponovnog crtanja. Skaliranje elementa sa `filter: blur(70px)`
   tera ga da zamućenje RAČUNA IZNOVA na svakom frejmu — tri velika kruga,
   neprekidno, dok je aplikacija otvorena. Razlika u izgledu je nevidljiva
   (5% na krugu koji je već rastočen na 70px), a pozadina prestaje da bude
   stalan izvor prekomponovanja. */
@keyframes float1 {
  0%,
  100% {
    transform: translate(0, 0);
  }
  50% {
    transform: translate(30px, 40px);
  }
}
@keyframes float2 {
  0%,
  100% {
    transform: translate(0, 0);
  }
  50% {
    transform: translate(-30px, -40px);
  }
}

/* ============================================================
   3. TOP BAR & STICKY BANERS
   ============================================================ */
.topbar {
  position: relative;
  z-index: 5;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 24px 24px 16px;
}
.topbar-actions {
  display: flex;
  gap: 8px;
}
.topbar-actions .icon-btn {
  width: 42px;
  height: 42px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text);
}
.brand {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
  flex: 1 1 auto;
}
.brand-mark {
  width: 60px;
  height: 60px;
}
.brand-text h1 {
  font-size: 16px;
  font-weight: 800;
  letter-spacing: -0.3px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
.brand-text p {
  font-size: 12px;
  color: var(--text-dim);
  margin-top: 1px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.brand-text {
  min-width: 0;
  flex: 1 1 auto;
}
.brand-title-row {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 8px;
  min-width: 0;
}
.tier-icon-btn {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 17px;
  flex: 0 0 auto;
  background: var(--surface);
  border: 1px solid var(--border);
}
.tier-icon-btn.tier-pro {
  background: rgba(124, 156, 255, 0.14);
  border-color: rgba(124, 156, 255, 0.35);
}
.tier-icon-btn.tier-premium {
  background: linear-gradient(
    135deg,
    rgba(76, 126, 255, 0.25),
    rgba(255, 92, 122, 0.25)
  );
  border-color: transparent;
}

/* Gornja lepljiva obaveštenja (Sticky Banner) - isključivo mala slova[cite: 5] */
#topAlerts {
  position: relative;
  z-index: 10;
  width: 100%;
  display: flex;
  flex-direction: column;
}
.sticky-banner {
  background: rgba(255, 193, 90, 0.12);
  border-bottom: 1px solid rgba(255, 193, 90, 0.25);
  color: var(--warn);
  padding: 10px 20px;
  font-size: 12px;
  font-weight: 700;
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  text-align: left;
  animation: fadeUp 0.3s var(--ease);
  cursor: pointer;
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
}
.sticky-banner svg {
  width: 14px;
  height: 14px;
  flex: 0 0 auto;
}
.savings-alert {
  background: rgba(245, 86, 140, 0.15);
  border: 1px solid rgba(245, 86, 140, 0.3);
  border-radius: 12px;
  margin: 10px 0;
  padding: 14px;
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  color: #ff8a80;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  cursor: default;
}
.savings-alert-actions {
  display: flex;
  gap: 8px;
  margin-top: 2px;
}
.mini-action-btn {
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--text);
  font-size: 11px;
  font-weight: 800;
  padding: 4px 10px;
  border-radius: var(--r-pill);
  cursor: pointer;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.mini-action-btn.good {
  color: var(--good);
}

/* ============================================================
   4. SCREENS & NAVIGATION
   ============================================================ */
.screens-wrap {
  position: relative;
  z-index: 2;
  flex: 1 1 auto;
  /* Isti razlog kao kod `.app-shell` — skrol ovde radi `.screen`, ovaj omotač
     ne sme da se pomeri ni programski. */
  overflow: hidden;
  overflow: clip;
  scroll-behavior: smooth;
}
.screen {
  position: absolute;
  inset: 0;
  /* Donjih 48px, ne 20px: `.nav-fab` („+" u navigaciji) ima
     `margin-top: -28px` i prsten `0 0 0 8px` od senke, pa se izdiže ~36px
     IZNAD navigacije i prelazi preko dna ekrana. Sa 20px su se dugmad
     „Otkaži"/„Potvrdi i sačuvaj račun" sudarala s njim (korisnikov izveštaj).
     Vrednost je globalna jer problem nije vezan za jedan ekran — pogađa svaki
     čiji sadržaj završava na dnu. */
  padding: 4px var(--pad-screen) 48px;
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  /* Zaustavlja „gumeni" višak na kraju liste (workflow.md #165). Bez ovoga se
     skrol koji je stigao do dna prosleđuje roditelju, pa se ceo ekran malo
     povuče i vrati — izgleda kao da iza sadržaja ima još nečega. */
  overscroll-behavior: contain;
  opacity: 0;
  transform: translateY(15px);
  /* `visibility` NIJE višak pored `opacity: 0` — ona je jedina od te dve koja
     element uklanja i iz ČITAČA EKRANA i iz reda za Tab. Svih 19 ekrana je
     stalno u DOM-u (vidi CLAUDE.md), pa je slep korisnik pre ovoga dobijao
     sadržaj svih devetnaest odjednom, kao jednu beskonačnu stranicu, a Tab je
     šetao kroz dugmad koja se ne vide.
     Odloženo za 0.3s (`0s linear 0.3s`) da se ekran koji odlazi i dalje vidi
     dok traje prelaz — bez odlaganja bi nestao u istom frejmu. */
  visibility: hidden;
  transition:
    opacity 0.3s var(--ease),
    transform 0.3s var(--ease),
    visibility 0s linear 0.3s;
  pointer-events: none;
}
.screen.is-visible {
  opacity: 1;
  transform: translateY(0);
  visibility: visible;
  transition:
    opacity 0.3s var(--ease),
    transform 0.3s var(--ease),
    visibility 0s linear 0s;
  pointer-events: auto;
}
/* Ekran dobija fokus pri prebacivanju (modules/pristupacnost.js) — bez ovoga
   bi oko njega iskočio okvir, iako to nije element koji se „bira". */
.screen:focus {
  outline: none;
}
.screen-head {
  padding: 12px 0 24px;
}
/* Dugme "Nazad" za ekrane "nivo dublje" (Krediti, Najjeftiniji artikal,
   Izvoz/Uvoz, Porodični rezultati, Pametni saveti, Štednja lista/izazov —
   dostupni samo preko Pregled-a/Štednja hub-a, nemaju svoju ikonicu u
   donjoj navigaciji). Stoji IZNAD .screen-head, ne unutra. */
.screen-back-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: none;
  border: none;
  padding: 4px 0;
  margin-top: 4px;
  font-size: 13px;
  font-weight: 700;
  color: var(--text-dim);
  cursor: pointer;
}
.screen-back-btn svg {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}
.screen-head h2 {
  font-size: 24px;
  font-weight: 800;
  letter-spacing: -0.3px;
}
.screen-head p {
  font-size: 14px;
  color: var(--text-dim);
  margin-top: 4px;
}

/* Donji meni optimizovan za 5 stavki bez preloma[cite: 4] */
.bottom-nav {
  position: relative;
  z-index: 20;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-around;
  padding: 8px 12px calc(14px + env(safe-area-inset-bottom, 0px));
  background: rgba(14, 16, 24, 0.85);
  backdrop-filter: blur(24px);
  -webkit-backdrop-filter: blur(24px);
  border-top: 1px solid var(--border);
}
.nav-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  color: var(--text-dimmer);
  font-size: 9.5px;
  font-weight: 700;
  padding: 4px 6px;
  border-radius: 12px;
  transition: color 0.2s;
  min-width: 50px;
}
.nav-btn svg {
  width: 22px;
  height: 22px;
  transition: transform 0.2s var(--ease);
}
.nav-btn.active {
  color: var(--text);
}
.nav-btn:active svg {
  transform: scale(0.9);
}
.nav-fab {
  width: 52px;
  height: 52px;
  border-radius: 50%;
  margin-top: -28px;
  background: linear-gradient(135deg, var(--blue), var(--pink));
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow:
    0 12px 30px rgba(245, 86, 140, 0.4),
    0 0 0 8px var(--bg);
  transition: transform 0.2s var(--ease);
  color: white;
}
.nav-fab svg {
  width: 24px;
  height: 24px;
}
.nav-fab:active {
  transform: scale(0.92);
}

/* ============================================================
   5. CARDS & MODERN COMPONENTS
   ============================================================ */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 16px;
  /* BEZ `backdrop-filter` — ovo je bio pravi uzrok bljeska pri otvaranju
     modala (workflow.md #165).
     `backdrop-filter` tera pregledač da za SVAKI takav element uzorkuje sve
     što je ispod njega. Na Početnoj ima 5-10 kartica, i sve to stoji iznad
     `.bg-orbs`, koji su `filter: blur(70px)` sa stalnom animacijom. Kad se
     preko svega toga umetne nov, preko celog ekrana — a modal je tačno to —
     svi ti uzorci moraju da se izračunaju ponovo u istom frejmu. Taj jedan
     frejm se vidi kao bljesak.
     Vizuelno se ne gubi gotovo ništa: `--surface` je belo na 4%, a iza
     kartica je skoro ravna tamna pozadina — zamućivanje ravne boje daje istu
     ravnu boju. Orbovi su ionako već zamućeni na 70px.
     Zamućenje je zadržano SAMO tamo gde sadržaj stvarno klizi ispod
     elementa: `.bottom-nav`, `.sticky-banner`, `.toast`, `.savings-alert`. */
  box-shadow: var(--shadow-1);
  padding: var(--pad-card);
}
.card + .card {
  margin-top: 16px;
}
.card-title {
  font-size: 12px;
  font-weight: 800;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.8px;
}

/* chips row */
.chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  overflow-x: auto;
  padding: 2px 0 4px;
  /* „Probija" karticu do njene ivice, pa poslednja pilula pri skrolu ne visi u
     vazduhu. Bleed MORA da prati `.card`-ov padding — vidi `--pad-card`. */
  margin: 10px calc(-1 * var(--pad-card));
  padding-left: var(--pad-card);
  padding-right: var(--pad-card);
}
.chip-row::-webkit-scrollbar {
  display: none;
}
.chip {
  flex: 0 0 auto;
  padding: 9px 16px;
  border-radius: var(--r-pill);
  background: var(--surface);
  border: 1px solid var(--border);
  font-size: 12.5px;
  font-weight: 700;
  color: var(--text-dim);
  white-space: nowrap;
  transition: all 0.2s var(--ease);
}
.chip.active {
  background: var(--text);
  color: #12141f;
  border-color: var(--text);
}
.chip:active {
  transform: scale(0.95);
}

/* buttons */
.btn {
  border-radius: var(--r-md);
  font-weight: 700;
  font-size: 15px;
  padding: 16px 24px;
  transition:
    transform 0.15s var(--ease),
    filter 0.15s;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
}
.btn:active {
  transform: scale(0.97);
}
/* Podrazumevana veličina ikonice unutar bilo kog dugmeta — dosad su samo
   specifični modifikatori (.btn-block, .btn-flex...) imali svoje pravilo,
   pa su ikonice u "golim" dugmadima padale na (preveliku) podrazumevanu
   veličinu browsera. */
.btn svg {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
}
/* Bazna mera SVIH ikonica-dugmadi. Do sad je `.icon-btn` bio goli `<button>`
   velik tačno koliko i SVG u njemu (20px), pa je meta za prst bila ispod
   svake preporuke, a razmak između dve ikonice se razlikovao od ekrana do
   ekrana. 34px je klik-zona; sam glif ostaje 20px i izgleda isto kao pre.
   `.topbar-actions .icon-btn` (42px, veća specifičnost) ostaje nepromenjen. */
.icon-btn {
  width: 34px;
  height: 34px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  border-radius: 50%;
}
.icon-btn svg {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
}
/* Kanta je UVEK crvena (nema hover na mobilnom, pa boja mora da nosi
   upozorenje sama) — vidi CLAUDE.md, "Konvencije koda". Ovo je varijanta za
   kantu unutar `.icon-btn`, koju do sad nije imao nijedan ekran: brisanje se
   svuda drugde radi punim `.tx-delete-btn`/`.row-action-btn danger`
   dugmetom, a u zaglavlju kartice štednje (workflow.md #135) nema mesta za
   takvo. */
.icon-btn-danger {
  color: var(--bad);
}
.btn-primary {
  background: linear-gradient(135deg, var(--blue), var(--pink));
  color: #fff;
  border: none;
  box-shadow: 0 8px 24px rgba(76, 126, 255, 0.3);
  filter: brightness(1.06);
}
.btn-danger {
  background: linear-gradient(135deg, #ff6b5e, #ff3b5c);
  color: #fff;
  border: none;
  box-shadow: 0 8px 24px rgba(255, 107, 94, 0.35);
  filter: brightness(1.06);
}
.btn-good {
  background: linear-gradient(135deg, #3ed598, #2bb583);
  color: #fff;
  border: none;
  box-shadow: 0 8px 24px rgba(62, 213, 152, 0.35);
  filter: brightness(1.06);
}
.btn-secondary {
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text);
}
.btn-ghost {
  background: transparent;
  color: var(--text-dim);
}
.btn-block {
  width: 100%;
  height: 52px;
}
.btn-block svg {
  height: 20px;
  width: 20px;
}

.btn[disabled] {
  opacity: 0.45;
  pointer-events: none;
}

/* inputs & fields */
.field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.field label {
  font-size: 11.5px;
  font-weight: 700;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.4px;
}
.input,
.select {
  background: rgba(0, 0, 0, 0.2);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: 12px 14px;
  /* 16px, ne 14px — i to je uslov, ne ukus. iOS Safari SAM uveća celu stranicu
     kad fokus uđe u polje manje od 16px, i posle toga je ostavi uvećanu. Dok
     je u `index.html` stajalo `maximum-scale=1`, to se nije videlo, jer je
     zumiranje bilo zabranjeno — ali ta zabrana je istovremeno oduzimala
     slabovidom korisniku jedini način da uveća tekst (WCAG 1.4.4). Kad je
     zabrana pala, veličina polja mora da je zameni. */
  font-size: 16px;
  color: var(--text);
  width: 100%;
  transition: border-color 0.2s;
}
.input-compact {
  padding: 9px 12px;
  font-size: 16px;
}
.input::placeholder {
  color: #757892; /* ~10% svetlije od --text-dimmer, radi bolje čitljivosti */
}
.input:focus,
.select:focus {
  border-color: var(--accent);
}
/* Ikonica kalendara kod input[type=date] je po difoltu tamna — nevidljiva na tamnoj pozadini */
input[type="date"]::-webkit-calendar-picker-indicator {
  filter: invert(0.85);
  cursor: pointer;
  opacity: 0.8;
}
.select {
  appearance: none;
  -webkit-appearance: none;
  background-image: none;
  padding-right: 34px;
  cursor: pointer;
}
.select-wrap {
  position: relative;
}
.select-wrap::after {
  content: "";
  position: absolute;
  right: 12px;
  top: 50%;
  width: 9px;
  height: 9px;
  border-right: 2px solid var(--text-dim);
  border-bottom: 2px solid var(--text-dim);
  transform: translateY(-70%) rotate(45deg);
  pointer-events: none;
}

/* badges */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 10px;
  border-radius: var(--r-pill);
  font-size: 11px;
  font-weight: 700;
  background: var(--badge-bg);
  color: var(--badge-color);
}
.badge-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--dot-bg);
}

/* avatars */
.avatar {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 800;
  font-size: 32px;

  font-family: "Space Grotesk", sans-serif;
  color: #fff;
  flex: 0 0 auto;
}
.avatar-ring {
  padding: 4px;
  border-radius: 50%;
  border: 2px solid var(--ring-color, var(--blue));
  display: inline-flex;
  flex: 0 0 auto;
}
/* Kategorije u Podešavanjima — SAMO ivica u boji kategorije + emoji, BEZ
   obojene pozadine kruga (korisnik: previše boje, ivica je dovoljna).
   Scoped na .category-manage-list da ne dira avatare članova/transakcija
   koji dele istu .avatar/.avatar-ring klasu svuda drugde u aplikaciji. */
.category-manage-list .avatar {
  background: transparent;
}
/* …i BEZ kruga oko emotikona (korisnikov zahtev, 13.08.2026).
   Prsten je ovde nosio boju kategorije, ali spisak ima 16+ redova jedan ispod
   drugog — što je značilo 16 obojenih krugova u koloni, a sam emotikon je
   ionako ono što se čita. Boja kategorije se i dalje vidi svuda gde nešto
   znači (Istorija, plan potrošnje, Top 10).
   ⚠️ Scoped na `.category-manage-list` namerno: `.avatar-ring` nosi boju
   ČLANA u „Aktivnoj grupi" i boju kategorije u Istoriji — tamo prsten ostaje.
   Ovo je izuzetak od pravila „emoji u krugu ima prsten" iz `CLAUDE.md`. */
.category-manage-list .avatar-ring {
  border: none;
  padding: 0;
}
/* Aktivna grupa — prsten (.avatar-ring) nosi izabranu boju člana, ali sam
   krug (emotikon) ostaje neutralan (korisnikov zahtev, isti razlog kao
   .category-manage-list .avatar iznad — previše boje na malom prostoru). */
.member-row .avatar {
  background: transparent;
}

/* toasts */
/* ============================================================
   TOASTS - OBAVEŠTENJA SA BOJAMA (PO DIZAJNU APLIKACIJE)
   ============================================================ */

.toast-stack {
  position: absolute;
  top: 14px;
  left: 0;
  right: 0;
  z-index: 90;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  pointer-events: none;
  padding: 0 20px;
}

.toast {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px 20px;
  border-radius: var(--r-pill, 999px);
  font-size: 13px;
  font-weight: 600;
  box-shadow: var(--shadow-2, 0 8px 30px rgba(0, 0, 0, 0.5));
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  transform: translateY(-20px);
  opacity: 0;
  transition:
    transform 0.32s var(--ease, cubic-bezier(0.22, 1, 0.36, 1)),
    opacity 0.32s var(--ease, cubic-bezier(0.22, 1, 0.36, 1));
  max-width: 92%;
  width: auto;
  min-width: 180px;
  justify-content: center;
  border: 1px solid rgba(255, 255, 255, 0.1);
  color: #ffffff;
}

.toast.show {
  transform: translateY(0);
  opacity: 1;
}

/* Ponovljen klik na dugme koje daje ISTU poruku (ui.js, TODO.md stavka 9).
   Umesto još jednog toasta preko prvog, postojećem se vraća odbrojavanje i
   dobija kratak trzaj — bez njega bi drugi klik izgledao kao da ne radi
   ništa. Kratko i suzdržano namerno: ovo je potvrda prijema, ne upozorenje. */
.toast.is-repeat {
  animation: toast-repeat 0.34s var(--ease, cubic-bezier(0.22, 1, 0.36, 1));
}

@keyframes toast-repeat {
  0% {
    transform: translateY(0) scale(1);
  }
  40% {
    transform: translateY(2px) scale(1.035);
  }
  100% {
    transform: translateY(0) scale(1);
  }
}

/* Ko je isključio animacije u sistemu ne dobija ni ovu — poruka je i dalje
   tu, odbrojavanje se i dalje vraća na početak. */
@media (prefers-reduced-motion: reduce) {
  .toast.is-repeat {
    animation: none;
  }
}

.toast svg {
  width: 18px;
  height: 18px;
  flex: 0 0 auto;
}
.toast-icon-wrap {
  display: flex;
  color: var(--toast-icon-color);
}

/* --------------------------------------------
   VRSTE TOAST-OVA (good, warn, error, info)
   -------------------------------------------- */

/* ✅ GOOD - uspeh, potvrda */
.toast-good {
  background: rgba(62, 213, 152, 0.2);
  border-color: rgba(62, 213, 152, 0.35);
  color: #3ed598;
}
.toast-good svg {
  color: #3ed598;
}

/* ⚠️ WARN - upozorenje */
.toast-warn {
  background: rgba(255, 193, 90, 0.2);
  border-color: rgba(255, 193, 90, 0.35);
  color: #ffc15a;
}
.toast-warn svg {
  color: #ffc15a;
}

/* ❌ ERROR - greška */
.toast-error {
  background: rgba(255, 107, 94, 0.2);
  border-color: rgba(255, 107, 94, 0.35);
  color: #ff6b5e;
}
.toast-error svg {
  color: #ff6b5e;
}

/* ℹ️ INFO - informacija */
.toast-info {
  background: rgba(76, 126, 255, 0.2);
  border-color: rgba(76, 126, 255, 0.35);
  color: #4c7eff;
}
.toast-info svg {
  color: #4c7eff;
}

/* --------------------------------------------
   DODATNO - Poboljšanja
   -------------------------------------------- */

/* Ako ima ikona levo, malo razmaka */
.toast .toast-icon {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Ako ima tekst, neka bude čitljiv */
.toast .toast-text {
  flex: 1;
  text-align: center;
  word-break: break-word;
}

/* Animacija za nestajanje */
.toast.removing {
  transform: translateY(-20px) scale(0.95);
  opacity: 0;
}

/* ============================================================
   6. DASHBOARD MODULES (Budžet, Alokacija, Pretraga, Grafikoni)
   ============================================================ */
.total-card .label {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.5px;
}
.total-value {
  font-family: "Space Grotesk", sans-serif;
  font-weight: 700;
  font-size: 42px;
  letter-spacing: -0.5px;
  margin-top: 6px;
}
.total-delta {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-top: 10px;
  font-size: 12.5px;
  font-weight: 700;
  padding: 5px 10px;
  border-radius: var(--r-pill);
}
.total-delta.up {
  background: rgba(255, 107, 94, 0.14);
  color: #ff8a80;
}
.total-delta.down {
  background: rgba(62, 213, 152, 0.14);
  color: var(--good);
}
.total-delta svg {
  width: 12px;
  height: 12px;
}
.total-remaining-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--border-soft);
}
.total-remaining-lbl {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.5px;
}
.total-remaining-val {
  font-family: "Space Grotesk", sans-serif;
  font-weight: 700;
  font-size: 18px;
  color: var(--good);
}
/* "Uplaćeno" i "Projekcija do kraja meseca" — sporedni redovi u kartici.
   Najvažniji broj je "Ukupno preostalo" iznad njih (18px, zelen); ova dva su
   kontekst, ne poruka. Smanjeni su i tekst i oznaka, i razmak između redova,
   jer su ranije bili skoro iste veličine kao glavni broj i vukli pogled na
   sebe (korisnikov zahtev). */
.total-remaining-row-muted .total-remaining-val {
  font-size: 12.5px;
  color: var(--text-dim);
}
.total-remaining-row-muted .total-remaining-lbl {
  font-size: 10.5px;
  letter-spacing: 0.4px;
}
.total-remaining-row-muted {
  margin-top: 8px;
  padding-top: 8px;
}

/* Progres barovi budžeta i minus režim[cite: 4] */
.budget-progress-wrap {
  width: 100%;
  height: 12px;
  background: var(--surface-2);
  border-radius: var(--r-pill);
  overflow: hidden;
  margin: 12px 0;
  box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.2);
  /* `backdrop-filter` uklonjen (#165) — traka je 12px visoka i stoji na
     neprozirnoj podlozi, pa zamućenje nije davalo NIŠTA, a plaćalo se istom
     cenom kao bilo koje drugo (vidi `.card`). */
}
.budget-progress-fill {
  height: 100%;
  background: linear-gradient(90deg, #3ed598, #45d6c4); /* Zeleni režim */
  border-radius: var(--r-pill);
  transition:
    width 0.4s var(--ease),
    background 0.4s var(--ease),
    box-shadow 0.4s var(--ease);
  box-shadow: 0 0 10px rgba(62, 213, 152, 0.4);
}

/* AGRESIVNOST BOJE (korisnikov zahtev, 09.08.2026) — pet nivoa, zeleno →
   crveno. Atribut `data-agresivnost` postavlja `refreshBudgetUI()` (budget.js),
   i to je JEDINO mesto koje o tome odlučuje. Isti nivoi znače različitu stvar u
   dva režima, a to je namerno:

     • SA budžetom  — nivo raste kako PREOSTALO pada (traka pokazuje preostalo)
     • BEZ budžeta  — nivo raste sa STEPENICOM potrošnje (20k, 40k, 80k…)

   Boja nije jedini nosilac informacije: iznos i granica stoje ispisani ispod
   trake, pa poruka postoji i za onoga ko boje ne razlikuje (pristupačnost —
   isto pravilo kao kod `.bill-row` statusa).

   `!important` nije potreban: ova pravila su specifičnija od osnovnog
   `.budget-progress-fill`. Prekoračen budžet (`.is-negative`) i dalje pobeđuje,
   jer ima svoj `!important` — to je stanje, ne stepen. */
.budget-progress-wrap[data-agresivnost="0"] .budget-progress-fill {
  background: linear-gradient(90deg, #3ed598, #45d6c4);
  box-shadow: 0 0 10px rgba(62, 213, 152, 0.4);
}
.budget-progress-wrap[data-agresivnost="1"] .budget-progress-fill {
  background: linear-gradient(90deg, #9ad46b, #cfd25a);
  box-shadow: 0 0 10px rgba(154, 212, 107, 0.4);
}
.budget-progress-wrap[data-agresivnost="2"] .budget-progress-fill {
  background: linear-gradient(90deg, #f2c14e, #f0a63c);
  box-shadow: 0 0 10px rgba(242, 193, 78, 0.4);
}
.budget-progress-wrap[data-agresivnost="3"] .budget-progress-fill {
  background: linear-gradient(90deg, #f58b4c, #f5684c);
  box-shadow: 0 0 10px rgba(245, 139, 76, 0.45);
}
.budget-progress-wrap[data-agresivnost="4"] .budget-progress-fill {
  background: linear-gradient(90deg, #ff6b5e, #f5568c);
  box-shadow: 0 0 12px rgba(255, 107, 94, 0.5);
}
.budget-progress-wrap.is-negative .budget-progress-fill {
  background: linear-gradient(
    90deg,
    #ff6b5e,
    #f5568c
  ) !important; /* Crveni režim za dozvoljeni minus */
  box-shadow: 0 0 10px rgba(255, 107, 94, 0.4) !important;
}
.budget-figures-row {
  display: flex;
  justify-content: space-between;
  gap: 10px;
}
.budget-figure {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.budget-figure .lbl {
  font-size: 11px;
  color: var(--text-dimmer);
  font-weight: 700;
  text-transform: uppercase;
}
.budget-figure .val {
  font-family: "Space Grotesk", sans-serif;
  font-weight: 700;
  font-size: 13.5px;
}
.payday-preview {
  font-size: 12px;
  color: var(--text-dim);
  margin: 4px 0 10px;
}
.payday-date-btn {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--surface);
  font-size: 13px;
  color: var(--text);
  text-align: left;
}
.allow-negative-row {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--text-dim);
  cursor: pointer;
  margin: 6px 0;
}
.manual-funds-row {
  display: flex;
  gap: 8px;
  margin-top: 14px;
  align-items: center;
}

/* Alokacija po kategorijama[cite: 4] */
.alloc-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 0;
  border-bottom: 1px dashed rgba(255, 255, 255, 0.05);
  min-height: 54px;
  height: auto;
}
.alloc-icon {
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 21px;
  /* GO EMOTIKON, bez kruga i bez pozadine (korisnikov zahtev, 15.08.2026).
     Plan potrošnje je bio POSLEDNJE mesto u aplikaciji gde je emotikon
     kategorije stajao u obojenom okviru — Istorija (`.tx-item-icon`),
     Top 10 (`.top-prod-icon`) i Podešavanja (`.category-manage-list .avatar`)
     su prsten izgubili ranije, pa je ista kategorija na dva ekrana izgledala
     kao dve različite stvari. Boja kategorije se ovde i dalje vidi tamo gde
     nešto znači — u traci napretka ispod naziva (`--fill-color`).
     Širina od 32px OSTAJE: drži nazive kategorija poravnate u koloni. */
  background: transparent;
  margin-right: 14px;
  flex-shrink: 0;
}
.alloc-info {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-right: 16px;
}
.alloc-name {
  font-size: 15px;
  font-weight: 700;
  color: #f2f3f7;
  margin-bottom: 4px;
  overflow-wrap: anywhere;
}
.alloc-spent-text {
  font-size: 12px;
  color: var(--spent-color);
  margin-bottom: 6px;
}
.alloc-progress-track {
  height: 6px;
  width: 100%;
  background: rgba(255, 255, 255, 0.06);
  border-radius: 4px;
  overflow: hidden;
}
.alloc-progress-fill {
  height: 100%;
  width: var(--fill-pct);
  background: var(--fill-color);
  border-radius: 4px;
  transition: width 0.4s ease;
}
.alloc-input-wrap {
  /* 80px → 94px: polje unutra je moralo na 16px (vidi `.input`), inače iOS
     uveća celu stranicu pri fokusu. Sa starom širinom bi se peticifren iznos
     sudarao sa ivicama. */
  width: 94px;
  flex-shrink: 0;
}
.alloc-input-wrap .input {
  width: 100%;
  min-width: 60px;
  padding: 10px 4px;
  text-align: center;
  font-size: 16px;
}
.allocation-sum-row {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 13px;
  color: var(--text-dim);
  margin-top: 12px;
  padding: 0 2px;
}
.allocation-sum-row.over {
  color: var(--warn);
}
.allocation-sum-warn {
  font-size: 11px;
  line-height: 1.4;
}

/* Search i rezultati */
.search-box {
  position: relative;
}
.search-box .input {
  padding-left: 40px;
}
.search-icon {
  position: absolute;
  left: 14px;
  top: 50%;
  transform: translateY(-50%);
  width: 16px;
  height: 16px;
  color: var(--text-dimmer);
  pointer-events: none;
}

.chart-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 10px;
}
.chart-card-head h3 {
  font-size: 14px;
  font-weight: 800;
}
.chart-wrap {
  position: relative;
  width: 100%;
  height: 210px;
}
.legend-list {
  display: flex;
  flex-direction: column;
  gap: 9px;
  margin-top: 14px;
}
.legend-row {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 12.5px;
}
.legend-row .dot {
  width: 9px;
  height: 9px;
  border-radius: 3px;
  flex: 0 0 auto;
  background: var(--dot-bg);
}
.legend-row .name {
  flex: 1 1 auto;
  min-width: 0;
  overflow-wrap: anywhere;
  color: var(--text-dim);
  font-weight: 600;
}
.legend-row .amt {
  font-family: "Space Grotesk", sans-serif;
  font-weight: 700;
}
.legend-row .pct {
  color: var(--text-dimmer);
  font-size: 11px;
  width: 34px;
  text-align: right;
}
/* ============================================================
   7. ISTORIJA TRANSAKCIJA
   ============================================================ */
.month-label {
  font-size: 11.5px;
  font-weight: 800;
  color: var(--text-dimmer);
  text-transform: uppercase;
  letter-spacing: 0.6px;
  margin: 18px 2px 8px;
}
.month-label:first-child {
  margin-top: 4px;
}

/* NASLOV DANA U ISTORIJI (20.08.2026, korisnikov zahtev) — lista je grupisana
   po danima, ne po mesecima. Levo isti stil koji je nosio `.month-label`
   (da se promena grupisanja ne oseti kao promena dizajna), desno ZBIR TOG
   DANA.

   Zbir je `Space Grotesk` kao svaki drugi iznos u aplikaciji, ali `--text-dim`
   a ne bela: on je kontekst za grupu redova ispod, a ne jedan od iznosa u
   listi — kad bi bio pun kontrast, čitao bi se kao još jedna transakcija.

   `align-items: baseline`, ne `center`: dva teksta različite veličine (11.5 i
   12px) centrirana po kutiji vidno „plivaju" jedan u odnosu na drugi. */
.day-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin: 18px 2px 8px;
}
.day-head:first-child {
  margin-top: 4px;
}
.day-head .lbl {
  font-size: 11.5px;
  font-weight: 800;
  color: var(--text-dimmer);
  text-transform: uppercase;
  letter-spacing: 0.6px;
  /* Naziv dana sme da se prelomi („Danas · 20. avgusta 2025."), zbir ne. */
  min-width: 0;
}
.day-head .sum {
  font-family: "Space Grotesk", sans-serif;
  font-weight: 700;
  font-size: 12px;
  color: var(--text-dim);
  white-space: nowrap;
  flex: 0 0 auto;
}
.tx-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  margin-bottom: 10px;
  overflow: hidden;
  transition: border-color 0.2s;
}
.tx-card.flash {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(124, 156, 255, 0.18);
}
.list-item-checkbox {
  width: 18px;
  height: 18px;
  margin: 0;
  accent-color: var(--accent);
  cursor: pointer;
  flex: 0 0 auto;
}
/* Podsetnik da postoji nešto što traži pažnju (nezavršena šoping lista,
   neplaćeni računi...) — koristi se na dugmadi u dnu navigacije (samo
   ikonica se pomera).

   ⚠️ BOJA IDE KROZ `--pulse-color`, a ne direktno. Razlog nije urednost nego
   kvar koji se ne vidi: `navGlowPulse` je do 21.08.2026. imao `var(--warn)`
   UPISAN U SAME KEYFRAME-ove, pa je pravilo ispod menjalo `color` i početni
   `filter` u plavo — a animacija je preko toga 1,8 s vraćala NARANDŽAST sjaj.
   Plava ikonica sa narandžastim oreolom, i to na dugmetu čija je cela svrha da
   se razlikuje od upozorenja. Sad keyframe čita promenljivu, pa svako dugme
   dobije sjaj u svojoj boji, a nova boja traži jedan red umesto svog
   keyframe-a. */
.has-pending svg {
  --pulse-color: var(--warn);
  color: var(--pulse-color);
  filter: drop-shadow(0 0 4px var(--pulse-color));
  transform-origin: center;
  animation:
    navGlowPulse 1.8s ease-in-out infinite,
    cartShake 2.6s ease-in-out infinite;
}
/* „Pregled" — ŽUTO (korisnikov zahtev, 21.08.2026). Pali ga sve što dospeva
   ispod tog dugmeta: račun, rata, obaveza iz planera ili garancija
   (`updatePregledNavPulse()` u `racuni.js`). Žuto je izabrano jer stoji tačno
   između dva značenja koja već postoje u navigaciji — plavo je informacija
   („imaš aktivnu listu"), crveno je greška, a ovo je rok koji se približava:
   traži pažnju, ali još nije problem. */
.nav-btn[data-nav="pregled"].has-pending svg {
  --pulse-color: var(--signal-yellow);
}
/* Šoping lista I Štednja koriste ISTI mehanizam kao gore, ali plavo —
   "aktivna lista"/"aktivna štednja ili porodični izazov" nisu upozorenja nego
   informativni indikatori, pa ne smeju da izgledaju kao rok koji ističe (koji
   JESTE upozorenje i ostaje žut).
   Štednja je dodata u workflow.md #110 — dotad je pulsirala narandžasto,
   iako je `updateStednjaNavPulse()` (stednja.js) i tada palio signal i za
   aktivan cilj i za aktivan porodični izazov. */
.nav-btn[data-nav="shopping"].has-pending svg,
.nav-btn[data-nav="stednja"].has-pending svg {
  --pulse-color: var(--accent);
}
/* Ista poruka, ali za pilule unutar Pregled ekrana — SAMO svetli (bez
   drmusanja/rotacije, to ostaje rezervisano za ikonice u dnu navigacije
   iznad — Arhiva/Štednja/Šoping lista). */
.btn.field-pending {
  animation: fieldGlowPulse 1.8s ease-in-out infinite;
}
@keyframes fieldGlowPulse {
  0%,
  100% {
    box-shadow: 0 0 0 0 rgba(255, 193, 90, 0);
  }
  50% {
    box-shadow: 0 0 0 3px rgba(255, 193, 90, 0.3);
  }
}
@keyframes navGlowPulse {
  0%,
  100% {
    filter: drop-shadow(0 0 2px var(--pulse-color, var(--warn)));
  }
  50% {
    filter: drop-shadow(0 0 7px var(--pulse-color, var(--warn)));
  }
}
@keyframes cartShake {
  0%,
  85%,
  100% {
    transform: rotate(0deg);
  }
  87% {
    transform: rotate(-10deg);
  }
  89% {
    transform: rotate(9deg);
  }
  91% {
    transform: rotate(-7deg);
  }
  93% {
    transform: rotate(6deg);
  }
  95% {
    transform: rotate(-3deg);
  }
  97% {
    transform: rotate(0deg);
  }
}
.tx-summary {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 15px;
  text-align: left;
}
.tx-info {
  flex: 1 1 auto;
  min-width: 0;
  /* `.tx-store` i `.tx-date` su `<span>`-ovi, dakle inline — bez ovoga se
     ređaju JEDAN PORED DRUGOG i naziv prodavnice se stopi sa datumom
     („DELHAIZE SERBIA Doo BEograd 1. avgusta 2026."). `margin-top` na
     `.tx-date` je iz istog razloga bio bez efekta: inline element ga
     ignoriše. Kolona ih razdvaja u dva reda. */
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}
.tx-store {
  font-size: 14.5px;
  font-weight: 800;
}
.tx-date {
  font-size: 11.5px;
  color: var(--text-dim);
  margin-top: 2px;
}
.tx-amount {
  font-family: "Space Grotesk", sans-serif;
  font-weight: 700;
  font-size: 14.5px;
  white-space: nowrap;
}
.tx-chev {
  width: 18px;
  height: 18px;
  color: var(--text-dimmer);
  transition: transform 0.3s var(--ease);
  flex: 0 0 auto;
}
.tx-summary[aria-expanded="true"] .tx-chev {
  transform: rotate(180deg);
  color: var(--text);
}
.tx-details {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.35s var(--ease);
}
.tx-details.open {
  grid-template-rows: 1fr;
}
.tx-details-inner {
  overflow: hidden;
  min-height: 0;
}
.tx-items {
  padding: 2px 15px 14px;
  border-top: 1px solid var(--border-soft);
}
.tx-item-row {
  display: flex;
  /* `flex-start`, ne `center` — otkad se naziv prelama u više redova
     (workflow.md #142), centriranje bi ikonicu i cenu ostavilo da „lebde"
     na sredini visokog reda. */
  align-items: flex-start;
  gap: 10px;
  padding: 9px 0;
}
.tx-item-row:not(:last-child) {
  border-bottom: 1px dashed var(--border-soft);
}
.tx-delete-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  margin: 6px 0 2px;
  padding: 10px;
  background: rgba(255, 107, 94, 0.18);
  border: 1px dashed rgba(255, 107, 94, 0.35);
  border-radius: var(--r-sm);
  color: #ff6b5e;
  font-size: 12.5px;
  font-weight: 700;
  cursor: pointer;
}
.list-active-badge {
  color: var(--good);
  background: rgba(62, 213, 152, 0.14);
}
/* Plava ivica na SVAKOJ nezavršenoj listi — direktno odgovara razlogu zašto
   "Šoping lista" ikonica u dnu navigacije svetli plavo (updateShoppingNavBadge(),
   shopping.js — bilo koja nezavršena lista). Ranije se ivica prikazivala
   SAMO uz Premium poklapanje cene (drugi, uži uslov), pa nije bilo jasno
   koja kartica "objašnjava" plavi sjaj kad poklapanja cene nema. */
.list-is-active {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent);
}
.list-match-badge {
  color: var(--warn);
  background: rgba(255, 159, 90, 0.14);
  margin-left: 6px;
}
.list-actions-row {
  display: flex;
  gap: 8px;
  margin: 6px 0 2px;
}
.list-actions-row .tx-delete-btn {
  margin: 0;
  flex: 1 1 0;
}
.list-edit-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  flex: 1 1 0;
  padding: 10px;
  background: rgba(124, 156, 255, 0.18);
  border: 1px dashed rgba(124, 156, 255, 0.35);
  border-radius: var(--r-sm);
  color: var(--accent);
  font-size: 12.5px;
  font-weight: 700;
  cursor: pointer;
}

.list-edit-btn svg {
  height: 18px;
}
.tx-delete-btn svg {
  width: 15px;
  height: 15px;
}
.tx-item-icon {
  width: 28px;
  height: 28px;
  border-radius: 9px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  flex: 0 0 auto;
  /* Bez obojene pozadine — samo prsten (vidi .alloc-icon). */
  background: transparent;
}
/* Naziv artikla i značka kategorije u SVOJOJ koloni (workflow.md #142) —
   pre toga su naziv, značka i cena bili tri direktna flex-deteta u istom
   redu, pa je značka promenljive širine gurala cenu i cene se nisu poravnale
   ni u jednom redu. Sad je cena jedini element desno od ove kolone. */
.tx-item-main {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 5px;
}
.tx-item-name {
  font-size: 13px;
  font-weight: 600;
  /* Nazivi sa fiskalnog računa su dugački („Krem duo mlec.kakao Maxi
     400g/KOM (Б)") — `nowrap` + `ellipsis` ih je sekao na pola, pa se u
     istoriji nije moglo pročitati šta je kupljeno. Prelamaju se u više
     redova; `anywhere` je zbog dugačkih delova bez razmaka (`145g/KOM`). */
  white-space: normal;
  overflow-wrap: anywhere;
}
/* Količina (workflow.md #143/#144). Prva verzija ju je prikazivala SAMO kad
   je veća od 1 („1×" je delovalo kao šum) — ali korisnik je tražio da se vidi
   UVEK, jer je količina podatak koji se unosi i očekuje se u pregledu. Sad
   stoji u svom redu, ispod naziva. */
.tx-item-qty {
  font-family: "Space Grotesk", sans-serif;
  font-weight: 700;
  font-size: 11.5px;
  color: var(--text-dim);
  white-space: nowrap;
}

/* Značka kategorije je od #143 DUGME (klik je menja) — mora da izgleda
   isto kao ranije `.badge` span, samo sa naznakom da je kliktabilna. */
.tx-item-cat-btn {
  border: none;
  cursor: pointer;
  font-family: inherit;
}
.tx-cat-edit-icon {
  width: 11px;
  height: 11px;
  opacity: 0.7;
}

/* Mreža za izbor kategorije (#143). `auto-fill` + `minmax` — na uskom
   telefonu daje 3 kolone, na širem 4-5, bez media query-ja. */
.cat-choice-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(94px, 1fr));
  gap: 8px;
  max-height: 40vh;
  overflow-y: auto;
}
.cat-choice {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 10px 6px;
  border-radius: var(--r-sm);
  border: 1px solid var(--border-soft);
  background: var(--surface-2);
  color: var(--text);
  font-family: inherit;
  cursor: pointer;
}
.cat-choice.is-active {
  border-color: var(--accent);
  background: rgba(76, 126, 255, 0.14);
}
.cat-choice-icon {
  font-size: 20px;
  line-height: 1;
}
.cat-choice-name {
  font-size: 11px;
  font-weight: 600;
  text-align: center;
  line-height: 1.25;
}
/* Emoji picker levo, naziv desno — picker ima fiksnu širinu da polje za
   naziv dobije sav preostali prostor. */
.new-cat-row {
  display: flex;
  align-items: flex-start;
  gap: 8px;
}
.new-cat-row .input {
  flex: 1 1 auto;
  min-width: 0;
}

.tx-item-price {
  font-family: "Space Grotesk", sans-serif;
  font-weight: 700;
  font-size: 13px;
  /* Fiksna kolona desno — sve cene u listi počinju na istoj liniji, bez
     obzira koliko je naziv dugačak. `nowrap` sprečava da se „230 RSD"
     prelomi u dva reda. */
  flex: 0 0 auto;
  min-width: 74px;
  text-align: right;
  white-space: nowrap;
}
/* Olovčica za izmenu artikla, skroz desno u redu (korisnikov zahtev,
   13.08.2026). `.icon-btn` daje klik-zonu od 34px i glif od 20px — ovde je
   red visok svega ~36px, pa bi puna mera pojela ceo red i gurnula cenu.
   Klik-zona ostaje 30px (i dalje iznad glifa, koji je 15px), a negativna
   desna margina je vraća do same ivice liste. */
.tx-item-edit-btn {
  width: 30px;
  height: 30px;
  flex: 0 0 auto;
  margin-right: -6px;
  color: var(--text-dimmer);
}
.tx-item-edit-btn svg {
  width: 15px;
  height: 15px;
}
.empty-state {
  text-align: center;
  padding: 10px 20px;
  color: var(--text-dim);
}
.empty-state .emoji {
  font-size: 34px;
  margin-bottom: 10px;
}
.empty-state p {
  font-size: 13px;
}
.empty-state-compact {
  padding: 24px 10px;
}

/* ============================================================
   8. SKENER & FORMULAR ZA UNOS
   ============================================================ */
.user-toggle-row {
  display: flex;
  gap: 10px;
}
.user-toggle {
  flex: 1 1 0;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 14px;
  border-radius: var(--r-md);
  border: 1.5px solid var(--border);
  background: var(--surface);
  transition: all 0.2s var(--ease);
}
.user-toggle .name {
  font-size: 13px;
  font-weight: 700;
}
.user-toggle .role {
  font-size: 10.5px;
  color: var(--text-dim);
}
.user-toggle.selected {
  border-color: var(--tg-color);
  background: var(--tg-soft);
}

/* Prečice (gore) i Skeniraj/Unesi ručno (dole) su DVA odvojena flex-child
   diva unutar .scan-stage — .scan-stage sam raste da popuni ceo preostali
   prostor ekrana (#screen-unos/#unosStage ispod), pa justify-content:
   space-between gura drugi div skroz na dno, bez potrebe za bilo kakvom
   linijom/marginom da se "izmisli" razmak. */
.scan-stage {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  justify-content: space-between;
  align-items: center;
  text-align: center;
  /* Bez dodatnog bočnog uvlačenja (nekad "30px 10px 10px") — dugmad se
     oslanja isključivo na .screen-ov osnovni padding (20px), kao svi ostali
     ekrani. */
  padding: 6px 0 10px;
}
.scan-shortcuts {
  width: 100%;
  display: flex;
  flex-direction: column;
}
.scan-main {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.scan-btn {
  /* Bilo 148px + 8px prsten (+14px u pulsu) = 176px vidljivog kruga, pa je
     na nižim telefonima udaralo u prečice iznad (workflow.md #159). Prvo
     smanjeno na 120px + 6px (140px ukupno) — i dalje se sudaralo (#161).
     Sad 96px + 5px prsten (+8px u pulsu) = 112px vidljivog kruga, i 26px
     razmaka: ukupno 64px niže nego pre prve popravke. */
  width: 96px;
  height: 96px;
  margin-top: 26px;
  border-radius: 50%;
  background: radial-gradient(
      circle at 30% 25%,
      rgba(255, 255, 255, 0.08),
      transparent 60%
    ),
    var(--surface);
  border: 1.5px solid var(--su-color, var(--blue));
  box-shadow:
    0 0 0 5px var(--su-glow, var(--blue-soft)),
    0 16px 32px rgba(0, 0, 0, 0.35);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  color: var(--text);
  animation: pulseRing 2.6s ease-in-out infinite;
  transition: transform 0.16s var(--ease);
}
.scan-btn:active {
  transform: scale(0.95);
}
.scan-btn svg {
  width: 26px;
  height: 26px;
  color: var(--su-color, var(--blue));
}
.scan-btn span {
  font-size: 12px;
  font-weight: 800;
}
@keyframes pulseRing {
  0%,
  100% {
    box-shadow:
      0 0 0 5px var(--su-glow, var(--blue-soft)),
      0 16px 32px rgba(0, 0, 0, 0.35);
  }
  50% {
    box-shadow:
      0 0 0 8px transparent,
      0 16px 32px rgba(0, 0, 0, 0.35);
  }
}
.scan-caption {
  font-size: 12.5px;
  color: var(--text-dim);
  margin-top: 18px;
  margin-bottom: 14px;
  max-width: 240px;
  line-height: 1.5;
}

/* ČITANJE QR KODA UŽIVO (`modules/qr.js`) — prikaz kamere koja sama pročita QR
   kod sa dna fiskalnog računa. Ovde se ništa ne slika i nema dugmeta za
   okidanje: kod se pročita čim uđe u kadar.

   Pravila su nasleđena od ranijeg, uklonjenog prikaza kamere (`.kamera-*`,
   koji je ostao u CSS-u bez ijednog korisnika) — odnos stranica 3/4 i crna
   pozadina su isti, promenjeni su samo nazivi i dodat je okvir za nišanjenje. */
.qr-stage {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 14px 4px 6px;
}
.qr-video-wrap {
  position: relative;
  width: 100%;
  aspect-ratio: 3 / 4;
  max-height: 360px;
  border-radius: var(--r-md);
  overflow: hidden;
  background: #000;
  border: 1px solid var(--border);
}
.qr-video-wrap video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* Okvir za nišanjenje. Čist ukras — jsQR traži kod po CELOM kadru, ne samo
   unutar okvira — ali bez njega korisnik ne zna koliko blizu da priđe. */
.qr-target {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 62%;
  aspect-ratio: 1;
  border: 2px solid rgba(255, 255, 255, 0.85);
  border-radius: var(--r-md);
  box-shadow: 0 0 0 100vmax rgba(0, 0, 0, 0.35);
  pointer-events: none;
}

/* Mesto za dugme lampice. Prazno je dok kamera ne javi da lampicu ima, pa ne
   sme da zauzima visinu — inače ekran „poskoči" sekundu posle otvaranja. */
.qr-torch-slot:empty {
  display: none;
}
.qr-torch-slot {
  margin-top: 12px;
  display: flex;
  justify-content: center;
}

/* Prozor „Kako da čitam račune?" — dva puta, svaki sa svojim dugmetom. */
.scan-method-option {
  margin-top: 14px;
  padding: 14px;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface-2);
}
.scan-method-option h4 {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 15px;
  margin-bottom: 8px;
}
/* `.popup-copy-mini` je flex red (ikonica + tekst); ovde su to rečenice koje
   se prelamaju, pa moraju kao običan blok. */
.scan-method-option .popup-copy-mini {
  display: block;
  margin-top: 6px;
  line-height: 1.5;
}
/* Spisak izmena u modalu „Šta je novo" (`modules/promene.js`).
   Jedino mesto u aplikaciji sa pravom `<ul>` listom — svuda drugde su redovi
   kartice. Ovde je lista tačna oznaka: stavke su nabrajanje bez redosleda i
   čitač ekrana ih tako i najavi („spisak, 3 stavke"). */
.promene-lista {
  margin: 0;
  padding-left: 20px;
  list-style: disc;
}
.promene-lista li {
  font-size: 13px;
  line-height: 1.55;
  color: var(--text-dim, #9295a8);
  margin-bottom: 8px;
}
.promene-lista li:last-child {
  margin-bottom: 0;
}

/* Koraci instalacije (`modules/instalacija.js`). Numerisana lista, jer je
   redosled ovde deo uputstva — čitač ekrana najavi „1. od 4". */
.instalacija-koraci {
  margin: 0;
  padding-left: 22px;
  list-style: decimal;
}
.instalacija-koraci li {
  font-size: 13px;
  line-height: 1.6;
  color: var(--text-dim, #9295a8);
  margin-bottom: 10px;
}
.instalacija-koraci li:last-child {
  margin-bottom: 0;
}
.instalacija-koraci strong {
  color: var(--text, #f2f3f7);
}

.tier-badge.free {
  background: rgba(62, 213, 152, 0.18);
  color: var(--good);
}

/* Dugme koje izgleda kao link — za sitne prečice unutar rečenice
   („Način: QR kod · promeni"). */
.link-btn {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  color: var(--accent);
  text-decoration: underline;
  cursor: pointer;
}

.loading-stage {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: 30px 20px;
}
.spinner {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: conic-gradient(from 0deg, var(--blue), var(--pink), var(--blue));
  animation: spin 1s linear infinite;
  position: relative;
  margin-bottom: 20px;
}
.spinner::after {
  content: "";
  position: absolute;
  inset: 6px;
  border-radius: 50%;
  background: var(--bg-soft);
}
@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

.loading-text {
  margin-top: 20px;
  margin-bottom: 12px;
  font-size: 16px;
  font-weight: 700;
  color: #f2f3f7;
}
.progress-bar-container {
  width: 100%;
  max-width: 280px;
  height: 8px;
  background: rgba(255, 255, 255, 0.08);
  border-radius: 4px;
  margin: 0 auto 8px auto;
  overflow: hidden;
  position: relative;
}
/* Dve trake, isto ponašanje: jedna na ekranu Unos, druga u modalu za
   završetak šoping liste (07.08.2026). Odvojeni id-jevi jer su oba ekrana
   stalno u DOM-u — id mora biti globalno jedinstven. */
#ocrProgressBar,
#checkoutOcrProgressBar {
  width: 0%;
  height: 100%;
  background: var(--accent, #4c7eff);
  border-radius: 4px;
  transition: width 0.1s ease;
}
.loading-sub {
  margin-top: 5px;
  font-size: 13px;
  color: #9295a8;
}

@keyframes fadeUp {
  from {
    opacity: 0;
    transform: translateY(14px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* `minmax(0, 1fr)`, NE `1fr` (16.08.2026). Kolona `1fr` je zapravo
   `minmax(auto, 1fr)`, dakle NIKAD se ne skuplja ispod min-content svog
   sadržaja — a u ovom redu skoro uvek stoji `input[type="date"]`, čiji
   min-content Chrome računa iz „dd.mm.gggg." + ikonice kalendara i iznosi
   ~150px na 16px fontu (a 16px je uslov, vidi `.input`). Dva takva polja +
   razmak traže ~310px, pa je red probijao karticu već oko 400px širine
   ekrana. Sa `minmax(0, …)` polje sme da se stisne; ispod 360px se red
   ionako razdvaja u dva reda (sekcija „MALI TELEFONI"). */
.form-row-2 {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 10px;
}
/* Sat/Minut selektori (Planer obaveza) — zamena za <input type="time">, koji
   prikazuje 12h ili 24h format u zavisnosti od lokala browsera/OS-a (van
   naše kontrole) — dva <select>-a garantuju 24h prikaz svuda. */
/* Sat i minut. Od 09.08.2026. stoje u SVOM redu, ispod datuma (ranije su
   delili red sa njim, pa su se stiskali u pola širine — prijavljeno).
   Zato više ne rastu do kraja reda: dva padajuća menija razvučena preko cele
   širine izgledaju kao da se u njima bira nešto veliko, a bira se dvocifren
   broj. `max-width` drži par na prirodnoj veličini, uz levu ivicu. */
.time-select-row {
  display: flex;
  align-items: center;
  gap: 6px;
  max-width: 220px;
}
.time-select-row .select-wrap {
  flex: 1 1 0;
  min-width: 0;
}
.time-select-sep {
  color: var(--text-dimmer);
  font-weight: 700;
}
.item-edit-row {
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--border-soft);
  border-radius: var(--r-sm);
  padding: 12px;
  margin-bottom: 10px;
}
.item-edit-top {
  display: flex;
  gap: 8px;
  align-items: center;
}
.item-edit-top .input {
  flex: 1 1 auto;
  /* Polje za unos ima sopstven min-content (~20 znakova, dakle ~175px na
     16px fontu) i bez ovoga se ne skuplja ispod njega — na uskom telefonu je
     guralo kantu za brisanje van reda. */
  min-width: 0;
}
/* Drugi red nosi ČETIRI stvari (kategorija, količina, cena, oznaka), pa mora
   da prelama na uskom telefonu — inače cena i oznaka izlaze iz kartice.
   Kategorija je fiksnih 44px (samo emotikon), pa cena dobija ostatak reda. */
.item-edit-bottom {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
  row-gap: 8px;
  margin-top: 8px;
}
/* Kategorija je SAMO EMOTIKON (korisnikov zahtev), i to dugme — ne suženi
   `<select>`. Suženi select je imao dva problema koja se nisu dala rešiti: pun
   naziv je bio odsečen na nasumičnom slovu, a strelicu za dole je crtao
   `.select-wrap::after`, pa je ostajala i posle sužavanja polja.
   Klik otvara `openCategoryPickerModal()` — isti modal kao u Istoriji.
   Namerno bez boje kategorije: u redu se već razlikuju naziv, količina i cena. */
.cat-pick-btn {
  flex: 0 0 44px;
  width: 44px;
  height: 38px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 19px;
  line-height: 1;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  cursor: pointer;
  /* Emotikon je tekst, pa bi bez ovoga nasledio font i veličinu dugmeta. */
  font-family: inherit;
  padding: 0;
}
.cat-pick-btn:active {
  border-color: var(--accent);
}
/* Oznaka „ručno" nije upozorenje nego konstatacija — zato bez žute boje koju
   `.auto-badge` inače nosi. Ista veličina i oblik, da red ne poskakuje kad se
   natpis promeni. */
.auto-badge.is-manual {
  color: var(--text-dim);
  background: rgba(255, 255, 255, 0.07);
}
.price-input-wrap {
  position: relative;
  width: 108px;
  flex: 0 0 auto;
}
.price-input-wrap .input {
  /* Bilo 34px — PREMALO. Sufiks "RSD" (.price-suffix ispod) stoji na
     `right: 10px` i na 10.5px/700 je širok ~22px, dakle zauzima prostor do
     ~32px od desne ivice. Sa 34px paddinga ostajalo je 2px zazora, pa se
     uneta cifra (i placeholder) vizuelno sudarala sa "RSD" — pogotovo kad
     font padne na sistemski fallback, koji je širi. 40px daje ~9px zazora,
     isti red veličine kao .password-field-wrap (44px za 38px dugme). */
  padding-right: 40px;
  text-align: right;
}
.price-suffix {
  position: absolute;
  right: 9px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 10.5px;
  color: var(--text-dimmer);
  font-weight: 700;
  pointer-events: none;
}
/* `.row-del-btn` (zaobljen kvadratić 30px sa crvenom podlogom) je UKLONJEN —
   kanta za brisanje sad svuda izgleda isto kao na kartici štednje:
   `.icon-btn.icon-btn-danger`, goli crveni glif bez podloge (korisnikov
   zahtev). Zamenjeno je na svih 7 mesta: unos, šoping (dva), obaveštenja,
   članovi porodice, kategorije u Podešavanjima, servisni dnevnik garancije.

   „Odbij zahtev" (`x` u porodica.js) je jedini koji je nosio istu klasu a
   nije kanta — i on prati istu meru, boju nosi sam glif. */

/* U redu obaveštenja stoje TRI dugmeta, ali samo jedno briše
   (workflow.md #164). Pravilo projekta je da je crveno rezervisano za
   brisanje — „označi kao pročitano" i „isključi tip" su povratne radnje, pa
   su zelena odnosno neutralna. Bez ovoga sva tri izgledaju podjednako opasno
   i korisnik okleva da klikne bilo koje.
   Podloge su skinute zajedno sa `.row-del-btn`: kanta pored njih više je
   nema, pa bi dva dugmeta sa podlogom i jedno bez izgledala neuredno. */
.notif-read-btn {
  color: var(--good);
}
.notif-mute-btn {
  color: var(--text-dim);
}
.row-edit-btn {
  width: 30px;
  height: 30px;
  border-radius: 9px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-dim);
  flex: 0 0 auto;
}
.row-edit-btn svg {
  width: 16px;
  height: 16px;
}
.auto-badge {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: 9.5px;
  font-weight: 800;
  color: var(--warn);
  background: rgba(255, 193, 90, 0.14);
  padding: 3px 7px;
  border-radius: var(--r-pill);
}
.auto-badge svg {
  width: 9px;
  height: 9px;
}

.add-item-btn {
  width: 100%;
  border: 1.5px dashed var(--accent);
  border-radius: var(--r-sm);
  padding: 12px;
  font-size: 12.5px;
  font-weight: 700;
  color: var(--text);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 60px;
  transition: all 0.18s;
}

.add-item-btn svg {
  height: 20px;
  width: 20px;
}

/* Kontrolni zbir sa dna računa — traka IZNAD liste očitanih stavki
   (`#zbirProvera`, unos.js). Bila je toast, pa je nestajala pre nego što
   korisnik stigne da pogleda listu na koju se odnosi. */
.zbir-provera {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 10px 12px;
  margin: 0 0 12px;
  border-radius: 12px;
  font-size: 13px;
  line-height: 1.45;
  border: 1px solid transparent;
}
.zbir-provera-znak {
  flex: 0 0 auto;
  line-height: 1.4;
}
.zbir-provera.is-ok {
  background: rgba(62, 213, 152, 0.14);
  border-color: rgba(62, 213, 152, 0.35);
  color: var(--text);
}
.zbir-provera.is-warn {
  background: rgba(255, 192, 90, 0.16);
  border-color: rgba(255, 192, 90, 0.45);
  color: var(--text);
}

.form-total-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 2px;
  margin: 4px 0 6px;
}
.form-total-row .lbl {
  font-size: 13px;
  font-weight: 700;
  color: var(--text-dim);
}
.form-total-row .val {
  font-family: "Space Grotesk", sans-serif;
  font-weight: 700;
  font-size: 19px;
}
.form-actions {
  display: flex;
  justify-content: space-between;
  gap: 5px;
  margin-top: 4px;
  /* Bez prelamanja dugme sa dugim natpisom („Potvrdi i sačuvaj račun") nema
     gde da stane na uskom telefonu — `width: fit-content` ispod mu ne da da
     se skupi, pa je izlazilo iz forme. Sa `wrap` se u tom slučaju spusti u
     svoj red. */
  flex-wrap: wrap;
}

.form-actions button {
  width: fit-content;
  padding: 10px;
}
/* Glavna radnja forme (uvek `.btn-block`) uzima SAV preostali prostor pored
   „Otkaži", umesto da stane na širinu teksta. `min-width: max-content` je
   ono što stvarno pokreće prelamanje: dugme ne sme da se stisne ispod svog
   natpisa, pa kad zajedno sa „Otkaži" ne stane, ide u novi red — tamo je
   samo i dobija punu širinu.
   Specifičnost (0,2,0) nadjačava `.form-actions button` (0,1,1) iznad. */
.form-actions .btn-block {
  flex: 1 1 auto;
  width: auto;
  min-width: max-content;
}

/* Dno forme za UNOS TROŠKA — „Otkaži" / „Potvrdi i sačuvaj račun".
   (korisnikov izveštaj 08.08.2026: „prelama se sa navigacijom dole")

   Natpis „Potvrdi i sačuvaj račun" je najduži u aplikaciji. U običnom
   `.form-actions` redu njegov `min-width: max-content` znači „nikad se ne
   skupljaj ispod svog teksta", pa na uskom telefonu red više ne staje i
   `flex-wrap` ga spušta u SVOJ red — tačno uz donju navigaciju, gde ga „+"
   dugme (koje visi ~16px iznad nje) preseca. Prelamanje je dakle bilo
   rešenje za jedan problem koje je napravilo drugi.

   Ovde je red GRID sa dve kolone i BEZ prelamanja: „Otkaži" uzima tačno svoju
   širinu, glavno dugme ceo ostatak (`minmax(0, 1fr)` mu dozvoljava da se
   skupi ispod max-content), a natpis se skuplja fontom umesto da gura red
   nadole. `clamp()` je vezan za širinu prozora: 13px na 320px telefonu,
   15px (nepromenjeno) od ~415px naviše. */
.form-actions.form-actions-unos {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 8px;
  /* Poslednji red forme dobija vazduh do navigacije preko `.screen`-ovih 48px
     — „+" iz navigacije visi iznad nje, pa 48px jeste dovoljno, ali tesno. */
  margin-bottom: 14px;
}
.form-actions.form-actions-unos .btn {
  width: auto;
  min-width: 0;
  white-space: nowrap;
  font-size: clamp(13px, 3.6vw, 15px);
}

/* Dva ravnopravna izbora jedan pored drugog — brisanje štednje („vrati u
   budžet" / „bez vraćanja"). Ravnopravna su, pa dele istu širinu i isti red;
   jedno ispod drugog bi sugerisalo da je gornje glavno.
   Natpisi su duži nego što `.btn` (15px) podnosi u pola širine, pa font pada
   na 13px i tekst sme da se prelomi u dva reda — `align-items: stretch` iz
   grida drži obe pločice iste visine i kad se samo jedna prelomi. */
.delete-choice-row {
  display: grid;
  /* `minmax(0, …)` iz istog razloga kao `.form-row-2` — natpisi su dugački
     („Vrati novac u budžet"), pa bi im min-content držao kolonu širom od
     polovine kartice. */
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 8px;
}
.delete-choice-row .btn {
  width: 100%;
  font-size: 13px;
  padding: 12px 10px;
  line-height: 1.3;
  text-align: center;
}
.delete-choice-row .btn svg {
  width: 16px;
  height: 16px;
}

/* Tri dugmeta jedna pored drugog, jednake širine — budžet akcije (Dodaj /
   Postavi / Resetuj) u Settings-ima, sve tri dele isti iznos iz JEDNOG
   input polja iznad (nema više odvojenog polja po dugmetu). */
.form-actions-3 {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
  margin-top: 4px;
}
.form-actions-3 .btn {
  width: 100%;
  padding-left: 6px;
  padding-right: 6px;
}

/* `.new-cat-inline` / `.new-cat-row2` / `.new-cat-color` / `.new-cat-confirm`
   su uklonjeni zajedno sa `showNewCategoryInline()` (unos.js) — nova kategorija
   se sad pravi u samom modalu za biranje, isto kao iz Istorije. */

/* ============================================================
   9. MODUL ŠTEDNJA (Savings Goals)[cite: 4]
   ============================================================ */
.savings-card {
  position: relative;
  transition: opacity 0.3s;
}
.savings-card.is-resolved {
  opacity: 0.5;
}
/* Plava ivica na SVAKOM nerešenom cilju — direktno odgovara razlogu zašto
   "Štednja" ikonica u dnu navigacije svetli plavo (updateStednjaNavPulse(),
   stednja.js — bar jedan nerešen cilj ili aktivan izazov). */
.savings-card.is-active {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent);
}
.savings-card-head {
  display: flex;
  align-items: center;
  gap: 12px;
}
.savings-icon {
  /* 36 -> 50: glif je na korisnikov zahtev 34px, u 36px kružiću ne bi imao
     nimalo vazduha. Odnos glif/podloga ~68%. */
  width: 50px;
  height: 50px;
  border-radius: 50%;
  background: var(--surface-2);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--pink);
  flex: 0 0 auto;
}
.savings-icon svg {
  /* +20% (18 -> 22) na korisnikov zahtev — glif u kružiću je bio sitan
     u odnosu na 36px podlogu. */
  width: 34px;
  height: 34px;
}
.savings-info {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.savings-name {
  font-size: 15px;
  font-weight: 800;
  overflow-wrap: anywhere;
}
.savings-deadline {
  font-size: 12px;
  color: var(--text-dimmer);
}
.savings-deadline.expired {
  color: #ff8a80;
  font-weight: 700;
}
.savings-pct {
  font-family: "Space Grotesk", sans-serif;
  font-weight: 700;
  font-size: 16px;
  flex: 0 0 auto;
}
.savings-progress-wrap {
  width: 100%;
  height: 6px;
  background: rgba(255, 255, 255, 0.06);
  border-radius: 99px;
  overflow: hidden;
  margin: 12px 0 8px;
}
.savings-progress-fill {
  height: 100%;
  width: var(--pct, 0%);
  background: var(--pink);
  border-radius: 99px;
}
.savings-amounts {
  display: flex;
  justify-content: space-between;
  font-size: 13px;
  font-family: "Space Grotesk", sans-serif;
  font-weight: 600;
}
.savings-amounts .dim {
  color: var(--text-dimmer);
}
/* Štednja BEZ planiranog iznosa nema traku napretka, pa `.savings-amounts`
   dolazi ODMAH ispod zaglavlja i lepi se za njega. Razmak koji je inače davala
   traka (`margin: 12px 0 8px`) mora tad da preuzme sam red sa iznosom —
   susedni selektor pogađa tačno taj slučaj i nijedan drugi. */
.savings-card-head + .savings-amounts {
  margin: 12px 0 8px;
}
.savings-transfer-row {
  display: flex;
  gap: 8px;
  margin-top: 14px;
  align-items: center;
}
/* Polje za iznos uzima SAV preostali prostor, a "Uplati"/"Povuci" se skupljaju
   uz desnu ivicu (workflow.md #111, korisnikov zahtev). Ranije je polje imalo
   fiksnih 108px (`.price-input-wrap`), pa je uneta cifra sa "RSD" sufiksom
   ostajala tesna bez obzira na padding — širina je bila pravi uzrok, ne
   padding. Sad je polje ~20%+ šire na svakoj širini ekrana, a sufiks ima
   trajno dovoljno vazduha. */
.savings-transfer-row .price-input-wrap {
  flex: 1 1 auto;
  width: auto;
  min-width: 0;
}
.savings-transfer-row .btn {
  flex: 0 0 auto;
}
.savings-transfer-row .input {
  /* 36px desno (bilo 34) — korisnikova izmena: sufiks se i dalje sudarao. */
  padding: 8px 36px 8px 8px;
  font-size: 13px;
}
.savings-transfer-row .btn {
  padding: 8px 12px;
  font-size: 12px;
  border-radius: var(--r-sm);
}
.savings-transfer-row .btn svg {
  width: 12px;
  height: 12px;
}
/* "Mimo budžeta" — stoji tik ispod polja za iznos, na koje se i odnosi, pa je
   razmak manji nego kod ostalih `.toggle-row` sekcija na kartici (auto
   transfer / Prikaži na Početnoj), koje su odvojene teme. */
.savings-external-row {
  margin-top: 8px;
  font-size: 12.5px;
}
/* Sklapanje kartice cilja. Isti `.tx-chev` glif i ista rotacija kao
   kolapsibilne sekcije na Računima — ali selektor tamo traži `.tx-summary`
   (celo zaglavlje je dugme), a ovde zaglavlje već sadrži "Izmeni"/"Obriši"
   dugmad, pa dugme u dugmetu nije moguće i chevron je zaseban. */
.goal-collapse-btn[aria-expanded="true"] .tx-chev {
  transform: rotate(180deg);
  color: var(--text);
}

/* ============================================================
   10. MODUL MESEČNI RAČUNI (Plaćeni / Neplaćeni)[cite: 4]
   ============================================================ */
.bill-row {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 12px 0;
}
.bill-row:not(:last-child) {
  border-bottom: 1px dashed var(--border-soft);
}
/* Dashboard verzija (cela kartica je klik-meta ka Kućnim računima, vidi
   dashboard.js/racuni.js goToBillRow) — samo ovde, ne na pravom Računi
   ekranu gde su akcije na pojedinačnim dugmadima unutar reda. */
.dashboard-bill-row {
  cursor: pointer;
}
/* Isti razlog kao .dashboard-bill-row iznad, samo za kredite/rate (klik
   vodi na Krediti ekran, dashboard.js/krediti.js goToLoanRow). */
.dashboard-loan-row {
  cursor: pointer;
}
/* Kredit / cilj štednje UNUTAR kartice na Početnoj. Otkad naslov stoji u
   kartici (isto kao Računi/Planer/Garancije), unutrašnja stavka više ne sme
   biti `.card` — to bi bila kartica u kartici, sa dve ivice i dve pozadine.
   Razdvajaju se istom vlas-linijom kao redovi računa, ne ivicom. */
.dashboard-sub-card {
  background: transparent;
  border: none;
  box-shadow: none;
  border-radius: 0;
  padding: 12px 0;
}
.dashboard-sub-card:not(:last-child) {
  border-bottom: 1px dashed var(--border-soft);
}
.dashboard-sub-card:first-of-type {
  padding-top: 0;
}
.dashboard-sub-card:last-child {
  padding-bottom: 0;
}
/* ============================================================
   POVUCI DA OSVEŽIŠ (modules/osvezavanje.js)
   ============================================================
   Traka koja se spušta sa vrha dok se prstom vuče nadole. Visinu joj daje
   `--pull`, koju postavlja JS dok prati prst — to je jedini slučaj u kom je
   inline stil dozvoljen (CSS promenljiva za PODATAK koji se stvarno menja,
   vidi ARCHITECTURE.md §11).

   `position: absolute` u `.app-shell`, ne `fixed`: shell je već `fixed` i
   pokriva ekran, a `fixed` unutar njega bi se na iOS-u lomio kad se pojavi
   tastatura. */
.pull-refresh {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: var(--pull, 0px);
  z-index: 30;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.2s var(--ease);
}
/* Bez klase `is-pulling` traka se ne vidi ni kad `--pull` slučajno ostane —
   prst je pušten, gest je gotov. */
.pull-refresh.is-pulling {
  opacity: 1;
}
.pull-refresh-text {
  font-size: 11.5px;
  font-weight: 700;
  color: var(--text-dimmer);
  white-space: nowrap;
}
/* Prag je pređen — boja potvrđuje da će puštanje prsta stvarno osvežiti. */
.pull-refresh.is-ready .pull-refresh-text {
  color: var(--accent);
}
.pull-refresh.is-ready .pull-refresh-text::after {
  content: " — pusti";
}
/* Dok osvežavanje traje, ceo sadržaj je malo providan: jedini znak da se
   nešto dešava, bez spinera preko ekrana. Klase nema kad se ne osvežava, pa
   ovo ništa ne košta u normalnom radu.

   ⚠️ Klasu dodaje SAMO osvežavanje koje je korisnik sam tražio (povuci-nadole)
   — vidi `refreshNow()` u `modules/osvezavanje.js`. Dok je stajala i na tihom
   osvežavanju, svaka izmena drugog člana zatamnila je ceo ekran na pola
   sekunde, pa je „uživo osvežavanje" izgledalo kao da se aplikacija stalno
   ponovo učitava (prijavljeno sa produkcije 13.08.2026). */
.is-refreshing .app-shell main {
  opacity: 0.6;
  transition: opacity 0.2s var(--ease);
}

/* Spisak predloga za rekategorizaciju (istorija.js). Lista ume da bude duga —
   svaka stavka iz istorije koja bi po novim pravilima išla drugde — pa ima
   svoj skrol umesto da razvuče ceo modal. */
.recat-list {
  max-height: 42vh;
  overflow-y: auto;
  overscroll-behavior: contain;
}
.recat-row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  grid-template-areas: "check name" ". move";
  gap: 2px 10px;
  align-items: center;
  padding: 9px 0;
  border-bottom: 1px dashed var(--border-soft);
  cursor: pointer;
}
.recat-check {
  grid-area: check;
}
.recat-name {
  grid-area: name;
  font-size: 13px;
  font-weight: 700;
}
/* Prelaz „stara → nova" je objašnjenje, ne naslov — manji i prigušen, da se
   na prvi pogled čita SPISAK ARTIKALA, a tek onda šta im se dešava. */
.recat-move {
  grid-area: move;
  font-size: 11.5px;
  color: var(--text-dimmer);
}

/* Tekst u info-modalu (AI upozorenje o tempu) je cela poruka, ne uvodna
   rečenica — sme da bude visok i mora da diše. `.popup-copy` sam po sebi ima
   manji prored, pa se pet redova AI teksta slepi u blok. */
.info-modal-text {
  line-height: 1.65;
  margin-bottom: 16px;
  white-space: pre-line;
}

/* Prazan `.due-soon-inline` (preko 7 dana `dueSoonLabel()` vraća "") ne sme
   da ostavi razmak iza imena — bez ovoga se vidi „Struja " sa repom. */
.due-soon-inline:empty {
  display: none;
}
/* CELA sekcija „Dospeva" je prigušena (korisnikov zahtev) — i pravi računi iz
   sledećih meseci, i najave. Puna boja je rezervisana za „Treba da se plati":
   ono što traži radnju SADA. Rok koji dolazi za mesec dana ne sme da izgleda
   jednako hitno kao onaj sutra.
   Zato ide na sam kontejner sekcije, a ne na pojedinačan red. */
#billsLaterCard .tx-details-inner,
#obavezeKasnijeCard .tx-details-inner,
#loansLaterDetails .tx-details-inner {
  opacity: 0.55;
}
/* Naslov sekcije ostaje pun — on je oznaka, ne sadržaj, i mora se pročitati. */

/* Isti prigušen izgled za pojedinačnu NAJAVU kad stoji VAN sekcije „Dospeva"
   (kartica na Početnoj kad je prekidač „buduci rokovi" uključen).
   ⚠️ Unutar sekcije se NE primenjuje — dva opacity-ja se množe (0,55 × 0,55 =
   0,30), pa su najave ispadale duplo bleđe od ostalih redova u istoj sekciji.
   To je bio prijavljen „različit opacity". */
.bill-row-preview,
.savings-card-preview {
  opacity: 0.55;
}
#billsLaterCard .bill-row-preview,
#obavezeKasnijeCard .bill-row-preview,
#loansLaterDetails .savings-card-preview {
  opacity: 1;
}
/* GORNJI SPRAT: ikonica + naziv (rok ispod naziva). Ništa više — naziv time
   dobija ceo red i ne skraćuje se u tri tačke, što je bilo prijavljeno. */
.bill-row-top {
  display: flex;
  align-items: center;
  gap: var(--row-icon-gap);
}
/* Naziv sme da se prelomi u dva reda umesto da nestane pod „…" — ime računa
   je najvažniji podatak u redu. */
.bill-row-top .bill-name {
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
  line-height: 1.3;
  /* Naziv računa/garancije korisnik kuca sam („Infostan-stambenazajednica") —
     bez ovoga jedna dugačka reč bez razmaka ne može da se prelomi i gura ceo
     red preko ivice kartice. Na uskom telefonu je to jedini vidljiv kvar. */
  overflow-wrap: anywhere;
}
/* DONJI SPRAT: cena levo, glavna radnja („Plati") uz DESNU ivicu. Olovkica i
   kanta su od redizajna (korisnikov zahtev, `redizajn/kucni-racuni.png`) u
   GORNJEM spratu, uz naziv — ovde ostaje samo jedno dugme.
   `margin-left: auto` na njemu drži ga desno bez obzira koliko je cena duga;
   ne oslanja se na `.bill-amount`, koji u redu „Dospeva" (bez plaćanja) ostaje
   sam. */
.bill-row-bottom.row-actions-end {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  row-gap: 8px;
  padding-left: 0;
}
.row-actions-end > .row-action-btn {
  margin-left: auto;
}
/* Glavna radnja zadržava SVOJU meru — ne razvlači se preko reda (korisnikov
   zahtev: „ne povećavaš 'Plati' da uzme svu širinu").
   ⚠️ Selektor MORA nositi i `.row-action-btn`: bazno `.row-action-btn`
   (`flex: 1 1 0`) je NIŽE u fajlu i sa istom specifičnošću je pobeđivalo, pa
   je „Plati"/„Završi" i dalje gutalo ceo red — tačno to je bilo prijavljeno. */
.row-action-btn.row-action-inline {
  flex: 0 0 auto;
  height: 32px;
  padding: 0 12px;
  font-size: 12px;
}
/* `flex-wrap` je ovde OBAVEZAN, ne kozmetika: tri dugmeta (Plati/Izmeni/Obriši)
   na telefonu od 390px imaju ~142px ukupno, a same pilule traže ~85px svaka.
   Bez prelamanja se tekst prosto izlivao van pilule. Isto pravilo je ranije
   stajalo samo kod garancija (pet dugmadi); sad važi za svaki red. */
.bill-row-bottom {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  row-gap: 8px;
  /* Poravnato sa `.bill-info` iznad — mera se RAČUNA iz ikonice i razmaka
     (`--row-indent`), da se pri smanjivanju na uskom telefonu ne raziđu. */
  padding-left: var(--row-indent);
}
/* Isti kontejner, ali za kartice koje NISU `.bill-row` (kartica kredita je
   `.savings-card`). Razlika je samo u tome što nema ikonice iznad, pa ni
   poravnanja od 62px. Postoji da bi „Plati ratu / Izmeni / Obriši" na
   Kreditima izgledali identično istoj trojci na Računima — pre ovoga su
   koristili `.form-actions`, koji dugmad razvlači na krajeve
   (`justify-content: space-between` + `width: fit-content`). */
.row-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  row-gap: 8px;
}
/* Kad `.bill-row-bottom` nosi RADNJE (računi), a ne iznos (Početna, welcome
   kartice), poravnanje ispod ikonice se skida. */
.bill-row-bottom.row-actions {
  padding-left: 0;
}
/* Otkad su izmena i brisanje ikonice u zaglavlju, u redu ostaje SAMO glavna
   radnja („Plati", „Plati ratu", „Završi"). Ona ide uz DESNU ivicu i na svoju
   meru — razvučena preko cele kartice izgleda kao traka, a ne kao dugme, i
   sudara se sa ikonicama tačno iznad sebe.
   `flex: 0 1 auto` gasi `flex: 1 1 0` iz `.row-action-btn`, koji postoji zbog
   redova sa više dugmadi (garancije). */
.row-actions {
  justify-content: flex-end;
}
.row-actions > .row-action-btn:only-child {
  flex: 0 1 auto;
}
.bill-icon {
  /* 32 -> 48, isti razlog kao .savings-icon (34px glif se NIJE uklapao —
     prelivao bi kružić za 2px). Mera je promenljiva jer je `--row-indent`
     (uvlačenje donjeg sprata) izvodi iz nje. */
  width: var(--row-icon);
  height: var(--row-icon);
  border-radius: 50%;
  background: rgba(255, 193, 90, 0.1);
  color: var(--warn);
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
}
.bill-icon svg {
  /* +20% (16 -> 19), isti razlog kao .savings-icon svg. */
  width: 34px;
  height: 34px;
}
.bill-icon.paid {
  background: rgba(62, 213, 152, 0.1);
  color: var(--good);
}
.bill-info {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.bill-name {
  font-size: 14px;
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.bill-due {
  font-size: 11.5px;
  color: var(--text-dimmer);
  /* Poslednja brana (16.08.2026, izmereno na 320px). Red ima pet delova u
     istoj liniji — ikonica, naziv+rok, iznos i dve ikonice — pa na najužem
     telefonu ovom tekstu ostane ~87px, a „Rok: 15.08.2026." traži ~102px.
     Bez ovoga se datum ISCRTA preko iznosa (kutije se ne preklapaju, pa se
     kvar ne vidi ni kroz `scrollWidth` ni kroz granice ekrana — samo okom).
     Prelamanje datuma je ružno, ali se dešava tek kad mesta stvarno nema, i
     bolje je od dva broja jednog preko drugog. */
  overflow-wrap: anywhere;
}
.bill-amount {
  font-family: "Space Grotesk", sans-serif;
  font-weight: 700;
  font-size: 14px;
  flex: 1 1 auto;
}
/* Iznos u GORNJEM spratu (računi, garancije) stoji uz naziv i ne sme da guta
   preostalu širinu — inače gura status/rok pod ellipsis. U donjem spratu
   (Početna, welcome kartice) iznos je jedini sadržaj i tamo `flex: 1 1 auto`
   iznad ostaje ispravan. */
.bill-row-top > .bill-amount {
  flex: 0 0 auto;
  white-space: nowrap;
}
/* Olovkica "Izmeni" i crvena kanta na KRAJU gornjeg sprata (korisnikov
   zahtev) — isto mesto, ista veličina i isti razmak kao na kartici štednje,
   odakle je obrazac i preuzet. Važi za račune, obaveze i garancije; krediti i
   štednja imaju svoj `.savings-card-head`, koji ovo već radi.

   Skroz desno stižu same: `.bill-info` levo od njih ima `flex: 1 1 auto` i
   guta sav slobodan prostor. Veličinu i klik-zonu nosi bazna `.icon-btn`
   definicija (34px), pa ovde nema šta da se dodaje. */
.bill-pay-btn {
  padding: 6px 12px;
  font-size: 11.5px;
  border-radius: var(--r-pill);
  color: var(--warn);
  border-color: rgba(255, 193, 90, 0.3);
  flex: 0 0 auto;
  height: 32px;
}

/* ============================================================
   AKCIJE U REDU — JEDAN stil za sva dugmad tipa Plati/Završi/Izmeni/Obriši
   (workflow.md #110)
   ============================================================

   Pre ovoga su ista po značenju dugmad koristila TRI nepovezana sistema:
   `.bill-pay-btn` (32px pilula, 11.5px), `.row-edit-btn`/`.row-del-btn`
   (30x30 kvadratići, SAMO ikonica, bez teksta) i `.btn-good/.btn-danger` +
   `.btn-compact` (stil iz formi). Rezultat: u istom redu su stajala dugmad
   različite visine, različitog fonta i različitog oblika, a "Izmeni"/"Obriši"
   su bila samo ikonice bez natpisa dok je "Plati" imao tekst.

   Sad sva imaju: istu visinu (36px), isti font, isti pill oblik, ikonicu +
   natpis, i `flex: 1 1 0` — pa u redu zauzimaju JEDNAKE širine. Razlikuju se
   SAMO bojom po značenju (potvrdi / izmeni / obriši / neutralno). */
.row-action-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 36px;
  padding: 0 12px;
  border-radius: var(--r-pill);
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 700;
  border: 1px solid transparent;
  background: transparent;
  cursor: pointer;
  flex: 1 1 0;
  min-width: 0;
  white-space: nowrap;
  transition:
    background 0.15s,
    border-color 0.15s;
}
.row-action-btn svg {
  width: 15px;
  height: 15px;
  flex: 0 0 auto;
}
/* Glavna radnja reda — Plati (račun), Plati ratu (kredit), Završi (obaveza). */
.row-action-btn.confirm {
  color: var(--good);
  border-color: rgba(62, 213, 152, 0.35);
  background: rgba(62, 213, 152, 0.1);
}
.row-action-btn.edit {
  color: var(--blue);
  border-color: rgba(76, 126, 255, 0.35);
  background: rgba(76, 126, 255, 0.1);
}
.row-action-btn.danger {
  color: var(--bad);
  border-color: rgba(255, 107, 94, 0.35);
  background: rgba(255, 107, 94, 0.1);
}
/* Povratna/neutralna radnja (npr. "Vrati u zakazane") — bez jake boje, da ne
   konkuriše glavnoj radnji u istom redu. */
.row-action-btn.neutral {
  color: var(--text-dim);
  border-color: var(--border);
  background: transparent;
}

/* ============================================================
   11. TOP 10 PROIZVODA[cite: 4]
   ============================================================ */
.top-product-row {
  display: flex;
  /* `flex-start` — nazivi artikala se prelamaju u dva-tri reda, pa bi
     centriranje ostavilo rang, ikonicu i iznos da „lebde" na sredini. */
  align-items: flex-start;
  gap: 12px;
  padding: 10px 0;
}
.top-product-row:not(:last-child) {
  border-bottom: 1px solid var(--border-soft);
}
/* Sklopiv naslov kartice (workflow.md #144). Prvi takav na Početnoj —
   `.card-title` je do sad uvek bio običan `<div>`; ovde je unutar dugmeta,
   pa mora da poništi nasleđene stilove dugmeta (podloga, ivica, poravnanje). */
.card-collapse-btn {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  padding: 0;
  margin-bottom: 10px;
  background: none;
  border: none;
  color: inherit;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
}
/* Ista SVG strelica koju već koristi `.tx-chev` u Istoriji (workflow.md
   #145) — prva verzija je koristila tekstualni znak „▾", koji ne prati
   debljinu linije ni boju ostalih ikonica, pa je izgledao kao tuđ element. */
.card-chev {
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  color: var(--text-dim);
  /* Zatvoreno stanje: strelica gleda desno; otvoreno: nadole. */
  transform: rotate(-90deg);
  transition: transform 0.2s var(--ease);
}
.card-chev.open {
  transform: rotate(0deg);
}

/* „🔄 Spoji slične nazive" — na VRHU liste Top 10, ispod podnaslova
   (korisnikov zahtev; ranije je stajalo pored samog naslova, gde je na uskom
   telefonu stiskalo naslov u dva reda).
   Emotikon je tekst, pa mu treba eksplicitna veličina — isti razlog zbog kog
   `icon()` uvek mora da ima CSS pravilo veličine. */
.merge-names-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  width: 100%;
  padding: 9px 12px;
  margin-bottom: 10px;
  font-size: 12.5px;
  font-weight: 700;
  line-height: 1;
  font-family: inherit;
  color: var(--text-dim);
  background: var(--surface-2);
  border: 1px solid var(--border-soft);
  border-radius: var(--r-sm);
  cursor: pointer;
}
.merge-names-btn:active {
  border-color: var(--accent);
  color: var(--text);
}
/* Grupa u modalu za spajanje: jedan naslov („ostaje X") i ispod njega redovi
   sa čekboksom po obliku koji se u njega sliva. */
.merge-group {
  padding: 8px 0;
  border-bottom: 1px solid var(--border-soft);
}
.merge-group:last-child {
  border-bottom: none;
}
.merge-group-head {
  font-size: 12.5px;
  color: var(--text-dim);
  margin-bottom: 6px;
}
.merge-group-head strong {
  color: var(--text);
}

/* Red predloga = sama stavka (klikabilna, štiklira se) + dugme „nije isto".
   Dugme MORA biti van <label>-a — unutar njega bi svaki klik na ✕ usput
   preokrenuo i čekboks, pa bi odbijanje predloga izgledalo kao da ga je
   korisnik istovremeno i izabrao za spajanje. */
.merge-row {
  display: flex;
  align-items: center;
  gap: 8px;
}
.merge-row .recat-row {
  flex: 1;
  min-width: 0;
}
/* Crveno, kao sve što uklanja (konvencija projekta — nema hover na mobilnom,
   pa boja mora sama da kaže šta dugme radi). Veličina je namerno puna dodirna
   meta od 32px iako je znak mali: susedni element je čekboks, a promašaj bi
   ovde značio spojene nazive umesto odbijenog predloga. */
.merge-reject {
  flex: 0 0 auto;
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  border-radius: 50%;
  color: var(--bad);
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
}
.merge-reject:active {
  background: rgba(255, 107, 94, 0.14);
}

/* Rang i ikonica kategorije JEDNO ISPOD DRUGOG (workflow.md #144) — ranije
   su bili dva odvojena flex-deteta jedan pored drugog i trošili ~60px
   širine, na štetu naziva artikla koji se prelama u tri reda na telefonu. */
.top-rank-col {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  width: 34px;
}
.top-rank {
  font-family: "Space Grotesk", sans-serif;
  font-weight: 700;
  font-size: 13.5px;
  color: var(--text-dimmer);
}
.top-prod-icon {
  width: 30px;
  height: 30px;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 20px;
  /* Bez obojene pozadine — samo prsten (vidi .alloc-icon). */
  background: transparent;
  /* border: 1.5px solid var(--icon-ring, var(--border)); */
}
.top-prod-info {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.top-prod-name {
  font-size: 13.5px;
  font-weight: 700;
  /* Nazivi sa fiskalnog računa nose delove bez razmaka („145g/KOM"), isti
     razlog kao kod `.tx-item-name`. */
  overflow-wrap: anywhere;
}
.top-prod-meta {
  font-size: 11px;
  color: var(--text-dimmer);
}
.top-prod-total {
  font-family: "Space Grotesk", sans-serif;
  font-weight: 700;
  font-size: 13.5px;
  /* Ista ispravka kao `.tx-item-price` (workflow.md #142): bez fiksne
     kolone iznos je počinjao tamo gde se naziv završi, pa je svaki red imao
     drugačiju liniju — a duži iznosi („230 RSD") su se lomili u dva reda
     ispod kraćih („162 RSD"), što je izgledalo kao nasumičan raspored. */
  flex: 0 0 auto;
  min-width: 76px;
  text-align: right;
  white-space: nowrap;
}

/* ============================================================
   12. GRUPNI & MESEČNI MODALI / POP-UP PROZORI
   ============================================================ */
.modal-overlay {
  position: absolute;
  inset: 0;
  z-index: 60;
  /* BEZ `backdrop-filter` (workflow.md #162) — on je pravio BLJESAK celog
     ekrana pri otvaranju modala.
     Uzrok: `backdrop-filter` mora da pročita sve što je ISPOD sebe, a ispod su
     `.bg-orbs` sa `filter: blur(70px)` i beskonačnom animacijom. Kad se preko
     toga još i menja `opacity`, pregledač u istom frejmu pravi novi
     kompozitni sloj za ceo ekran — i taj jedan frejm se vidi kao bljesak.
     Na iOS-u zamućenje ionako nikad nije ni radilo: nedostajao je
     `-webkit-backdrop-filter`.
     Zamena je TAMNIJA podloga (0.6 → 0.72), koja daje isto odvajanje modala
     od pozadine, bez ijednog dodatnog sloja za crtanje.
     `translateZ(0)` + `will-change` drže sam prekrivač na SVOM sloju od prvog
     frejma, pa ni prelaz providnosti ne dira ostatak ekrana. */
  background: rgba(4, 5, 9, 0.72);
  display: flex;
  align-items: flex-end;
  justify-content: center;
  opacity: 0;
  pointer-events: none;
  /* `will-change: opacity` je UKLONJEN (workflow.md #165). Ima smisla samo za
     element koji na ekranu VEĆ STOJI pre nego što se animira; ovaj se pravi
     `innerHTML`-om neposredno pre otvaranja, pa je jedini efekat bio da se nov
     sloj preko celog ekrana napravi baš u frejmu u kom se sve ostalo ionako
     preračunava — dakle pojačavao je bljesak umesto da ga ublaži.
     `translateZ(0)` ostaje: on drži prekrivač na sopstvenom sloju tokom
     prelaza providnosti. */
  transform: translateZ(0);
  /* Isti razlog kao kod `.screen` — dva najveća modala („Aktivna grupa",
     Podešavanja) se pri zatvaranju NE brišu iz DOM-a nego samo gube klasu
     `.open`. Sa samo `opacity: 0` čitač ekrana je i dalje čitao ceo njihov
     sadržaj, a Tab ulazio u nevidljiva polja. */
  visibility: hidden;
  transition:
    opacity 0.28s var(--ease),
    visibility 0s linear 0.28s;
}
.modal-overlay.open {
  opacity: 1;
  visibility: visible;
  transition:
    opacity 0.28s var(--ease),
    visibility 0s linear 0s;
  pointer-events: auto;
}
/* Potvrda/transfer/mesečni pop-up (uvek kroz #monthlyPopupMount) mora da
   stoji IZNAD ostalih modala (Settings, Aktivna grupa) kad se otvori iz
   njih (npr. "Resetuj budžet" -> potvrda) — inače, na istom z-index-u,
   redosled u DOM-u bi ga sakrio ispod modala koji ga je otvorio. */
#monthlyPopupMount .modal-overlay {
  z-index: 65;
}
.sheet {
  width: 100%;
  background: #12141f;
  border: 1px solid var(--border);
  border-radius: 30px 30px 0 0;
  padding: 10px var(--pad-sheet) calc(26px + env(safe-area-inset-bottom, 0px));
  transform: translateY(100%);
  transition: transform 0.36s var(--ease);
  max-height: min(82%, calc(var(--real-vh, 1vh) * 92));
  overflow-y: auto;
}
.modal-overlay.open .sheet {
  transform: translateY(0);
}
.sheet-handle {
  width: 38px;
  height: 4px;
  border-radius: 3px;
  background: var(--border-soft);
  margin: 8px auto 14px;
}
.sheet-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 4px;
}
.sheet-head h3 {
  font-size: 16px;
  font-weight: 800;
}
.group-code-row {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  padding: 12px 14px;
  border-radius: var(--r-sm);
}
/* Beo okvir oko QR koda bez obzira na temu — kamere ga pouzdanije čitaju uz
   pun kontrast, tamna pozadina modala bi ga smanjila. */
.qr-code-wrap {
  display: flex;
  justify-content: center;
  padding: 16px;
  background: #fff;
  border-radius: var(--r-sm);
}
/* `qrcode.js` crta platno FIKSNIH 200px (porodica.js). Na uskom telefonu, uz
   padding modala i ovog okvira, to je tesno — a platno bez ovoga ne bi ni
   pokušalo da se smanji. Skaliranje QR koda je bezopasno: čita se oblik, ne
   rezolucija. */
.qr-code-wrap canvas,
.qr-code-wrap img {
  max-width: 100%;
  height: auto;
}
.group-code {
  font-family: "Space Grotesk", sans-serif;
  font-weight: 700;
  font-size: 15px;
  letter-spacing: 1px;
  flex: 1 1 auto;
}
.member-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 0;
}
.member-row:not(:last-child) {
  border-bottom: 1px solid var(--border-soft);
}
/* `min-width: 0` je OBAVEZAN, ne kozmetika: flex-dete se po difoltu ne skuplja
   ispod svog min-content-a, a ovde je min-content EMAIL ADRESA — jedan dugačak
   niz bez razmaka. Bez ovoga se ceo red člana raširio preko modala i „Ukloni"
   je izlazilo van ekrana. */
.member-info {
  flex: 1 1 auto;
  min-width: 0;
}
.member-name {
  font-size: 13.5px;
  font-weight: 700;
}
.member-role {
  font-size: 11.5px;
  color: var(--text-dim);
}
.member-email {
  font-size: 11px;
  color: var(--text-dimmer);
  /* Adresa nema razmak na kom bi se prelomila — bez ovoga se ne prelama uopšte
     (vidi `min-width: 0` na `.member-info`). */
  overflow-wrap: anywhere;
}
.sheet-divider {
  height: 1px;
  background: var(--border-soft);
  margin: 18px 0;
}
.invite-text {
  font-size: 12.5px;
  color: var(--text-dim);
  line-height: 1.5;
  margin-bottom: 14px;
}

/* Dinamičko kreiranje članova forme */
/* Biranje boje avatara pri registraciji — TAČNO 6 fiksnih neon boja
   (MEMBER_COLOR_PALETTE, data.js), ne slobodan <input type="color">. Prazna
   providna kockica sa neon ivicom u boji dok nije izabrana (isti "neon
   glow" jezik kao .has-pending/.field-pending upozorenja, samo statičan —
   ovde ne treba pulsiranje, nije upozorenje) — kad se izabere, kockica se
   ispuni tom bojom. */
.color-swatch-row {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}
.color-swatch-btn {
  width: 32px;
  height: 32px;
  border-radius: 10px;
  background: transparent;
  border: 2px solid var(--swatch-color);
  box-shadow: 0 0 10px 1px var(--swatch-glow);
  cursor: pointer;
  flex: 0 0 auto;
  transition:
    transform 0.15s var(--ease),
    box-shadow 0.15s var(--ease);
}
.color-swatch-btn:hover {
  transform: scale(1.08);
}
.color-swatch-btn.selected {
  background: var(--swatch-color);
  box-shadow: 0 0 16px 2px var(--swatch-glow);
}
.avatar-preset-row {
  display: flex;
  gap: 6px;
  overflow-x: auto;
  padding: 4px 0;
  margin-top: 8px;
}
.avatar-preset-btn {
  font-size: 26px;
  padding: 8px;
  background: var(--surface);
  /* border: 1px solid var(--border); */
  border-radius: 10px;
  cursor: pointer;
  transition: transform 0.1s;
}
.avatar-preset-btn.selected {
  border-color: var(--accent);
  background: var(--surface-2);
}
.savings-alert-actions .mini-action-btn {
  background: rgba(255, 255, 255, 0.2);
  /* `backdrop-filter` uklonjen (#165) — isti razlog kao kod `.card`. */
  transition: background 0.2s;
}

/* Mesečni pop-up vodič[cite: 4] */
.popup-copy {
  font-size: 13.5px;
  color: var(--text-dim);
  line-height: 1.5;
  margin-top: 10px;
}
/* Red "✅ Usluga je aktivirana …" — ponavlja se na 5 mesta (export.js,
   najjeftinije.js x2, pregled.js, stednja.js). Ranije je bio `flex-row gap-8`
   sa `align-items:center`, što je davalo DVA problema:
   1) `.popup-copy-mini` (tekst) nosi `margin-top:12px`, a ✅ span ne nosi
      ništa — pa su bili razmaknuti po vertikali iako su "centrirani";
   2) kad se tekst prelomi u dva-tri reda (a prelama se, rečenice su duge),
      `center` stavlja ✅ na sredinu CELOG bloka umesto uz prvi red.
   Ova klasa rešava oboje: poravnanje na VRH i nula margine na tekstu. */
.service-active-row {
  display: flex;
  /* `center`, NE `flex-start` (workflow.md #111, korisnikova ispravka —
     provereno uživo). `flex-start` poravnava GORNJE IVICE dva span-a, ali
     emoji i tekst nemaju istu visinu reda ni istu veličinu fonta, pa je
     rezultat izgledao pomereno gore-dole. `center` ih poravnava po sredini
     reda, što je vizuelno tačno u dominantnom slučaju (jedan red teksta).
     Za retke duge tekstove koji se prelome u 2-3 reda emoji ide na sredinu
     bloka — svesno prihvaćeno, jer je jednoredni slučaj pravilo. */
  align-items: center;
  gap: 8px;
}
.service-active-row > span:first-child {
  flex: 0 0 auto;
  line-height: 1.5;
}
.service-active-row .popup-copy-mini {
  margin-top: 0;
  line-height: 1.5;
}

.popup-copy-mini {
  font-size: 12px;
  color: var(--text-dimmer);
  margin-top: 12px;
  display: flex;
  align-items: center;
  gap: 6px;
}
.popup-copy-mini svg {
  width: 12px;
  height: 12px;
  color: var(--accent);
}

/* "Tvoj paket" pop-up (3 kartice paketa + linkovi) je znatno duži sadržaj
   od ostalih sheet-ova — bazni .sheet (min(82%, 92vh)) ostavlja veliku
   praznu traku na vrhu, a sam sadržaj se onda skoro dupliraj skroluje u
   uskom prostoru. Ide skoro do vrha ekrana umesto toga. */
#tierPickerOverlay .sheet {
  max-height: min(96%, calc(var(--real-vh, 1vh) * 96));
}

/* Registracija nove porodice ima dosta polja (email/lozinka/ime/prezime/
   uloga/avatar/boja/budžet/saglasnost) — ista logika kao tier picker iznad,
   veći max-height da manje skrolovanja treba da se dođe do dugmeta. */
#registerModalOverlay .sheet,
#newFamilySetupOverlay .sheet,
#joinProfileSetupOverlay .sheet {
  max-height: min(96%, calc(var(--real-vh, 1vh) * 96));
}

.password-field-wrap {
  position: relative;
}
.password-field-wrap .input {
  padding-right: 44px;
}
.password-toggle-btn {
  position: absolute;
  right: 4px;
  top: 50%;
  transform: translateY(-50%);
  width: 34px;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-dimmer);
  background: none;
  border: none;
  cursor: pointer;
}
.password-toggle-btn svg {
  width: 19px;
  height: 19px;
}
/* Pravilo za NOVU lozinku, ispod polja. Stoji samo tamo gde se lozinka
   POSTAVLJA (registracija, reset, promena, reset članu) — na polju za
   postojeću lozinku nema šta da traži. Prikazuje se PRE slanja forme; poruka
   posle slanja (`passwordProblem()`) nabraja tačno ono što fali. */
/* `.field-hint` je isti izgled pod bilo kojim poljem — dodat uz `.password-hint`
   umesto nove kopije pravila, i umesto da se ime „password" koristi ispod polja
   koje sa lozinkom nema veze (kod porodice zapamćen na uređaju). */
.password-hint,
.field-hint {
  display: block;
  margin-top: 6px;
  font-size: 11.5px;
  line-height: 1.35;
  color: var(--text-dimmer);
}

/* Stakleni efekat za dugmad u budžet kartici */
.budget-card .btn {
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}

/* Poboljšanje vidljivosti input polja u alokaciji */
#allocationForm .alloc-input {
  background: rgba(0, 0, 0, 0.35);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  color: var(--text);
  font-weight: 700;
  transition:
    border-color 0.2s ease,
    box-shadow 0.2s ease;
}

#allocationForm .alloc-input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(124, 156, 255, 0.15);
  outline: none;
}

.btn-flex {
  height: 48px;
}
.btn-flex svg {
  height: 20px;
  width: 20px;
}

/* Poboljšanje vidljivosti dugmeta za čuvanje alokacije */
#saveAllocationBtn {
  transition: all 0.3s ease;
}

#saveAllocationBtn:not([disabled]) {
  filter: brightness(1.1);
}

#saveAllocationBtn[disabled] {
  opacity: 0.4;
  cursor: not-allowed;
}
/* ============================================================
   UTILITY KLASE (zamena za ponavljane inline stilove po JS-u —
   menjaj razmak ovde, ne po komponentama)
   ============================================================ */
.mb-2 {
  margin-bottom: 2px;
}
.mb-4 {
  margin-bottom: 4px;
}
.mb-6 {
  margin-bottom: 6px;
}
.mb-8 {
  margin-bottom: 8px;
}
.mb-10 {
  margin-bottom: 10px;
}
.mb-12 {
  margin-bottom: 12px;
}
.mb-14 {
  margin-bottom: 14px;
}
.mb-16 {
  margin-bottom: 16px;
}
.mb-18 {
  margin-bottom: 18px;
}
.mb-20 {
  margin-bottom: 20px;
}
.mb-24 {
  margin-bottom: 24px;
}
.mb-0 {
  margin-bottom: 0;
}
.pt-14 {
  padding-top: 14px;
}
.mt-4 {
  margin-top: 4px;
}
.mt-6 {
  margin-top: 6px;
}
.mt-8 {
  margin-top: 8px;
}
.mt-10 {
  margin-top: 10px;
}
.mt-12 {
  margin-top: 12px;
}
.mt-14 {
  margin-top: 14px;
}
.mt-16 {
  margin-top: 16px;
}
.mt-18 {
  margin-top: 18px;
}
.mt-24 {
  margin-top: 24px;
}
.flex-row {
  display: flex;
  align-items: center;
}
.flex-col {
  display: flex;
  flex-direction: column;
}
.gap-6 {
  gap: 6px;
}
.gap-8 {
  gap: 8px;
}
.gap-10 {
  gap: 10px;
}
.gap-12 {
  gap: 12px;
}
.gap-14 {
  gap: 14px;
}
.flex-grow {
  flex: 1 1 auto;
}
.flex-fixed {
  flex: 0 0 auto;
}
.hidden {
  display: none;
}

/* Režim BEZ BUDŽETA (new-plan.md, Korak 3.1).
   Klasu `budget-off` postavlja applyBudgetModeClass() (budget.js) na
   #appShell kad `budget.budgetMode !== "on"`. SVE sakrivanje ide odavde, ne
   granjanjem u JS-u — inače bi svaki od desetak ekrana morao da zna za režim,
   a povratak na budžet bi tražio da se svaki od njih seti da vrati element.
   Ovako je dovoljno skinuti jednu klasu i sve se vraća netaknuto.
   `!important` jer neka od ciljanih pravila (npr. .total-remaining-row) imaju
   sopstveni `display: flex` koji bi inače pobedio po specifičnosti. */
.budget-off .budget-only {
  display: none !important;
}

/* Izuzetak za tok "uključi budžet" (new-plan.md, Korak 4.1 tačka 3).
   Kad korisnik u modalu potvrdi da hoće budžet, mora da vidi polje za iznos —
   a cela sekcija "Upravljanje budžetom" je u tom trenutku još sakrivena
   (režim postaje `pending` tek kad se iznos stvarno unese). Ova klasa otkriva
   SAMO tu sekciju, ostatak `budget-only` sadržaja ostaje sakriven.
   Skida je settings.js kad se iznos potvrdi ili kad se Podešavanja zatvore. */
.budget-off.budget-setup-open .settings-section .budget-only {
  display: revert !important;
}
.w-full {
  width: 100%;
}
.text-center {
  text-align: center;
}

/* ============================================================
   ŠOPING LISTA (izvučeno iz shopping.js — ranije inline stilovi)
   ============================================================ */
.modal-intro {
  margin: 10px 0 18px 0;
}
.modal-card-spacing {
  margin: 10px 0 16px 0;
}
.tx-items-empty {
  padding: 10px 0;
  color: var(--text-dim);
  font-size: 13px;
}
.shopping-item-name {
  flex: 1 1 auto;
  /* Isti razlog kao `.member-info`: naziv artikla korisnik kuca sam, a
     read-only kartica na Početnoj nema `.shopping-item-main` omotač koji ovo
     inače postavlja — pa je jedini put do prelivanja išao baš kroz nju. */
  min-width: 0;
  overflow-wrap: anywhere;
}
/* Kartica na Početnoj (dashboard.js) je read-only i nema dugme — tamo je
   `.bought` i dalje jedini nosilac precrtavanja. Na samoj Šoping listi tu
   ulogu ima `.is-bought` na celom redu (ispod). */
.shopping-item-name.bought {
  text-decoration: line-through;
  opacity: 0.5;
}
.shopping-item-added-by {
  font-size: 11px;
  color: var(--text-dimmer);
  flex: 0 0 auto;
}

/* ---- Red u Šoping listi (07.08.2026, korisnikov zahtev) ----------------
   Kućica za štikliranje je UKLONJENA: štiklira se klikom na sam artikal, a
   kupljena stavka dobija zelenu oznaku „štiklirano", prigušuje se i pada na
   dno liste. Kanta i „Izmeni" ostaju gde su bili.

   `.shopping-item-main` je DUGME preko celog naziva — meta je time širine
   reda umesto 18 px kućice, što je na telefonu jedina razlika koja se stvarno
   oseti. Namerno `align-items: center`: naziv je vertikalno centriran u odnosu
   na oznaku pored njega (traženo izričito), pa dugačak naziv u dva reda ne
   „visi" iznad ostatka. */
.shopping-item-row {
  align-items: center;
}
.shopping-item-main {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  padding: 6px 0;
  background: none;
  border: 0;
  text-align: left;
  color: inherit;
  font: inherit;
  cursor: pointer;
}
.shopping-item-main:disabled {
  cursor: default;
}
.shopping-item-main .shopping-item-name {
  min-width: 0;
  word-break: break-word;
}
/* Prigušenje ide na CEO red, ne samo na naziv — inače bi ime člana i kanta
   pored precrtane stavke ostali punog intenziteta i red bi izgledao napola
   obrađen. Kanta se vraća na punu vidljivost jer je i dalje upotrebljiva. */
.shopping-item-row.is-bought {
  opacity: 0.55;
}
.shopping-item-row.is-bought .shopping-item-name {
  text-decoration: line-through;
}
.shopping-item-row.is-bought .icon-btn-danger {
  opacity: 1;
}
/* Štiklica stoji dok stavka NIJE kupljena — to je meta za prst, ne potvrda.
   Prsten bez pozadine, po pravilu projekta za ikonice u krugu. */
.shopping-item-check {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border: 1.5px solid var(--good);
  border-radius: 50%;
  color: var(--good);
  background: transparent;
}
.shopping-item-check svg {
  width: 15px;
  height: 15px;
  flex-shrink: 0;
}
/* Polje za izmenu naziva već dodate stavke — niže od standardnog `.input`,
   da red ne poskoči kad se uđe u izmenu. */
.shopping-item-row.is-editing {
  gap: 6px;
}
.shopping-item-edit-input {
  height: 38px;
  padding: 0 10px;
  min-width: 0;
}
.shopping-item-edit-save svg {
  color: var(--good);
}
/* "Optimizuj kupovinu" (Premium) — puna anotacija ispod artikla u Šoping
   listi, kad je "Prikaži u Šoping listi" uključeno (shopping.js). */
.shopping-item-price-hint {
  font-size: 11.5px;
  color: var(--text-dimmer);
  padding: 0 0 8px 30px;
  margin-top: -4px;
  display: flex;
  align-items: center;
  gap: 5px;
}
.shopping-item-price-hint svg {
  width: 13px;
  height: 13px;
  flex-shrink: 0;
}
.list-add-item-row {
  display: flex;
  gap: 8px;
  margin-top: 10px;
}
.list-add-item-btn {
  flex: 0 0 auto;
  width: 48px;
  height: 48px;
  padding: 0;
}

/* ============================================================
   ULAZNA ANIMACIJA — DASHBOARD (elegantan fade+slide pri svakom ulasku)
   ============================================================ */
@keyframes dashFadeUp {
  from {
    opacity: 0;
    transform: translateY(14px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}
#screen-dashboard.is-visible > * {
  animation: dashFadeUp 0.5s var(--ease) both;
}
#screen-dashboard.is-visible > *:nth-child(1) {
  animation-delay: 0s;
}
#screen-dashboard.is-visible > *:nth-child(2) {
  animation-delay: 0.06s;
}
#screen-dashboard.is-visible > *:nth-child(3) {
  animation-delay: 0.12s;
}
#screen-dashboard.is-visible > *:nth-child(4) {
  animation-delay: 0.18s;
}
#screen-dashboard.is-visible > *:nth-child(5) {
  animation-delay: 0.24s;
}
#screen-dashboard.is-visible > *:nth-child(n + 6) {
  animation-delay: 0.3s;
}

/* ============================================================
   OBAVEŠTENJA / ZVONCE (notifikacije.js)
   ============================================================ */
.notif-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 2px;
  border-bottom: 1px solid var(--border-soft);
}
.notif-row:last-child {
  border-bottom: none;
}
.notif-row.unread {
  background: rgba(124, 156, 255, 0.06);
}
.notif-icon {
  display: flex;
  /* 34 -> 48, isti razlog kao .bill-icon. */
  width: var(--row-icon);
  height: var(--row-icon);
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: rgba(124, 156, 255, 0.14);
  color: var(--accent);
}
.notif-icon svg {
  /* +20% (16 -> 19), isti razlog kao .savings-icon svg. */
  width: 34px;
  height: 34px;
}
.notif-body {
  flex: 1 1 auto;
  min-width: 0;
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.notif-text {
  font-size: 12.5px;
  color: var(--text-dim);
  line-height: 1.4;
}
.notif-row.unread .notif-text {
  color: var(--text);
  font-weight: 700;
}
.notif-time {
  font-size: 10.5px;
  color: var(--text-dimmer);
}
.notif-bell-btn {
  position: relative;
}
.notif-badge {
  position: absolute;
  top: -2px;
  right: -2px;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: 99px;
  background: var(--pink);
  color: #fff;
  font-size: 9.5px;
  font-weight: 800;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* ============================================================
   TUTORIJAL (tutorijal.js)
   ============================================================ */
.tutorial-step {
  text-align: center;
  padding: 16px 6px 6px;
}
.tutorial-step-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 64px;
  height: 64px;
  margin: 0 auto 16px;
  border-radius: 50%;
  background: rgba(124, 156, 255, 0.14);
  color: var(--accent);
}
.tutorial-step-icon svg {
  width: 30px;
  height: 30px;
}
.tutorial-step-title {
  font-size: 17px;
  font-weight: 800;
  margin-bottom: 10px;
}
.tutorial-step-text {
  font-size: 13.5px;
  color: var(--text-dim);
  line-height: 1.5;
}
.tutorial-dots {
  display: flex;
  justify-content: center;
  gap: 6px;
  margin: 18px 0 16px;
}
.tutorial-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.15);
  transition: all 0.2s ease;
}
.tutorial-dot.active {
  background: var(--accent);
  width: 18px;
  border-radius: 4px;
}

/* ============================================================
   PODEŠAVANJA — redizajn (settings.js)
   ============================================================ */
.settings-section {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: 16px;
  margin-bottom: 14px;
}
.settings-section-title {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  font-weight: 800;
  margin-bottom: 12px;
  color: var(--text);
}
.settings-section-title svg {
  width: 16px;
  height: 16px;
  color: var(--accent);
  flex: 0 0 auto;
}
.toggle-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 4px 0;
}
.toggle-row-label {
  font-size: 12.5px;
  color: var(--text-dim);
  flex: 1 1 auto;
}
/* Objašnjenje ispod naziva prekidača — za ono gde posledica nije očigledna
   iz naziva („Ostavi me prijavljenog", workflow.md #152). */
.toggle-row-sub {
  display: block;
  margin-top: 3px;
  font-size: 11px;
  line-height: 1.4;
  color: var(--text-dimmer);
}
/* Jedna jedinstvena veličina za SVE toggle-switch dugmiće u aplikaciji
   (ranije je postojala i veća podrazumevana i .small varijanta — sad su
   spojene na ovu, manju, veličinu da nijedan prekidač ne odudara od
   ostalih). `.small` klasa je ostavljena u markup-u gde već postoji radi
   manjeg diff-a, ali više ne menja ništa. */
.toggle-switch {
  position: relative;
  display: inline-flex;
  width: 32px;
  height: 18px;
  flex: 0 0 auto;
}
.toggle-switch input {
  opacity: 0;
  width: 0;
  height: 0;
  position: absolute;
}
.toggle-slider {
  position: absolute;
  inset: 0;
  background: rgba(255, 255, 255, 0.12);
  border-radius: 99px;
  cursor: pointer;
  transition: background 0.2s ease;
}
.toggle-slider::before {
  content: "";
  position: absolute;
  height: 12px;
  width: 12px;
  left: 3px;
  top: 3px;
  background: #fff;
  border-radius: 50%;
  transition: transform 0.2s ease;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
}
.toggle-switch input:checked + .toggle-slider {
  background: var(--accent);
}
.toggle-switch input:checked + .toggle-slider::before {
  transform: translateX(14px);
}
/* "Prikaži na Početnoj" toggle UNUTAR rezultatske kartice (savings-card,
   loan card...) — ista isprekidana linija kao .auto-transfer-section, da
   se ne oseti kao "zalepljen" element koji ne pripada ostatku kartice. */
.dashboard-toggle-section {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px dashed var(--border-soft);
}
/* Kartica koja sadrži SAMO toggle-row (i po želji kratku status liniju
   iznad) — Plan potrošnje/Top proizvodi/Porodični rezultati/Pametni saveti/
   Najjeftiniji artikal ekrani. Manji padding od podrazumevanog .card (20px)
   da ne zauzima nepotrebno mesto za samo jedan red sadržaja. */
.toggle-only-card {
  padding: 14px 16px;
}

/* ============================================================
   PODEŠAVANJA — KATEGORIJE (settings.js)
   ============================================================ */
.plan-card {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: 16px;
}
.plan-card.selected {
  border-color: var(--accent);
  background: rgba(124, 156, 255, 0.08);
}
.plan-card.highlighted {
  border-color: var(--accent);
  background: rgba(124, 156, 255, 0.1);
  box-shadow: 0 0 0 1px var(--accent);
}
.plan-card-recommended {
  position: absolute;
  top: -10px;
  right: 16px;
  background: var(--accent);
  color: #fff;
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.3px;
  padding: 3px 10px;
  border-radius: var(--r-pill);
  text-transform: uppercase;
}
.plan-card-discount {
  display: block;
  font-size: 11px;
  font-weight: 700;
  color: var(--good);
  margin-bottom: 10px;
}
.plan-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 10px;
}
.plan-card-name {
  font-size: 15px;
  font-weight: 800;
}
.plan-card-price {
  font-size: 12px;
  font-weight: 700;
  color: var(--text-dim);
  /* Promotivni period: precrtana cena i „Besplatno" jedno ispod drugog,
     poravnati desno (kartica ima naziv levo, cenu desno). Kad naplata krene,
     ostaje samo jedan red i ova tri reda ne smetaju. */
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
}
.plan-card-price-old {
  color: var(--text-dimmer);
  font-weight: 600;
  text-decoration-thickness: 1.5px;
}
.plan-card-price-free {
  color: var(--good);
  font-size: 13px;
  font-weight: 800;
}
.plan-card-features {
  list-style: none;
  padding: 0;
  margin: 0 0 14px 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.plan-card-features li {
  font-size: 12.5px;
  color: var(--text-dim);
  padding-left: 18px;
  position: relative;
}
.plan-card-features li::before {
  content: "✓";
  position: absolute;
  left: 0;
  color: var(--good);
  font-weight: 700;
}

/* ============================================================
   PORODIČNI IZAZOV ŠTEDNJE — izbor težine (stednja-izazov.js)
   ============================================================ */
/* Vraćeno na stari (osnovni .card) izgled, samo malo manje od bazne
   .card (20px) — tri kartice jedna ispod druge su bile prevelike. */
.difficulty-card {
  padding: 14px 16px;
}
.category-manage-list {
  max-height: 320px;
  overflow-y: auto;
  margin-bottom: 12px;
}
.form-row-3-cat {
  display: grid;
  grid-template-columns: 44px 52px minmax(0, 1fr);
  gap: 8px;
  align-items: center;
}
.edit-cat-color {
  width: 44px;
  height: 44px;
  padding: 2px;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: rgba(0, 0, 0, 0.2);
  cursor: pointer;
  flex: 0 0 auto;
}
.edit-cat-icon {
  width: 52px;
  text-align: center;
  flex: 0 0 auto;
}

/* Emoji picker — dugme koje prikazuje trenutno izabran emoji, klik otvara
   grid sa izborom (umesto slobodnog kucanja teksta u polje). Grid je
   position:absolute (iskače iznad ostatka reda) da ne mora da menja uzak
   layout roditelja (.form-row-3-cat je grid sa fiksnom 52px kolonom). */
.emoji-picker {
  position: relative;
  width: 52px;
  flex: 0 0 auto;
}
.emoji-picker-trigger {
  width: 52px;
  height: 44px;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: rgba(0, 0, 0, 0.2);
  font-size: 20px;
  cursor: pointer;
  color: inherit;
}
.emoji-picker-trigger:focus,
.emoji-picker-trigger:active {
  border-color: var(--accent);
}
.emoji-picker-grid {
  position: absolute;
  /* OTVARA SE NAGORE (workflow.md #166, korisnikov zahtev). Ranije je stajalo
     `top: calc(100% + 6px)`, dakle ispod dugmeta — a dugme za ikonicu se
     nalazi u formi pri dnu modala, pa je spisak izlazio van vidljivog dela i
     morao je da se skroluje da bi se uopšte video. */
  bottom: calc(100% + 6px);
  left: 0;
  z-index: 30;
  width: 236px;
  max-height: 220px;
  overflow-y: auto;
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 4px;
  padding: 10px;
  /* NEPROZIRNA podloga umesto `--surface-2` + `backdrop-filter` (#166).
     Zamućenje pozadine je i ovde tražilo uzorkovanje svega ispod, u trenutku
     kad se element pojavljuje — isti uzrok bljeska kao kod `.card` (#165).
     Pošto je spisak ikonica sitan i mora da se ČITA, neprozirna podloga mu i
     inače više odgovara nego providna. */
  background: #1a1d2b;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-2);
}
.emoji-picker-grid.hidden {
  display: none;
}
.emoji-choice-btn {
  font-size: 18px;
  padding: 6px 0;
  border-radius: 8px;
  border: none;
  background: transparent;
  cursor: pointer;
}
.emoji-choice-btn:hover,
.emoji-choice-btn:active {
  background: rgba(255, 255, 255, 0.1);
}

/* ============================================================
   DASHBOARD (izvučeno iz dashboard.js — ranije inline stilovi)
   ============================================================ */
.h-48 {
  height: 48px;
}
.pt-8 {
  padding-top: 8px;
}
.price-input-wrap.grow {
  width: auto;
  flex: 1 1 auto;
}
#emptyDashNotice {
  padding: 28px 20px;
}
#budgetProgressFill {
  width: 0%;
}

/* ============================================================
   AUTH / LOGIN (izvučeno iz auth.js — ranije inline stilovi)
   ============================================================ */
.brand-mark img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: inherit;
}
.brand-mark-lg {
  width: 100px;
  height: 100px;
  border-radius: 10px;
  margin: 0 auto 18px;
}
@keyframes loginFadeUp {
  from {
    opacity: 0;
    transform: translateY(18px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}
.login-hero .brand-mark-lg {
  animation: loginFadeUp 0.6s var(--ease) both;
}
/* "Čekam odobrenje..." ekran (workflow.md #98) — ista pozicija/veličina kao
   .brand-mark-lg iznad, samo krug + ikonica umesto loga, sa blagim
   pulsiranjem da se oseti da se nešto "čeka" (ne samo statična ikonica). */
.waiting-icon-wrap {
  width: 84px;
  height: 84px;
  margin: 0 auto 18px;
  border-radius: 50%;
  background: rgba(124, 156, 255, 0.12);
  display: flex;
  align-items: center;
  justify-content: center;
  animation:
    loginFadeUp 0.6s var(--ease) both,
    waitingPulse 2.2s ease-in-out infinite;
}
.waiting-icon {
  width: 36px;
  height: 36px;
  color: var(--accent);
}
@keyframes waitingPulse {
  0%,
  100% {
    transform: scale(1);
    opacity: 1;
  }
  50% {
    transform: scale(1.08);
    opacity: 0.8;
  }
}
@media (prefers-reduced-motion: reduce) {
  .waiting-icon-wrap {
    animation: loginFadeUp 0.6s var(--ease) both;
  }
}
.login-hero .login-title {
  animation: loginFadeUp 0.6s var(--ease) 0.1s both;
}
.login-hero .login-subtitle {
  animation: loginFadeUp 0.6s var(--ease) 0.2s both;
}
.login-highlights-card {
  animation: loginFadeUp 0.6s var(--ease) 0.3s both;
  margin: 18px 22px 4px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: 4px 16px;
}
.login-actions {
  padding: 8px 22px 20px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  animation: loginFadeUp 0.6s var(--ease) 0.4s both;
}
/* ============================================================
   WELCOME EKRAN (auth.js, workflow.md #151)
   Predstavljanje aplikacije PRE prijave — prikazuje se samo prvi put na
   uređaju. Koristi iste tokene kao ostatak aplikacije (nema svoje palete ni
   fontova); desktop raspored je u main-desktop.css.
   ============================================================ */
.welcome-screen {
  padding-bottom: 24px;
  animation: loginFadeUp 0.5s var(--ease) both;
}
.welcome-hero {
  padding: 24px 22px 6px;
  text-align: center;
}
.welcome-title {
  font-family: "Space Grotesk", sans-serif;
  font-size: 30px;
  margin-bottom: 10px;
}
.welcome-tagline {
  color: var(--text-dim);
  font-size: 16px;
  line-height: 1.6;
  max-width: 44ch;
  margin: 0 auto;
  text-wrap: balance;
}
/* BAG (workflow.md #153): ovde je ceo tekst stajao DIREKTNO u flex
   kontejneru, sa `<strong>` usred rečenice. Flex od toga pravi TRI zasebna
   elementa („Trenutno je" / `<strong>` / ostatak), a `flex-wrap` je
   podrazumevano `nowrap` — pa su se nizali u jedan red i isticali iz kartice.
   Na telefonu je izgledalo kao da je tekst odsečen.
   Zato tekst sad ima svoj `<span>`: kontejner ima tačno dva deteta (ikonica +
   tekst), a prelom se dešava unutar teksta, gde i treba. */
.welcome-promo {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 14px 16px;
  border-radius: var(--r-sm);
  background: rgba(62, 213, 152, 0.1);
  border: 1px solid rgba(62, 213, 152, 0.25);
  color: var(--good);
  font-size: 14px;
  line-height: 1.55;
  text-align: left;
}
.welcome-promo-icon {
  display: flex;
  flex: 0 0 auto;
  /* Poravnato sa PRVIM redom teksta, ne sa sredinom bloka — kad se tekst
     prelomi u tri reda, centrirana ikonica odluta na sredinu kartice. */
  padding-top: 2px;
}
.welcome-promo-icon svg {
  width: 17px;
  height: 17px;
}
.welcome-promo-text {
  flex: 1 1 auto;
  min-width: 0;
}
.welcome-cta-row {
  display: flex;
  gap: 10px;
  justify-content: center;
  margin-top: 16px;
}
.welcome-section {
  padding: 28px 22px 0;
}
.welcome-section-title {
  font-family: "Space Grotesk", sans-serif;
  font-size: 13.5px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text);
  margin-bottom: 14px;
}
.welcome-features {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.welcome-feature {
  display: flex;
  gap: 14px;
  align-items: flex-start;
  padding: 16px 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
}
/* Bez obojene pozadine kruga — samo prsten, isto pravilo kao svaki drugi
   krug sa ikonicom u aplikaciji. */
.welcome-feature-icon {
  width: 42px;
  height: 42px;
  border-radius: 50%;
  border: 1.5px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  color: var(--accent);
}
.welcome-feature-icon svg {
  width: 22px;
  height: 22px;
}
.welcome-feature-body h3 {
  font-size: 15.5px;
  font-weight: 700;
  margin: 1px 0 4px;
}
.welcome-feature-body p {
  font-size: 14px;
  line-height: 1.55;
  color: var(--text-dim);
  margin: 0;
}
/* Numeracija je ovde ISTINITA — koraci se stvarno dešavaju tim redom.
   (Zato brojevi, a ne kod ostalih sekcija.) */
.welcome-steps {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.welcome-steps li {
  display: flex;
  gap: 13px;
  align-items: flex-start;
}
.welcome-step-num {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  border: 1.5px solid var(--accent);
  color: var(--accent);
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  font-family: "Space Grotesk", sans-serif;
  font-size: 14.5px;
  font-weight: 700;
}
.welcome-steps h3 {
  font-size: 15.5px;
  font-weight: 700;
  margin: 3px 0 3px;
}
.welcome-steps p {
  font-size: 14px;
  line-height: 1.55;
  color: var(--text-dim);
  margin: 0;
}
/* „Kako zaista izgleda" — prave kartice aplikacije sa izmišljenim brojevima.
   Same kartice nose SVOJE postojeće klase (.bill-row, .tx-card, .legend-row);
   ovde je samo raspored i to da su nepomične (nijedna nije klikabilna). */
.welcome-section-lead {
  margin: -6px 0 16px;
  font-size: 14px;
  line-height: 1.5;
  color: var(--text-dim);
}
.welcome-shots {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.welcome-shot {
  margin: 0;
  pointer-events: none; /* pregled, ne kontrola — ništa se ne klikće */
}
/* Transakcija ovde NIJE uvijena u `.card` (vidi auth.js) — `.tx-card` već nosi
   pozadinu i ivicu. Skida se samo donja margina koju ima u listi Istorije. */
.welcome-shot-tx {
  margin-bottom: 0;
}
.welcome-shot-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 12px;
}
.welcome-shot-label {
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-dimmer);
}
.welcome-shot-total {
  font-family: "Space Grotesk", sans-serif;
  font-size: 21px;
  font-weight: 700;
}
.welcome-donut-wrap {
  display: flex;
  align-items: center;
  gap: 16px;
}
.welcome-donut {
  width: 120px;
  height: 120px;
  flex: 0 0 auto;
  /* -90deg: prvi segment kreće od 12 sati, kao na grafikonu u aplikaciji. */
  transform: rotate(-90deg);
}
.welcome-donut-arc {
  fill: none;
  stroke-width: 12;
}
.welcome-donut-legend {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 7px;
}
/* Transakcija je u aplikaciji dugme koje se otvara/zatvara; ovde je zauvek
   otvorena, pa mora da izgleda kao red teksta, ne kao dugme. */
.welcome-shot-tx .tx-summary {
  cursor: default;
}
.welcome-more {
  margin: 16px 0 0;
  text-align: center;
  font-size: 14.5px;
  font-weight: 700;
  color: var(--text-dim);
}

/* „Šta još možeš" — pitanje/odgovor, jer je svaka stavka odgovor na stvarnu
   zamerku („nerviraju me obaveštenja", „ne volim generičku početnu"). */
.welcome-qa {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.welcome-qa-row {
  padding: 16px 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  border-left: 3px solid var(--accent);
}
.welcome-qa-row h3 {
  font-size: 15px;
  font-weight: 700;
  margin: 0 0 5px;
}
.welcome-qa-row p {
  font-size: 14px;
  line-height: 1.55;
  color: var(--text-dim);
  margin: 0;
}

.welcome-security {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.welcome-security li {
  position: relative;
  padding-left: 26px;
  font-size: 14px;
  line-height: 1.6;
  color: var(--text-dim);
}
.welcome-security li::before {
  content: "🔒";
  position: absolute;
  left: 0;
  top: 1px;
  font-size: 13px;
}
.welcome-security strong {
  color: var(--text);
  font-weight: 700;
}
.welcome-fineprint {
  margin-top: 14px;
  font-size: 13px;
  color: var(--text-dimmer);
}
.welcome-fineprint a {
  color: var(--accent);
}
.welcome-bottom {
  padding: 28px 22px 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
/* „Sve je besplatno" stoji ISPOD sadržaja, tik iznad dugmadi (korisnikova
   skica, assets/putanja.png) — a ne na vrhu ekrana: prvo šta aplikacija radi,
   pa tek onda koliko košta. */
.welcome-bottom .welcome-promo {
  margin: 0 0 6px;
}
/* Dva dugmeta za instalaciju (Android / iPhone), jedno pored drugog.
   `1fr 1fr` umesto flex-a: nazivi su različite dužine („Instaliraj za
   Android" je duže od „…za iPhone"), a dva dugmeta različite širine u istom
   redu izgledaju kao greška. Ispod 380px prelaze jedno ispod drugog — u dve
   kolone bi tekst pao na tri reda po dugmetu. */
.welcome-install-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
@media (max-width: 380px) {
  .welcome-install-row {
    grid-template-columns: 1fr;
  }
}
/* Ikonice platformi su pune (`fill`), ne linijske kao ostatak seta, pa na
   istoj meri deluju teže od ostalih ikonica u dugmadima — otud 14px umesto
   16px koliko `.btn-compact svg` daje. */
.welcome-install-row .btn svg {
  width: 14px;
  height: 14px;
}
/* Kratko objašnjenje ispod svakog dugmeta za registraciju — bez njega su dve
   opcije („nov korisnik" / „pridruži se porodici") razlika koju zna samo onaj
   ko je već koristio aplikaciju. */
.register-option-hint {
  margin: -2px 0 2px;
  padding: 0 2px;
  font-size: 14px;
  line-height: 1.5;
  color: var(--text-dim);
}

.login-hero {
  padding: 20px 24px 10px;
  text-align: center;
}
.login-title {
  font-family: "Space Grotesk", sans-serif;
  font-size: 24px;
  margin-bottom: 10px;
}
.login-subtitle {
  color: var(--text-dim);
  font-size: 14px;
  line-height: 1.5;
}
.login-highlight-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 7px 0;
}
.login-highlight-row:not(:last-child) {
  border-bottom: 1px dashed var(--border-soft);
}
.login-highlight-icon {
  display: flex;
  width: 32px;
  height: 32px;
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: rgba(124, 156, 255, 0.14);
  color: var(--accent);
}
.login-highlight-icon svg {
  width: 15px;
  height: 15px;
}
.login-highlight-text {
  font-size: 12.5px;
  color: var(--text-dim);
  line-height: 1.4;
}
.login-divider {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--text-dimmer);
  font-size: 11.5px;
}
.login-divider::before,
.login-divider::after {
  content: "";
  flex: 1 1 auto;
  height: 1px;
  background: var(--border-soft);
}
.legal-links-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 8px;
  row-gap: 4px;
  margin-top: -2px;
}
.consent-row {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  cursor: pointer;
}
.consent-row .toggle-switch {
  margin-top: 2px;
}
.consent-text {
  font-size: 12.5px;
  color: var(--text-dim);
  line-height: 1.55;
}
.consent-text a {
  color: var(--accent);
  font-weight: 700;
}
.legal-link-btn {
  font-size: 11.5px;
  color: var(--text-dimmer);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.legal-link-sep {
  font-size: 11.5px;
  color: var(--text-dimmer);
}
.role-setup-intro {
  margin: 4px 0 14px 0;
}

/* ============================================================
   PORODICA (izvučeno iz porodica.js — ranije inline stilovi)
   ============================================================ */
.family-name-display {
  flex: 1 1 auto;
  min-width: 0;
  overflow-wrap: anywhere;
  font-size: 14px;
  font-weight: 700;
  color: var(--text);
}
.member-role-select-wrap {
  margin-top: 4px;
  width: 140px;
}
.member-role-select {
  font-size: 11px;
  padding: 5px 22px 5px 8px;
  height: auto;
}
.member-admin-toggle-btn {
  width: 30px;
  height: 30px;
  color: var(--toggle-color);
}

/* ============================================================
   ISTORIJA (izvučeno iz istorija.js — ranije inline stilovi)
   ============================================================ */
.cat-toggle-btn {
  width: 100%;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.chart-wrap-short {
  height: 150px;
}

/* ============================================================
   UNOS TROŠKA (izvučeno iz unos.js — ranije inline stilovi)
   ============================================================ */
.item-qty-field {
  flex: 0 0 52px;
  text-align: center;
  padding-left: 4px;
  padding-right: 4px;
}
/* Fiksna plava (--blue), NE boja aktivnog korisnika — dugmad za unos troška
   (kamera/galerija/ručno) su namerno neutralna, isto za svakog člana. */
/* Dve alternative skeniranju ("Ubaci sliku" i "Unesi ručno") — ravnopravne su,
   pa izgledaju ISTO. Ranije je samo "Unesi ručno" imalo ovaj stil, a "Ubaci
   sliku" je bilo `btn-ghost` (providno, sivi tekst), pa je delovalo kao
   sporedna/nedovršena opcija iako je jednako korisna.
   Klasa je preimenovana iz `.manual-input-btn` — koristila se na tačno jednom
   mestu, pa preimenovanje nije ništa drugo dotaklo. */
.scan-alt-btn {
  background: rgba(76, 126, 255, 0.14);
  border: 1px solid rgba(76, 126, 255, 0.35);
  color: var(--blue);
}
/* SVG ikonica unutar dugmeta mora imati eksplicitnu veličinu — `icon()` vraća
   SVG bez ograničenja (`display:block`), što je ponavljan izvor bagova u ovom
   projektu (vidi CLAUDE.md). Do sad je "Ubaci sliku" imalo ikonicu u istom
   redu sa tekstom bez pravila; sad kad su oba dugmeta ista, pravilo je
   eksplicitno. */
.scan-alt-btn svg {
  width: 17px;
  height: 17px;
  flex: 0 0 auto;
}
.scan-secondary-row {
  display: flex;
  gap: 8px;
  width: 100%;
  margin-top: 8px;
}
.scan-secondary-row .btn {
  margin-top: 0;
}
/* ============================================================
   ŠTEDNJA (izvučeno iz stednja.js — ranije inline stilovi)
   ============================================================ */
.auto-transfer-section {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px dashed var(--border-soft);
}

/* Jednokratna ponuda da se mesečni iznos prebaci u valutu cilja (zapis stariji
   od 06.08.2026.). `display: block` je namerno — `.popup-copy-mini` je flex
   red, a ovde ispod teksta stoji dugme koje mora u svoj red, ne pored. */
.auto-transfer-fix-note {
  display: block;
  margin-top: 10px;
  padding: 10px 12px;
  border-radius: 10px;
  border: 1px solid rgba(255, 193, 90, 0.3);
  background: rgba(255, 193, 90, 0.08);
  color: var(--text-dim);
  line-height: 1.5;
}

/* ============================================================
   PREGLED EKRAN (izvučeno iz pregled.js — ranije inline stilovi)
   ============================================================ */
.due-soon-card {
  margin-bottom: 14px;
  padding: 12px 14px;
  display: flex;
  align-items: center;
  gap: 10px;
  border-color: rgba(255, 193, 90, 0.3);
  background: rgba(255, 193, 90, 0.08);
}
.due-soon-icon {
  display: flex;
  /* +20% (18 -> 22) — ovde je sam kontejner ikonica (nema zaseban svg blok). */
  width: 22px;
  height: 22px;
  flex: 0 0 auto;
  color: var(--warn);
}
.due-soon-text {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--warn);
}
/* Isto narandžasto "dospeva za X dana" ali INLINE pored imena (Početna
   kartice računa/kredita) — vidi .due-soon-text iznad za dedikovan ekran. */
.due-soon-inline {
  font-size: 11.5px;
  font-weight: 700;
  color: var(--warn);
}
.pregled-buttons-wrap {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.pregled-pill-btn {
  height: 56px;
  font-size: 15px;
  justify-content: flex-start;
  padding-left: 18px;
  gap: 12px;
}
.pregled-pill-icon {
  display: flex;
  width: 34px;
  height: 34px;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  flex: 0 0 auto;
}
.pregled-pill-icon.gold {
  background: rgba(255, 193, 90, 0.18);
  color: #ffc15a;
}
.pregled-pill-icon.accent {
  background: rgba(124, 156, 255, 0.18);
  color: var(--accent);
}
.pregled-pill-icon.green {
  background: rgba(62, 213, 152, 0.18);
  color: var(--good);
}
.pregled-pill-icon.pink {
  background: rgba(255, 92, 122, 0.18);
  color: #ff5c7a;
}
/* Porodični štednja izazov — svesno PLAVA, da se na prvi pogled razlikuje od
   Štednje (koja je roze/crvena svuda: .savings-icon, dugme na hub ekranu).
   Jača plava od `.accent` (#7c9cff) baš da razlika bude očigledna. */
.pregled-pill-icon.blue {
  background: rgba(76, 126, 255, 0.18);
  color: var(--blue);
}
/* Brojač aktivnih garancija — SKROZ DESNO na svom dugmetu (korisnikov
   zahtev). `margin-left: auto` umesto `justify-content: space-between` na
   roditelju: dugme je `justify-content: flex-start` zbog ikonice + teksta,
   pa bi promena poravnanja razvukla i njih dvoje. */
.pregled-pill-count {
  margin-left: auto;
  padding: 4px 10px;
  border-radius: var(--r-pill);
  background: rgba(255, 193, 90, 0.16);
  color: #ffc15a;
  font-size: 11.5px;
  font-weight: 700;
  white-space: nowrap;
  flex: 0 0 auto;
}

/* ============================================================
   PRAĆENJE GARANCIJA (garancije.js)
   Red garancije je `.bill-row` (isti skelet kao računi/krediti/obaveze) —
   ovde su samo dodaci kojih drugi entiteti nemaju: meta red sa prodavnicom
   /datumom/rokom, napomena, biranje slika i pun prikaz slike u modalu.
   ============================================================ */
/* (Prelamanje reda dugmadi je premešteno na sam `.bill-row-bottom` — više nije
   posebnost garancija, isti problem imali su i računi sa tri dugmeta.) */
.garancija-due-soon {
  color: var(--warn);
  font-weight: 700;
}
.garancija-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
  padding-left: var(--row-indent); /* poravnato sa .bill-info, isto kao .bill-row-bottom */
  margin: 8px 0;
  font-size: 11.5px;
  color: var(--text-dimmer);
}
.garancija-meta span {
  display: inline-flex;
  align-items: center;
  gap: 5px;
}
/* icon() je SVG bez sopstvene veličine — bez ovog pravila bi se raširio na
   celu širinu reda (ponavljan izvor bagova, vidi CLAUDE.md). */
.garancija-meta svg {
  width: 13px;
  height: 13px;
  flex: 0 0 auto;
}
/* TRAKA ROKA GARANCIJE (24.09.2026, korisnikov zahtev) — PRAZNI se kako rok
   ističe (`garancijaPreostalo()` u utils.js). Uvučena kao `.garancija-meta`,
   da stoji ispod teksta, ne ispod ikonice. Boja prati ISTI prag kao natpis
   „Ističe za N dana" i signal na ikonici „Pregled" (30 dana): zeleno dok ima
   vremena, žuto kad je vreme da se nađu račun i garantni list. */
.garancija-rok {
  padding-left: var(--row-indent);
  margin: 2px 0 10px;
}
.garancija-rok-traka {
  width: 100%;
  height: 6px;
  background: rgba(255, 255, 255, 0.06);
  border-radius: 99px;
  overflow: hidden;
}
.garancija-rok-fill {
  height: 100%;
  width: var(--pct, 0%);
  background: var(--good);
  border-radius: 99px;
  transition: width 0.4s ease;
}
.garancija-rok-uskoro .garancija-rok-fill {
  background: var(--signal-yellow);
}
.garancija-rok-tekst {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  margin-top: 5px;
  font-size: 11.5px;
  color: var(--text-dim);
}
.garancija-rok-tekst .dim {
  color: var(--text-dimmer);
}
.garancija-rok-uskoro .garancija-rok-tekst span:first-child {
  color: var(--signal-yellow);
  font-weight: 700;
}
/* Na Početnoj red nema `.garancija-meta` ispod naslova, pa traka ide odmah
   ispod njega — sa istim uvlačenjem, bez donjeg razmaka koji bi razvukao
   kompaktnu karticu. */
.dashboard-bill-row .garancija-rok {
  margin: 8px 0 2px;
}
@media (prefers-reduced-motion: reduce) {
  .garancija-rok-fill {
    transition: none;
  }
}
.garancija-note {
  padding-left: var(--row-indent);
  margin: 0 0 8px;
  font-size: 12px;
  color: var(--text-dim);
  font-style: italic;
}
.garancija-months-row {
  margin-bottom: 8px;
}
/* Naziv IDE U SVOJ RED, pa tek onda stanje/dugme (korisnikov zahtev,
   16.08.2026). Ranije je red bio vodoravan sa `flex-wrap`, pa je raspored
   zavisio od DUŽINE naziva: „🧾 Račun (slika ili PDF)" je stajao u jednom redu
   sa „✓ Novi fajl izabran" i dugmetom „Ukloni", a duži „📄 Garantni list
   (slika ili PDF)" je isto to prelamao u dva reda. Dva ista polja jedno ispod
   drugog izgledala su kao dve različite komponente. Uspravno slaganje daje
   isti raspored za oba, i ne menja se ni na 320px. */
.garancija-picker {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
  padding: 10px 0;
  border-top: 1px solid var(--border);
}
.garancija-picker-label {
  font-size: 12.5px;
  font-weight: 600;
}
.garancija-picker-state {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.garancija-picker-ok {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 11.5px;
  color: var(--good);
}
.garancija-picker-ok svg {
  width: 14px;
  height: 14px;
}
/* <label> koji sadrži skriven <input type="file"> — klik bilo gde po njemu
   otvara birač fajlova, pa izgleda i ponaša se kao dugme. */
.garancija-picker-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 12px;
  border-radius: var(--r-pill);
  border: 1px solid var(--border);
  background: var(--surface-2);
  font-size: 11.5px;
  font-weight: 600;
  cursor: pointer;
  flex: 0 0 auto;
}
.garancija-picker-btn svg {
  width: 15px;
  height: 15px;
}
/* Modal za prikaz dokumenta — JEDINI modal u projektu koji NE SME da se
   skroluje (korisnikov zahtev, 16.08.2026). Ranije je slika imala fiksnih
   `62vh`, pa je zbir naslova, podnaslova, slike i dugmeta „Preuzmi sliku"
   redovno prelazio visinu fioke: dugme se nije videlo dok se ne skroluje, a
   skrol unutar modala se na telefonu sudara sa gestom za zatvaranje.
   Zato se ovde visina ne zadaje slici nego se RAČUNA: fioka je uspravan flex
   kontejner fiksne najveće visine, sve osim slike zauzima svoju prirodnu
   visinu, a slika dobija ono što PRETEKNE (`flex: 1 1 auto` + `min-height: 0`,
   bez kog flex-dete ne sme da se skupi ispod svog sadržaja). `object-fit:
   contain` čuva odnos stranica, pa se visok račun prosto prikaže manji. */
.garancija-image-sheet {
  display: flex;
  flex-direction: column;
  /* Više prostora nego kod običnog modala (82%) — sadržaj je jedna slika i
     svaki procenat se vidi. */
  max-height: min(92%, calc(var(--real-vh, 1vh) * 94));
  overflow: hidden;
}
.garancija-image-sheet > * {
  flex: 0 0 auto;
}
#garancijaImageWrap {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
#garancijaImageWrap > .btn {
  flex: 0 0 auto;
}
.garancija-image-full {
  display: block;
  width: 100%;
  flex: 1 1 auto;
  min-height: 0;
  object-fit: contain;
  border-radius: var(--r-md);
  background: #000;
}
/* PDF se prikazuje u okviru, preko blob: URL-a (Chrome blokira `data:` u
   <iframe>-u). Visina se ne zadaje (PDF nema „prirodnu" visinu koju bi okvir
   nasledio) nego se dobija iz istog flex rasporeda kao slika. */
.garancija-pdf-frame {
  display: block;
  width: 100%;
  flex: 1 1 auto;
  min-height: 0;
  border: 0;
  border-radius: var(--r-md);
  background: #fff;
}
/* Cena na kartici — desno u gornjem redu, uz status. `.bill-amount` daje
   Space Grotesk i težinu; ovde se samo skida rastezanje (kod računa cena
   zauzima celu preostalu širinu, ovde ne sme da gura status). */
.garancija-price {
  flex: 0 0 auto;
  font-size: 13px;
  color: var(--text-dim);
  white-space: nowrap;
}
.service-log-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 0;
  border-bottom: 1px solid var(--border-soft);
  font-size: 12.5px;
}
.service-log-row:last-child {
  border-bottom: 0;
}
.service-log-date {
  flex: 0 0 auto;
  color: var(--text-dimmer);
  font-variant-numeric: tabular-nums;
}
.service-log-note {
  flex: 1 1 auto;
  min-width: 0;
}
/* (`.icon-btn.danger-icon` je uklonjen — kanta u servisnom dnevniku garancije
   koristi isti `.icon-btn.icon-btn-danger` kao i svaka druga u aplikaciji.) */

/* ============================================================
   NAJJEFTINIJI ARTIKAL / NAJJEFTINIJE PO PRODAVNICAMA (najjeftinije.js)
   ============================================================ */
.avatar svg {
  width: 22px;
  height: 22px;
}
.price-disclaimer-box {
  display: flex;
  align-items: center;
  gap: 10px;
  border: 1.5px dashed var(--warn);
  border-radius: var(--r-sm);
  padding: 12px 14px;
  margin-bottom: 14px;
}
.price-disclaimer-icon {
  display: flex;
  width: 22px;
  height: 22px;
  flex: 0 0 auto;
  color: var(--warn);
}
.price-disclaimer-text {
  font-size: 12px;
  color: var(--text-dim);
}
.mode-toggle-row {
  display: flex;
  gap: 6px;
  background: var(--surface-2);
  padding: 4px;
  border-radius: var(--r-pill);
  margin-bottom: 14px;
}
.mode-toggle-btn {
  flex: 1 1 auto;
  padding: 10px 8px;
  border-radius: var(--r-pill);
  font-size: 12.5px;
  font-weight: 700;
  color: var(--text-dim);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}
.mode-toggle-btn.active {
  background: var(--accent);
  color: #fff;
}
.mode-toggle-btn svg {
  width: 15px;
  height: 15px;
}
.tier-badge {
  margin-left: auto;
  flex: 0 0 auto;
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.3px;
  padding: 3px 8px;
  border-radius: var(--r-pill);
  text-transform: uppercase;
}
.tier-badge.pro {
  background: rgba(124, 156, 255, 0.18);
  color: var(--accent);
}
.tier-badge.premium {
  background: linear-gradient(135deg, var(--blue), var(--pink));
  color: #fff;
}
.store-name-inline {
  color: var(--warn);
  font-weight: 700;
}
.store-group-count {
  font-weight: 400;
  color: var(--text-dim);
}

/* ============================================================
   MODUL: SPRECAVA POMERANJE UI PRI RENDEROVANJU ALOKACIJE
   ============================================================ */

/* Fiksna visina za karticu alokacije da ne skače */
#allocationCard {
  transition: min-height 0.3s ease;
}

/* Stabilna visina za formu alokacije */
#allocationForm {
  min-height: 180px;
}

/* #screen-unos (samo OVAJ ekran, ne deljena .screen klasa) je flex kolona
   da #unosStage ispod .screen-head-a može da RASTE i popuni ceo preostali
   prostor ekrana — bez ovoga #unosStage nema stvarnu visinu da bi
   .scan-stage-ov justify-content:space-between imao šta da razdvoji. */
#screen-unos {
  display: flex;
  flex-direction: column;
}
#unosStage {
  flex: 1 1 auto;
  min-height: 260px;
  display: flex;
  flex-direction: column;
  /* NIKAD `justify-content: center` ovde (workflow.md #141).
     Kad je sadržaj VIŠI od kontejnera, centriranje u flex koloni deli
     prekoračenje na OBE strane — pa gornji deo liste završi IZNAD početka
     kontejnera, a skrol ne može u negativno. Kod dugačkog računa (20+
     stavki) prve stavke tako postaju potpuno nedostupne: korisnik skroluje
     skroz gore i i dalje vidi odsečen red.
     `.scan-stage` ionako ima `flex: 1 1 auto` i sam popuni celu visinu, pa
     mu ovo centriranje nikad nije ni trebalo. */
  justify-content: flex-start;
}

/* Animacija glatkog prelaza sa OCR učitavanja na formu */
.form-fade {
  animation: glatkoPojavljivanjeForme 0.3s var(--ease);
}

@keyframes glatkoPojavljivanjeForme {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}
/* Spreči pomeranje pri fokusu */
.alloc-input:focus {
  outline: none !important;
  box-shadow: 0 0 0 2px rgba(124, 156, 255, 0.3) !important;
}

/* reduced motion support */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}
/* ============================================================
   PORODIČNI IZAZOV ŠTEDNJE — kućice po danima + sažetak na dnu
   (izvučeno iz stednja-izazov.js, redizajn — ne liči na dashboard karticu,
   plava boja umesto pink/gold da se poklopi sa zahtevom za "štednja" ikonice)
   ============================================================ */
.challenge-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(52px, 1fr));
  gap: 8px;
  margin-top: 10px;
}
.challenge-cell {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  aspect-ratio: 1;
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--border-soft);
}
.challenge-cell-day {
  font-size: 9px;
  font-weight: 800;
  text-transform: uppercase;
  color: var(--text-dimmer);
}
.challenge-cell-amount {
  font-family: "Space Grotesk", sans-serif;
  font-size: 12px;
  font-weight: 700;
  color: var(--text-dim);
}
.challenge-cell.is-today {
  border-color: var(--accent);
  background: rgba(124, 156, 255, 0.12);
  box-shadow: 0 0 0 2px rgba(124, 156, 255, 0.2);
}
.challenge-cell.is-today .challenge-cell-day,
.challenge-cell.is-today .challenge-cell-amount {
  color: var(--accent);
}
/* Boja kućice prati boju ČLANA porodice koji je taj dan uneo iznos
   (stednja-izazov.js -> challengeGridHtml(), --cell-bg/--cell-border/
   --cell-color inline po ćeliji) — fallback na generičku zelenu ako član
   više ne postoji (ili u retkom slučaju da inline stil nije postavljen). */
.challenge-cell.is-filled {
  background: var(--cell-bg, rgba(62, 213, 152, 0.14));
  border-color: var(--cell-border, rgba(62, 213, 152, 0.35));
}
.challenge-cell.is-filled .challenge-cell-amount {
  color: var(--cell-color, var(--good));
}
.challenge-cell.is-skipped {
  background: rgba(255, 107, 94, 0.08);
  border-color: rgba(255, 107, 94, 0.2);
  opacity: 0.55;
}
/* Izazov je PLAV svuda (ikonica, traka napretka, kartica na Početnoj) — da se
   razlikuje od Štednje, koja je roze/crvena (.savings-icon → var(--pink)).
   Korisnikov zahtev; ranije je bio `--accent` (bledo plavo-ljubičasto), što se
   na Početnoj slabo razlikovalo od kartica ciljeva štednje. */
.challenge-summary-icon {
  color: var(--blue);
  background: rgba(76, 126, 255, 0.14);
}
.challenge-progress-fill {
  background: var(--blue);
}
/* (Zasebna traka napretka PO DANIMA je uklonjena na korisnikov zahtev —
   kartica „Sakupljeno do sad" odmah ispod već nosi isti podatak, samo po
   iznosu, pa su dve trake jedna iznad druge bile ponavljanje.) */
/* Kartica izazova na Početnoj koristi isti .savings-card skelet kao ciljevi
   štednje — ova klasa menja SAMO ono što treba da se razlikuje (procenat), da
   se ne duplira ceo blok pravila. */
.challenge-dashboard-row .savings-pct {
  color: var(--blue);
}

/* ============================================================
   KOMPAKTNIJA DUGMAD — koristi se u formama za dodavanje štednje/liste
   (Otkaži / Dodaj) i u sekciji "Isključena obaveštenja" (Uključi), gde je
   bazna .btn veličina (16px/24px padding, 15px font) delovala preglomazno
   u uskim karticama. Ne menja bazni .btn nigde drugde u aplikaciji.
   ============================================================ */
/* Dugmad u formama (Otkaži / Dodaj / Sačuvaj). Visina spuštena 44 -> 40 i
   font 13 -> 12.5 (workflow.md #110) da se poklope sa `.row-action-btn`
   (36px) — pre ovoga je "Dodaj račun" u formi bio osetno krupniji od "Plati"
   u redu odmah ispod, iako su vizuelno ista klasa radnje. 40px (a ne 36) jer
   su ova dugmad glavna radnja celog formulara, pa smeju da budu minimalno
   istaknutija — ali u istom redu veličine, ne dvostruko veća. */
.btn-compact {
  padding: 10px 16px;
  font-size: 12.5px;
  height: 40px;
}
.btn-compact svg {
  width: 15px;
  height: 15px;
  flex: 0 0 auto;
}
/* U `.form-actions` redu obe dugmadi zauzimaju jednake širine — ranije je
   "Otkaži" bio uzak a "Dodaj" (sa .btn-block) se širio preko ostatka, pa red
   nikad nije bio simetričan. */
.form-actions .btn-compact {
  flex: 1 1 0;
  min-width: 0;
}
.btn-compact svg {
  width: 16px;
  height: 16px;
}
/* Otkaži/Dodaj parovi na formama (Nova štednja, Nova šoping lista, Novi
   kredit...) sad prate ISTI translucentni "pill" izgled kao Izmeni/Obriši
   po stavci (.list-edit-btn/.tx-delete-btn, ispod) — čvrst gradient sa
   senkom je delovao "teško" za dugmad unutar uske forme-kartice. Scoped
   SAMO na .btn-compact kombinaciju — pune (btn-block, bez compact) verzije
   .btn-danger/.btn-good (npr. potvrda brisanja u showConfirmModal(), "Da,
   odustani" u izazovu štednje) namerno ostaju vizuelno "teže" — to su
   ozbiljnije, finalne potvrde brisanja, ne obična Otkaži/Dodaj par. */
.btn-danger.btn-compact {
  background: rgba(255, 107, 94, 0.18);
  border: 1px dashed rgba(255, 107, 94, 0.35);
  color: #ff6b5e;
  box-shadow: none;
  filter: none;
}
.btn-good.btn-compact {
  background: rgba(62, 213, 152, 0.18);
  border: 1px dashed rgba(62, 213, 152, 0.35);
  color: var(--good);
  box-shadow: none;
  filter: none;
}

/* Kompaktnije Izmeni/Obriši dugme po stavci šoping liste — bilo je 10px
   padding / 12.5px font na dugmadima razvučenim na pola širine kartice
   (flex: 1 1 0), što je delovalo krupno. Scoped SAMO na ovaj red da se ne
   dirne .tx-delete-btn koji se koristi svuda drugde (transakcije, računi,
   ciljevi štednje...). */
.list-actions-row .list-edit-btn,
.list-actions-row .tx-delete-btn {
  padding: 8px;
  font-size: 11.5px;
}

/* BAG: bedž sa brojem obaveštenja je pokazivao "0" iako nema obaveštenja.
   Uzrok: `.notif-badge { ... display:flex; }` i generička `.hidden {
   display:none }` utility klasa imaju ISTU specifičnost (0,1,0) — koja od
   njih "pobedi" zavisi samo od REDOSLEDA u fajlu, a `.notif-badge` je
   dodata POSLE `.hidden` (kad je rađen centar obaveštenja), pa je njen
   `display:flex` tiho pobeđivao `.hidden`-ov `display:none`, bez obzira što
   je JS ispravno kačio klasu "hidden". Ispravka: kombinovan selektor ima
   veću specifičnost (0,2,0) i uvek pobeđuje, bez diranja generičke
   `.hidden` klase (koja i dalje radi svuda drugde u aplikaciji). */
.notif-badge.hidden {
  display: none;
}

/* Ikonica "Štednja" u donjoj navigaciji — ISTI .has-pending mehanizam kao
   "Pregled" (žuto) i "Šoping lista" (plavo), samo primenjen na ovo dugme.
   Uključuje se (stednja.js -> updateStednjaNavPulse()) dok postoji bar
   jedan nerešen cilj štednje ili je porodični izazov aktivan.
   Boja ide kroz `--pulse-color` — vidi objašnjenje uz `.has-pending svg` u
   sekciji sa navigacijom; direktan `filter` bi ionako bio pregažen animacijom. */
.nav-btn[data-nav="stednja"].has-pending svg {
  --pulse-color: var(--accent);
}

/* Manja, "lepša" cifra za predloženi iznos u kartici "Danas" porodičnog
   izazova štednje — namerno MANJA od `.total-value` (koja je mišljena za
   krupne dashboard brojeve), da polje ne deluje preglomazno. */
.challenge-today-amount {
  font-family: "Space Grotesk", sans-serif;
  font-weight: 700;
  font-size: 20px;
  color: var(--text);
}
/* Plava ivica — isti razlog kao .savings-card.is-active: ovaj ekran se
   renderuje SAMO dok je izazov aktivan, što je i jedan od dva uslova koji
   pale plavu ikonicu "Štednja" u navigaciji (updateStednjaNavPulse()). */
.challenge-summary-card {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent);
}
.btn-dashed {
  background: transparent;
  border: 1.5px dashed var(--accent);
  color: var(--text);
}

/* Prezime porodice ispod "Kućni bilans" — ista boja i veličina kao naslov
   (h1#brandTitle), ne dim/mali podnaslov kao generička `.brand-text p`.
   ID selektor (veća specifičnost) pobeđuje `.brand-text p` bez obzira na
   redosled u fajlu — overflow/ellipsis zaštita za duga prezimena (vidi
   workflow.md sekciju 23) ostaje nasleđena iz `.brand-text p`, dira se
   SAMO font/boja. */
#topbarSubtitle {
  font-size: 16px;
  font-weight: 800;
  letter-spacing: -0.3px;
  color: var(--text);
}

/* ============================================================
   30. OZNAKA AI SADRŽAJA (AI Act, čl. 50 — vidi modules/ai.js)
   ============================================================ */

/* Napomena ide UZ tekst i mora da se pročita zajedno sa njim, pa ima istu
   levu ivicu kao sam tekst i ne stoji u zasebnoj kartici. Nije prigušena do
   nečitljivosti (`--text-dim`, ne `--text-dimmer`): oznaka koja se ne vidi
   ne ispunjava uslov „jasna i razgovetna". */
.ai-content {
  display: block;
}
.ai-disclaimer {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 10px;
  padding-top: 8px;
  border-top: 1px dashed var(--border-soft);
  font-size: 11.5px;
  line-height: 1.45;
  color: var(--text-dim);
}
.ai-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border-radius: var(--r-pill);
  border: 1px solid var(--accent);
  color: var(--accent);
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: 0.2px;
  white-space: nowrap;
}

/* ============================================================
   30a. STATISTIKA (20.08.2026, korisnikov zahtev — modules/statistika.js)
   ============================================================

   Stubičasti grafikon je CSS, ne Chart.js. Razlog je u modulu; ovde je bitna
   posledica za stilove: iznos iznad stuba i skraćenica meseca ispod njega su
   OBIČAN TEKST, pa nasleđuju veličinu fonta i uvećanje stranice. Kad bi bili
   nacrtani u `<canvas>`-u, slabovid korisnik ih ne bi mogao uvećati, a čitač
   ekrana ih ne bi pročitao uopšte. */

.bar-chart {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 8px;
  height: 190px;
  margin-top: 4px;
}
.bar-col {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  /* `flex: 1 1 0` sa `min-width: 0` — bez oba, kolona sa širim iznosom
     („142.300") postane šira od ostalih i stubovi se razmaknu neravnomerno. */
  flex: 1 1 0;
  min-width: 0;
  height: 100%;
}
.bar-val {
  font-family: "Space Grotesk", sans-serif;
  font-weight: 700;
  font-size: 11px;
  color: var(--text-dim);
  white-space: nowrap;
}
.bar-track {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  width: 100%;
  flex: 1 1 auto;
}
/* 36px, ne puna širina kolone: prati `barThickness: 26` iz Chart.js
   podešavanja u `istorija.js` (tamo je horizontalno, pa je to visina stuba).
   Stub razvučen preko cele kolone se čita kao blok, ne kao stub. */
.bar-fill {
  width: 36px;
  max-width: 100%;
  height: var(--h, 0%);
  border-radius: 10px 10px 4px 4px;
  background: var(--blue);
}
/* Tekući mesec nosi gradijent `--blue → --pink` (isti kao `.btn-primary` i
   `.nav-fab`) — jedina razlika koja bez ijedne reči kaže „ovaj još traje".
   Zato i piše „N od M dana" u redu ispod grafikona. */
.bar-col.is-current .bar-fill {
  background: linear-gradient(180deg, var(--blue), var(--pink));
  box-shadow: 0 6px 18px rgba(245, 86, 140, 0.3);
}
.bar-col.is-current .bar-val {
  color: var(--text);
}
.bar-lbl {
  font-size: 11px;
  font-weight: 700;
  color: var(--text-dimmer);
  text-transform: uppercase;
  letter-spacing: 0.3px;
}
.bar-col.is-current .bar-lbl {
  color: var(--text-dim);
}

.stat-figures {
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid var(--border-soft);
}
.stat-figure-end {
  align-items: flex-end;
  text-align: right;
}

.stat-card-sub {
  font-size: 12px;
  line-height: 1.45;
  color: var(--text-dimmer);
  margin-top: 4px;
}
.stat-rows {
  margin-top: 6px;
}
.stat-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 11px 0;
}
.stat-row:not(:last-child) {
  border-bottom: 1px dashed var(--border-soft);
}
.stat-name {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--text-dim);
  overflow-wrap: anywhere;
}
.stat-val {
  font-family: "Space Grotesk", sans-serif;
  font-weight: 700;
  font-size: 13.5px;
  white-space: nowrap;
  flex: 0 0 auto;
}
/* Promena u odnosu na prosek. Boja NIJE jedini nosilac poruke — znak (+/−)
   stoji ispisan, pa red ima isto značenje i za onoga ko boje ne razlikuje
   (isto pravilo kao `.bill-row` status i traka budžeta).
   `min-width` drži pilule poravnate u kolonu bez obzira da li je unutra
   „+7%" ili „−31%". */
.stat-delta {
  font-family: "Space Grotesk", sans-serif;
  font-weight: 700;
  font-size: 11.5px;
  padding: 3px 8px;
  border-radius: var(--r-pill);
  white-space: nowrap;
  flex: 0 0 auto;
  min-width: 58px;
  text-align: center;
}
.stat-delta.up {
  background: rgba(255, 107, 94, 0.14);
  color: #ff8a80;
}
.stat-delta.down {
  background: rgba(62, 213, 152, 0.14);
  color: var(--good);
}
/* „novo" — kategorija koja se ranijih meseci nije pojavljivala. Neutralna
   namerno: nije ni ušteda ni prekoračenje, nego odsustvo poređenja. */
.stat-delta.neutral {
  background: var(--surface-2);
  color: var(--text-dimmer);
}


/* ============================================================
   31. KALKULATOR STRUJE (04.09.2026, redizajn istog dana)
   ============================================================

   Ekran preuzima gotove komponente gde god može — `.card`, `.field`,
   `.form-row-2`, `.bill-row` za sačuvane obračune, `.tx-details` za
   kolapsibilne sekcije. Ovde je samo ono što drugde ne postoji: veliki iznos
   računa, trake po zonama i tabela stavki.

   REDIZAJN (korisnikov zahtev): prvi raspored je bio spisak od pet jednakih
   kartica u kom se nije videlo šta je odgovor a šta pitanje — iznos je stajao
   na sredini, a dvadeset polja za cene pre njega. Sada rezultat ide NA VRH i
   nosi poređenje sa prethodnim mesecom, a unos je sveden na tri stvari (staro
   stanje samo prvi put, novo stanje, obračunska snaga). Sve fiksno je sklopljeno
   pod „Cene i naknade" — vidljivo, ali ne na putu.

   Trake su CSS, ne `<canvas>` — isti razlog kao grafikon u Statistici:
   kilovati i iznosi ostaju tekst, pa ih čita čitač ekrana i uvećava zum.
   ============================================================ */

/* Naslov ekrana nosi munju. `icon()` je `display: block` bez zadate mere, pa
   bi bez ovoga pala na podrazumevanu veličinu pregledača i prelomila red —
   isto pravilo kao `.btn svg` (sekcija 8), samo za jedno mesto koje nije
   dugme. */
#screen-struja .screen-head h2 {
  display: flex;
  align-items: center;
  gap: 9px;
}
#screen-struja .screen-head h2 svg {
  width: 22px;
  height: 22px;
  flex-shrink: 0;
  color: var(--signal-yellow);
}

/* ---- PREUZETO STARO STANJE ----
   Kad istorija postoji, staro stanje se ne unosi nego se preuzima. Prikazuje
   se kao gotov podatak sa vidljivim poreklom, ne kao polje — polje koje se ne
   dira samo poziva da se u njega nešto ukuca. */

.struja-preuzeto {
  padding: 12px;
  border-radius: var(--r-sm);
  background: var(--surface);
  border: 1px solid var(--border-soft);
}
.struja-preuzeto-glava {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  font-size: 11.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-dimmer);
}
.struja-preuzeto-brojevi {
  display: flex;
  gap: 18px;
  margin: 8px 0 6px;
}
.struja-preuzeto-brojevi span {
  font-size: 18px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.struja-preuzeto-brojevi i {
  margin-right: 6px;
  font-size: 11px;
  font-style: normal;
  font-weight: 700;
  letter-spacing: 0.06em;
  color: var(--text-dimmer);
}

/* Tekstualno dugme za sporedne radnje („Izmeni", „Vrati izračunatu"). Nije
   `.btn` jer stoji unutar rečenice, a pravo dugme bi je prelomilo. */
.btn-link {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-weight: 600;
  color: var(--accent);
  text-decoration: underline;
  cursor: pointer;
}

/* ---- ŽIVA POTROŠNJA ---- */

.struja-potrosnja {
  margin-top: 12px;
  padding: 10px 12px;
  border-radius: var(--r-sm);
  background: var(--surface);
  border: 1px solid var(--border-soft);
}
.struja-potrosnja-red {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 4px 0;
  font-size: 12.5px;
  color: var(--text-dim);
}
.struja-potrosnja-red b {
  font-variant-numeric: tabular-nums;
  color: var(--text);
}
.struja-potrosnja-zbir {
  margin-top: 4px;
  padding-top: 8px;
  border-top: 1px solid var(--border-soft);
  font-weight: 600;
  color: var(--text);
}
.struja-potrosnja-zbir b {
  color: var(--accent);
  font-size: 15px;
}

/* ---- OBRAČUNSKA SNAGA ---- */

.struja-snaga {
  padding-top: 14px;
  border-top: 1px solid var(--border-soft);
}

/* ---- POPUST: izbor stope ---- */

.struja-stope {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.struja-stopa {
  padding: 7px 11px;
  border-radius: var(--r-pill);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-dim);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.18s var(--ease);
}
/* Izabrana stopa se boji isto kao `.chip.active` (sekcija 8) — ista vrsta
   izbora, pa mora da izgleda isto; ovo nije `.chip` samo zato što se prelama
   u više redova umesto da se skroluje vodoravno. */
.struja-stopa.is-active {
  border-color: var(--text);
  background: var(--text);
  color: #12141f;
}

/* ---- GRANICE ZONA ---- */

.struja-granice {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 10px;
}
.struja-granica {
  padding: 5px 10px;
  border-radius: var(--r-pill);
  background: var(--surface-2);
  font-size: 11.5px;
  font-weight: 600;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}
/* Boje granica prate boje traka ispod — ista zona, isti signal. */
.struja-granica-zelena {
  color: var(--good);
}
.struja-granica-plava {
  color: var(--blue);
}
.struja-granica-crvena {
  color: var(--bad);
}

/* Sažetak u zaglavlju kolapsibilne sekcije: naslov levo, trenutna vrednost
   ispod njega. Bez ovoga bi „Obračunski period" i „Cene i naknade" bili dva
   zatvorena reda koji ne govore šta je unutra, pa bi ih trebalo otvarati da
   bi se videlo da su već popunjeni. */
.struja-period-sazetak {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
  text-align: left;
}
.struja-period-vr {
  font-size: 11.5px;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}

/* ---- REZULTAT ---- */

.struja-total-label {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-dimmer);
}
.struja-total-label svg {
  width: 15px;
  height: 15px;
  color: var(--signal-yellow);
}
.struja-total {
  margin-top: 4px;
  font-size: 30px;
  font-weight: 800;
  line-height: 1.15;
  /* Cifre iste širine — iznos se menja dok korisnik kuca, a bez ovoga ceo
     broj poskakuje levo-desno na svaki otkucan znak. */
  font-variant-numeric: tabular-nums;
}
.struja-total-meta {
  margin-top: 6px;
  font-size: 12.5px;
  color: var(--text-dim);
}

/* ---- POREĐENJE SA PRETHODNIM OBRAČUNOM ----
   Sam iznos ne govori ništa dok se ne uporedi. Boja je namerno obrnuta od
   uobičajene: veći račun je crven i kad je porast mali, jer je to jedina
   stvar zbog koje bi neko ovaj ekran otvorio dvaput. */

.struja-poredjenje {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 10px;
  padding: 8px 11px;
  border-radius: var(--r-pill);
  background: var(--surface-2);
  font-size: 12px;
  line-height: 1.4;
  color: var(--text-dim);
}
.struja-poredjenje svg {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
}
.struja-poredjenje b {
  color: inherit;
}
.struja-poredjenje.je-vise {
  color: var(--bad);
}
.struja-poredjenje.je-manje {
  color: var(--good);
}
.struja-poredjenje.je-isto svg {
  display: none;
}

/* ---- UPOZORENJA O UNOSU ----
   Ekran uvek prikaže neki iznos, i to je opasno: izračunat račun za struju
   izgleda isto bez obzira na to da li su ulazi celi. Ovo je jedino mesto koje
   kaže da broj iznad ne treba shvatiti ozbiljno. */

.struja-upozorenja {
  margin-top: 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.struja-upozorenje {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  padding: 10px 12px;
  border-radius: var(--r-sm);
  background: var(--surface);
  border: 1px solid var(--signal-yellow);
  font-size: 11.5px;
  line-height: 1.45;
  color: var(--text-dim);
}
.struja-upozorenje svg {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
  margin-top: 1px;
  color: var(--signal-yellow);
}

/* ---- ZONE ---- */

.struja-zona + .struja-zona {
  margin-top: 12px;
}
.struja-zona-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 6px;
}
.struja-zona-naziv {
  font-size: 13.5px;
  font-weight: 600;
}
.struja-zona-iznos {
  font-size: 13.5px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.struja-zona-traka {
  height: 8px;
  border-radius: var(--r-pill);
  background: var(--surface-2);
  overflow: hidden;
}
.struja-zona-fill {
  height: 100%;
  width: var(--pct, 0%);
  border-radius: var(--r-pill);
  background: var(--zona-boja, var(--accent));
  transition: width 0.35s var(--ease);
}
.struja-zona-meta {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-top: 6px;
  font-size: 11.5px;
  color: var(--text-dim);
}
/* Boje zona su iste tri koje EPS štampa na računu — zelena/plava/crvena nisu
   ukras nego naziv zone, pa se ne smeju menjati u nešto „lepše". */
.struja-zona-zelena {
  --zona-boja: var(--good);
}
.struja-zona-plava {
  --zona-boja: var(--blue);
}
.struja-zona-crvena {
  --zona-boja: var(--bad);
}
/* Zona kroz koju potrošnja nije prešla se utišava, ali se NE sklanja: tri
   zone su skala, a skala kojoj fali krajnji član ne govori gde si na njoj. */
.struja-zona.is-prazna {
  opacity: 0.45;
}

/* ---- RAZRADA STAVKI ---- */

.struja-razrada {
  padding-top: 4px;
}
.struja-stavka {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 7px 0;
  border-bottom: 1px dashed var(--border-soft);
  font-size: 12.5px;
}
.struja-stavka:last-child {
  border-bottom: 0;
}
/* Redni broj stavke sa računa. Fiksna širina — cela svrha razrade je da se
   red poredi sa papirom, a nazivi se ne poravnaju ako broj menja širinu. */
.struja-stavka-broj {
  flex: 0 0 18px;
  font-size: 11px;
  font-weight: 700;
  color: var(--text-dimmer);
  font-variant-numeric: tabular-nums;
}
.struja-stavka-naziv {
  flex: 1;
  color: var(--text-dim);
  /* Bez ovoga dug naziv stavke razvuče red i gurne iznos iz kartice. */
  min-width: 0;
}
.struja-stavka-iznos {
  flex-shrink: 0;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
/* Zbirne stavke sa računa (zaduženje, osnovica) — one po kojima se traži
   greška kad se iznos ne poklopi sa štampanim. */
.struja-stavka-jaka {
  font-weight: 700;
}
.struja-stavka-jaka .struja-stavka-naziv {
  color: var(--text);
}

/* ---- GRAFIKON POTROŠNJE PO MESECIMA ----
   CSS, ne Chart.js — isti razlog kao u Statistici: kilovati ostaju tekst, pa
   ih čita čitač ekrana i uvećava zum. Stubovi rastu naviše, pa se traka
   poravnava na dno reda (`align-items: flex-end` na kontejneru bi poravnalo
   cele stubove, a broj iznad mora da stoji tik uz vrh trake). */

.struja-graf {
  display: flex;
  align-items: flex-end;
  gap: 6px;
  margin-bottom: 14px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--border-soft);
  /* Više od nekoliko meseci ne staje na telefon — skrol unutar kartice, nikad
     vodoravni skrol cele stranice. */
  overflow-x: auto;
}
.struja-graf-stub {
  display: flex;
  flex: 1 0 42px;
  flex-direction: column;
  align-items: center;
  gap: 5px;
}
.struja-graf-vr {
  font-size: 10.5px;
  font-weight: 700;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}
.struja-graf-traka {
  display: flex;
  align-items: flex-end;
  width: 100%;
  height: 68px;
  border-radius: var(--r-sm);
  background: var(--surface-2);
  overflow: hidden;
}
.struja-graf-fill {
  width: 100%;
  height: var(--pct, 0%);
  border-radius: var(--r-sm);
  background: var(--accent);
  transition: height 0.35s var(--ease);
}
.struja-graf-mesec {
  font-size: 10px;
  color: var(--text-dimmer);
  white-space: nowrap;
}

/* ---- POPUST NA SLEDEĆEM RAČUNU ---- */

.struja-popust {
  padding: 12px;
  border-radius: var(--r-sm);
  background: var(--surface);
  border: 1px solid var(--border-soft);
}
.struja-popust-naslov {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  font-weight: 600;
}
.struja-popust-naslov svg {
  width: 16px;
  height: 16px;
  color: var(--good);
}
.struja-popust-red {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 5px 0;
  font-size: 12.5px;
  color: var(--text-dim);
}
.struja-popust-red span:last-child {
  font-weight: 600;
  color: var(--good);
  font-variant-numeric: tabular-nums;
}

/* ---- CENE I NAKNADE ---- */

.struja-cene-grupa {
  margin: 14px 0 8px;
  font-size: 11.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-dimmer);
}
.struja-cene-grupa:first-child {
  margin-top: 8px;
}

/* ---- PROSEK ---- */

.struja-prosek-red {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 7px 0;
  border-bottom: 1px dashed var(--border-soft);
  font-size: 12.5px;
}
.struja-prosek-red:last-child {
  border-bottom: 0;
}
.struja-prosek-naziv {
  color: var(--text-dim);
}
.struja-prosek-vr {
  flex-shrink: 0;
  font-variant-numeric: tabular-nums;
}
/* `.dim` je ovde lokalna: globalne klase za utišan tekst nema, a raspon
   „od X do Y" i opis zone moraju da budu tiši od broja pored kog stoje. */
.struja-prosek-vr .dim,
.struja-zona-meta .dim {
  color: var(--text-dimmer);
}

/* ============================================================
   32. MALI TELEFONI (16.08.2026, korisnikov zahtev)
   ============================================================

   Aplikacija je crtana na ~425px i tamo je bila tačna. Ispod toga se gužvala:
   na 375px su se nazivi lomili u tri reda i dugmad se sudarala, a na 320px je
   sadržaj počinjao da izlazi iz kartica. Uzrok NIJE bio jedan element nego to
   što su skoro sve mere u fajlu upisane kao fiksan piksel — ekran se smanji, a
   razmaci, ikonice i brojevi ostanu isti.

   Zato ova sekcija radi DVE stvari, i to je ceo pristup:

     1. Menja `--pad-*` / `--row-*` promenljive (sekcija 1). Time se odjednom
        smanje razmaci na SVAKOM ekranu, bez nabrajanja komponenti — i, što je
        važnije, spregnute mere se pomere ZAJEDNO (bleed `.chip-row`-a prati
        padding kartice, uvlačenje donjeg sprata prati veličinu ikonice).
     2. Popravlja pojedinačna mesta gde fiksna mera nije razmak nego SADRŽAJ
        (veliki iznos na Početnoj, kolona cene u listi, mreža kućica izazova,
        spisak ikonica kategorija) — tu se mora navesti šta se menja.

   TRI PRAGA, namerno vezana za stvarne uređaje, ne za okrugle brojeve:

     ≤ 420px  iPhone 12/13/14 (390), Pixel (393), „plus" modeli (412/414) i
              iPhone SE/8 (375). Blago stezanje — 425px naviše ostaje netaknut,
              kako je i traženo.
     ≤ 360px  većina Android telefona je TAČNO 360. Ovde se `.form-row-2`
              razdvaja u dva reda: dva `input[type="date"]` polja jedno pored
              drugog ispod ove širine više nisu čitljiva ni sa `minmax(0, …)`.
     ≤ 330px  iPhone SE prve generacije (320) i uski prozori na desktopu.

   Pragovi se GOMILAJU (na 320px važe sva tri), pa idu od šireg ka užem i svaki
   menja samo ono što prethodni nije dovoljno smanjio.

   ⚠️ Nijedno polje za unos ne sme ispod 16px — iOS ispod te mere SAM uveća
   celu stranicu pri fokusu i ostavi je uvećanu (`tests/pristupacnost.test.mjs`
   to i proverava). Polja se ovde zato sužavaju i dobijaju manji padding, ali
   im se font NE dira. */

@media (max-width: 420px) {
  :root {
    --pad-screen: 15px;
    --pad-card: 16px;
    --pad-sheet: 16px;
    --row-icon: 42px;
    --row-icon-gap: 12px;
  }

  /* ---- zaglavlje ---- */
  .topbar {
    padding: 18px 15px 12px;
  }
  .topbar-actions {
    gap: 6px;
  }
  .topbar-actions .icon-btn {
    width: 38px;
    height: 38px;
  }
  .brand {
    gap: 10px;
  }
  .brand-mark {
    width: 50px;
    height: 50px;
  }
  .sticky-banner {
    padding: 10px 15px;
  }

  /* ---- naslovi ekrana ---- */
  .screen-head {
    padding: 10px 0 18px;
  }
  .screen-head h2 {
    font-size: 21px;
  }
  .screen-head p {
    font-size: 13px;
  }

  /* Najveći broj u aplikaciji i jedini koji zavisi od TUĐEG podatka:
     sedmocifren iznos na 42px traži ~325px širine, a toliko kartica na 375px
     telefonu nema. */
  .total-value {
    font-size: 34px;
  }

  /* ---- redovi sa ikonicom (računi, krediti, obaveze, garancije, obaveštenja) ---- */

  /* Gornji sprat nosi PET stvari u istoj liniji: ikonicu, naziv+rok, iznos,
     olovčicu i kantu. Sve osim naziva ima fiksnu širinu, pa naziv dobija samo
     ostatak — na 375px oko 83px, u kojima se dugačko ime („Infostan-stambena
     zajednica-Novi-Beograd") prelama na po jednu reč po redu i red naraste na
     sedam linija. Ne izlazi sa ekrana, ali se ne može ni pročitati.

     Zato: naziv dobija POD od pola širine reda, a red sme da prelomi — kad
     ispod tog poda više nema mesta, dve ikonice se spuste u svoj red i odu uz
     desnu ivicu (`flex-end` na liniju koja nije puna). Kad je ime kratko —
     dakle skoro uvek — ništa se ne menja: `.bill-info` i dalje upija ceo
     slobodan prostor i red ostaje jednolinijski. */
  .bill-row-top {
    flex-wrap: wrap;
    justify-content: flex-end;
  }
  /* `flex: 1 1 0`, a NE nasleđeno `1 1 auto` — i to je cela poenta ovog
     pravila. Flex bira gde da prelomi red po HIPOTETIČKOJ veličini svakog
     deteta, a kod `auto` je to max-content: za dugačko ime ~266px, više nego
     što ceo red ima. Posledica je bila da se u prvi red ne smesti ni ikonica
     sa imenom — ikonica ostane sama, pa odleti uz desnu ivicu, i red izgleda
     rasklimano. Sa osnovom 0 hipotetička veličina je sam `min-width` (pola
     reda), pa se prelamaju tek dve ikonice na kraju, kako i treba.
     `flex-grow: 1` je nepromenjen, pa kratko ime i dalje upija sav slobodan
     prostor i red ostaje jednolinijski. */
  .bill-info {
    flex: 1 1 0;
    min-width: 50%;
  }

  .bill-icon svg,
  .notif-icon svg {
    width: 28px;
    height: 28px;
  }
  .savings-icon {
    width: 44px;
    height: 44px;
  }
  .savings-icon svg {
    width: 28px;
    height: 28px;
  }

  /* ---- Istorija i Top 10 ---- */
  .tx-summary {
    padding: 13px 13px;
    gap: 10px;
  }
  .tx-items {
    padding: 2px 13px 13px;
  }
  .tx-item-price {
    min-width: 66px;
  }
  .top-product-row {
    gap: 10px;
  }
  .top-rank-col {
    width: 30px;
  }
  .top-prod-total {
    min-width: 68px;
  }

  /* ---- dugmad ----
     Bazni `.btn` se NE dira: klasu deli sa `.btn-compact`,
     `.list-add-item-btn` i još nekoliko koji imaju SVOJ padding i istu
     specifičnost, pa bi ih šire pravilo odavde tiho prepisalo. Menja se samo
     puna širina, gde je natpis stvarno stešnjen. */
  /* ⚠️ `:not(.btn-compact)` NIJE višak (korisnikova prijava 16.08.2026:
     „Sačuvaj garanciju i Otkaži nisu iste veličine"). Glavno dugme forme nosi
     OBE klase (`btn-compact btn-block`, 23 mesta u projektu), a ovo pravilo
     deli specifičnost sa `.btn-compact` (0,1,0) i stoji posle njega u fajlu —
     pa je bez izuzetka prepisivalo njegovih `height: 40px` na `min-height:
     50px`. Rezultat: „Sačuvaj garanciju" 50px, „Otkaži" pored njega 40px, i to
     SAMO na telefonu ispod 420px, gde se par i gleda. Kompaktna dugmad imaju
     kratke natpise u jednom redu, pa im prelamanje zbog kog ovo pravilo i
     postoji ionako ne treba. */
  .btn-block:not(.btn-compact) {
    padding-left: 14px;
    padding-right: 14px;
    /* Fiksnih 52px je tačno dok natpis staje u jedan red. „Registruj se kao
       nova porodica" na uskom telefonu pada u dva — a onda tekst izlazi iz
       dugmeta. `min-height` daje isti izgled u jednorednom slučaju i pušta
       dugme da poraste u dvorednom. */
    height: auto;
    min-height: 50px;
  }
  /* MORA posle `.btn-block` — deli specifičnost sa njim, pa odlučuje redosled.
     „Plan potrošnje po kategorijama" je najduži natpis na ovom ekranu i ispod
     ~370px se prelama; sa fiksnom visinom je propadao kroz dno dugmeta. */
  .pregled-pill-btn {
    height: auto;
    min-height: 54px;
    padding: 10px 14px;
    font-size: 14px;
    gap: 10px;
    line-height: 1.3;
  }
  .pregled-pill-icon {
    width: 30px;
    height: 30px;
  }
  .pregled-buttons-wrap {
    gap: 12px;
  }

  /* ---- plan potrošnje po kategorijama ---- */
  .alloc-row {
    gap: 10px;
  }
  .alloc-icon {
    margin-right: 8px;
  }
  .alloc-info {
    margin-right: 10px;
  }
  .alloc-input-wrap {
    width: 84px;
  }

  /* ---- mreže ---- */
  .cat-choice-grid {
    grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
  }
  .challenge-grid {
    grid-template-columns: repeat(auto-fill, minmax(46px, 1fr));
    gap: 6px;
  }

  /* ---- kartice i sekcije ---- */
  .settings-section {
    padding: 14px;
  }
  .plan-card {
    padding: 14px;
  }
  .toggle-only-card {
    padding: 12px 14px;
  }
  .difficulty-card {
    padding: 12px 14px;
  }
  .consent-row {
    padding: 12px;
    gap: 10px;
  }

  /* ---- unos troška ---- */
  .item-edit-row {
    padding: 10px;
  }
  .price-input-wrap {
    width: 98px;
  }
  .item-qty-field {
    flex: 0 0 46px;
  }

  /* Spisak ikonica se otvara iz DRUGE kolone reda (44px boja + 8px razmak).
     Sa `left: 0` mu desna ivica izlazi iz kartice čim ekran padne ispod
     ~365px, pa je pomeren do LEVE ivice reda i ograničen širinom prozora. */
  .form-row-3-cat .emoji-picker-grid {
    left: -52px;
    width: min(236px, calc(100vw - 90px));
  }

  /* ---- vodič ---- */
  .tutorial-step-icon {
    width: 56px;
    height: 56px;
  }
  .tutorial-step-icon svg {
    width: 26px;
    height: 26px;
  }

  /* ---- welcome / prijava ---- */
  .welcome-hero {
    padding: 20px 16px 6px;
  }
  .welcome-section,
  .welcome-bottom {
    padding: 24px 16px 0;
  }
  .welcome-title {
    font-size: 26px;
  }
  .welcome-tagline {
    font-size: 15px;
  }
  .welcome-feature {
    padding: 14px;
    gap: 12px;
  }
  .welcome-feature-icon {
    width: 38px;
    height: 38px;
  }
  .welcome-feature-icon svg {
    width: 20px;
    height: 20px;
  }
  .welcome-qa-row {
    padding: 14px;
  }
  .welcome-donut-wrap {
    gap: 12px;
  }
  .welcome-donut {
    width: 104px;
    height: 104px;
  }
  .login-hero {
    padding: 16px 16px 10px;
  }
  .login-highlights-card {
    margin: 16px 16px 4px;
    padding: 4px 14px;
  }
  .login-actions {
    padding: 8px 16px 18px;
  }
  .brand-mark-lg {
    width: 84px;
    height: 84px;
  }
}

@media (max-width: 360px) {
  :root {
    --pad-screen: 12px;
    --pad-card: 14px;
    --pad-sheet: 14px;
    --row-icon: 38px;
    --row-icon-gap: 10px;
  }

  /* Statistika — grafikon ima ŠEST kolona u jednom redu, pa je najosetljiviji
     element na ekranu: na 360px svakoj ostane ~44px, a šestocifren iznos
     („142.300") na 11px traži ~42px. Ovde se steže i razmak i sam broj, jer
     stub koji se ne vidi ceo ne znači ništa, a iznos koji se prelama u dva
     reda obara visinu svih ostalih kolona. */
  .bar-chart {
    gap: 6px;
    height: 176px;
  }
  .bar-val {
    font-size: 10px;
  }
  .bar-fill {
    width: 30px;
  }
  .stat-delta {
    min-width: 52px;
    padding: 3px 6px;
  }

  .topbar {
    padding: 16px 12px 10px;
  }
  .topbar-actions .icon-btn {
    width: 36px;
    height: 36px;
  }
  .brand-mark {
    width: 44px;
    height: 44px;
  }
  .brand-text h1,
  #topbarSubtitle {
    font-size: 14.5px;
  }
  .sticky-banner {
    padding: 10px 12px;
  }

  .screen-head h2 {
    font-size: 19px;
  }
  .total-value {
    font-size: 29px;
  }
  .total-remaining-lbl {
    font-size: 11.5px;
  }
  .card-title {
    font-size: 11.5px;
    letter-spacing: 0.6px;
  }

  .bill-icon svg,
  .notif-icon svg {
    width: 24px;
    height: 24px;
  }
  .savings-icon {
    width: 40px;
    height: 40px;
  }
  .savings-icon svg {
    width: 25px;
    height: 25px;
  }

  .tx-summary {
    padding: 12px 11px;
    gap: 8px;
  }
  .tx-items {
    padding: 2px 11px 12px;
  }
  .tx-item-row {
    gap: 8px;
  }
  .tx-item-icon {
    width: 24px;
    height: 24px;
    font-size: 13px;
  }
  .tx-item-price {
    min-width: 58px;
    font-size: 12.5px;
  }
  .tx-item-edit-btn {
    width: 26px;
    height: 26px;
    margin-right: -4px;
  }
  .top-rank-col {
    width: 26px;
  }
  .top-prod-icon {
    width: 26px;
    height: 26px;
    font-size: 17px;
  }
  .top-prod-total {
    min-width: 60px;
  }

  /* Dva polja jedno pored drugog ispod ove širine više nisu čitljiva: u paru
     je skoro uvek `input[type="date"]`, koji se sa `minmax(0, …)` doduše više
     ne preliva, ali mu se prikaz datuma odseca. Jedan red po polju je jedino
     rešenje koje ne krije podatak. */
  .form-row-2 {
    grid-template-columns: minmax(0, 1fr);
  }

  /* Donja navigacija ima pet mesta i mora da stane bez preloma na svakoj
     širini — ovo je jedino mesto gde se to stvarno meri. */
  .bottom-nav {
    padding: 8px 6px calc(12px + env(safe-area-inset-bottom, 0px));
  }
  .nav-btn {
    min-width: 42px;
    padding: 4px 2px;
    font-size: 9px;
    gap: 5px;
  }
  .nav-btn svg {
    width: 20px;
    height: 20px;
  }
  .nav-fab {
    width: 48px;
    height: 48px;
    margin-top: -26px;
  }
  .nav-fab svg {
    width: 22px;
    height: 22px;
  }

  .chip {
    padding: 8px 12px;
    font-size: 12px;
  }
  .row-action-btn {
    height: 34px;
    padding: 0 9px;
    gap: 5px;
    font-size: 12px;
  }

  .alloc-row {
    gap: 8px;
  }
  .alloc-icon {
    width: 28px;
    height: 28px;
    font-size: 19px;
    margin-right: 6px;
  }
  .alloc-input-wrap {
    width: 76px;
  }
  .alloc-input-wrap .input {
    min-width: 0;
    padding-left: 2px;
    padding-right: 2px;
  }

  .cat-choice-grid {
    grid-template-columns: repeat(auto-fill, minmax(74px, 1fr));
    gap: 6px;
  }
  .challenge-grid {
    grid-template-columns: repeat(auto-fill, minmax(42px, 1fr));
    gap: 5px;
  }
  .challenge-cell-amount {
    font-size: 11px;
  }

  .item-edit-bottom {
    gap: 6px;
  }
  .cat-pick-btn {
    flex: 0 0 40px;
    width: 40px;
  }
  .item-qty-field {
    flex: 0 0 44px;
  }
  .price-input-wrap {
    width: 92px;
  }
  /* Uz uže polje mora i uži razmak za sufiks „RSD" — inače četvorocifren
     iznos ostane odsečen (izmereno: 4px na 360px). Sufiks je na 10.5px/700
     širok ~22px i stoji na `right: 9px`, pa je 34px dovoljno. */
  .price-input-wrap .input {
    padding-right: 34px;
    padding-left: 8px;
  }

  /* Red „boja / ikonica / naziv" u Podešavanjima — sve tri kolone se stežu
     zajedno, pa polje za naziv ne padne ispod čitljive širine. */
  .form-row-3-cat {
    grid-template-columns: 40px 46px minmax(0, 1fr);
    gap: 6px;
  }
  .edit-cat-color {
    width: 40px;
    height: 40px;
  }
  .edit-cat-icon {
    width: 46px;
  }
  .emoji-picker,
  .emoji-picker-trigger {
    width: 46px;
  }
  .form-row-3-cat .emoji-picker-grid {
    left: -46px;
  }

  .savings-transfer-row {
    gap: 6px;
  }
  .savings-transfer-row .btn {
    padding: 8px 10px;
    font-size: 11.5px;
  }
  .group-code-row {
    padding: 10px 12px;
    gap: 8px;
  }
  .group-code {
    font-size: 14px;
    letter-spacing: 0.5px;
  }
  .member-role-select-wrap {
    width: 118px;
  }

  .welcome-hero {
    padding: 18px 13px 6px;
  }
  .welcome-section,
  .welcome-bottom {
    padding: 22px 13px 0;
  }
  .welcome-title {
    font-size: 24px;
  }
  .welcome-tagline {
    font-size: 14.5px;
  }
  .welcome-feature {
    padding: 12px;
    gap: 10px;
  }
  .welcome-donut {
    width: 88px;
    height: 88px;
  }
  .login-hero {
    padding: 14px 13px 10px;
  }
  .login-highlights-card {
    margin: 14px 13px 4px;
    padding: 4px 12px;
  }
  .login-actions {
    padding: 8px 13px 16px;
  }
  .brand-mark-lg {
    width: 76px;
    height: 76px;
  }
}

@media (max-width: 330px) {
  :root {
    --pad-screen: 10px;
    --pad-card: 12px;
    --pad-sheet: 12px;
    --row-icon: 34px;
    /* 7px, ne 9px: ovaj razmak stoji IZMEĐU SVIH pet delova gornjeg sprata
       reda računa (ikonica · naziv+rok · iznos · olovčica · kanta), dakle
       četiri puta. Dva piksela ovde vrede osam u redu — a baš toliko je
       nedostajalo da „Rok: 15.08.2026." stane pored iznosa na 320px. */
    --row-icon-gap: 7px;
  }

  /* Poslednje stezanje grafikona (320px): kolona spada na ~38px. Ispod 9px se
     ne ide — tekst mora ostati čitljiv, a stub se svejedno vidi. */
  .bar-chart {
    gap: 4px;
    height: 164px;
  }
  .bar-val {
    font-size: 9px;
  }
  .bar-fill {
    width: 26px;
  }
  .bar-lbl {
    font-size: 10px;
  }
  .stat-name {
    font-size: 12.5px;
  }
  .stat-val {
    font-size: 12.5px;
  }
  .stat-delta {
    min-width: 46px;
    font-size: 11px;
  }

  .brand-mark {
    width: 40px;
    height: 40px;
  }
  .screen-head h2 {
    font-size: 18px;
  }
  .total-value {
    font-size: 26px;
  }

  .bill-icon svg,
  .notif-icon svg,
  .savings-icon svg {
    width: 22px;
    height: 22px;
  }
  .savings-icon {
    width: 36px;
    height: 36px;
  }

  .bill-due {
    font-size: 11px;
  }
  .bill-row-top > .bill-amount {
    font-size: 13px;
  }
  .tx-item-price {
    min-width: 52px;
  }
  .top-prod-total {
    min-width: 54px;
  }
  .alloc-input-wrap {
    width: 68px;
  }
  .challenge-grid {
    grid-template-columns: repeat(auto-fill, minmax(38px, 1fr));
  }
  .nav-btn {
    min-width: 38px;
  }
  .row-action-btn {
    padding: 0 8px;
    font-size: 11.5px;
  }
  .form-row-3-cat {
    grid-template-columns: 38px 44px minmax(0, 1fr);
  }
  .edit-cat-color {
    width: 38px;
    height: 38px;
  }
  .edit-cat-icon,
  .emoji-picker,
  .emoji-picker-trigger {
    width: 44px;
  }
  .form-row-3-cat .emoji-picker-grid {
    left: -44px;
    width: min(236px, calc(100vw - 70px));
  }
  .welcome-donut {
    width: 80px;
    height: 80px;
  }
}
