/* Moderela - tokens and base.
   Values come from the design system in the vault:
   outputs/moderela-design-system/ds/foundations/*.
   Nothing here may be softened: the minimum sizes and the focus ring are the
   accessibility floor, not a style preference. */

:root {
  --paper: #F0E8DC;
  --surface: #FBF7F1;
  --surface-max: #FFFFFF;
  --line: #DDCFBE;
  --line-soft: #E3D7C8;

  --ink: #241D1A;
  --ink-70: #40352F;
  --ink-60: #6B6055;          /* lightest permitted text on paper */

  --accent: #C1502E;
  --accent-ink: #8A3418;
  --accent-40: #E8A05C;
  --accent-08: #FBEDDF;

  --done: #3F6B4A;
  --late: #B8621A;
  --danger: #7A2E1E;
  --disabled-bg: #DDCFBE;
  --disabled-ink: #8A8071;

  --r-sm: 3px;
  --r: 4px;
  --r-lg: 5px;
  --r-xl: 6px;
  --r-xxl: 8px;

  --font-head: Archivo, system-ui, sans-serif;
  --font-body: "IBM Plex Sans", system-ui, sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, monospace;

  --hour-row: 72px;
  --time-col: 64px;
}

* { box-sizing: border-box; }

/* Traka sa satom i baterijom na instaliranoj aplikaciji.
   =====================================================
   Moderni iOS je boji **pozadinom dokumenta**, ne oznakom
   `apple-mobile-web-app-status-bar-style` - ta je oznaka danas bitna samo za
   `black-translucent`, koji gura stranicu pod sat. Dok su `html` i `body` bili
   iste bež boje, traka je bila bež.

   Zato je `html` taman a `body` ostaje papir. Vidi se samo ondje gdje se
   `body` ne proteže: iza trake stanja gore, i pri pretjeranom povlačenju na
   dnu. Bez ijedne izmjene u rasporedu i bez razmaka na svakom zaslonu, što je
   cijena koju traži prozirna traka. */
html {
  background: var(--ink);
}

/* Pojas iza sata i baterije, na instaliranoj aplikaciji.
   ======================================================
   Prvi pokušaj je bio tamna podloga dokumenta, i nije radio: uz
   `viewport-fit=cover` raspored pokriva cijeli ekran, pa `body` svojom bež
   bojom preboji i pojas iza sata i podloga se nikad ne vidi. Druga oznaka
   (`apple-mobile-web-app-status-bar-style`) danas mijenja samo to gura li se
   stranica **pod** sat, a to ne želimo jer traži gornji razmak na svakom
   zaslonu.

   Zato traka, izravno preko tog pojasa. U pregledniku je `env()` nula pa je
   visina nula i nema je; u instaliranoj aplikaciji je točno onoliko koliko
   iOS rezervira, na svakom modelu.

   `pointer-events: none`, da ne pojede dodir namijenjen onome ispod nje. */
body::before {
  content: "";
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  /* Točno pojas koji iOS rezervira za sat, i ništa više.
     ====================================================
     U instaliranoj aplikaciji to je stvarna visina i traka se vidi kao tamna.
     U kartici preglednika je nula, dakle trake nema - i tako mora ostati.

     Pokušaj da se u kartici stavi tanka crta (22.08.2026.) je promašio: tamo
     pojas pripada Safariju, sadržaj se pri skrolanju pomiče **pod** sat, pa
     je crta sjela ispod njega i izgledala kao kvar. Ono što se u kartici zna
     promijeniti pri skrolanju je Safarijev posao, ne naš. */
  height: env(safe-area-inset-top);
  background: var(--ink);
  z-index: 50;
  pointer-events: none;
}

html, body {
  margin: 0;
  padding: 0;
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 16px;
  font-weight: 500;
  line-height: 1.5;
  -webkit-text-size-adjust: 100%;
}

/* Tijelo je tamno, a papir je sloj iza sadržaja.
   ==============================================
   Izmjereno 22.08.2026., nakon tri promašaja: Safari boju gornjeg pojasa
   (sat, signal, baterija) uzima iz **pozadine tijela**. Ne iz `theme-color`
   (index.hr ga nema, a traka mu je crvena), ne iz oznake za instaliranu
   aplikaciju, i ne s iscrtane pozadine - pruga na vrhu pozadine nije
   promijenila ništa, dakle čita se izračunata boja.

   Zato je `background` tijela tamna, a papir dolazi kao učvršćeni sloj preko
   cijelog prozora, iza svega ostalog. Zaslon izgleda isto do piksela, a
   traka postaje tamna. */
body {
  /* Boju čita Safari za traku sa satom, sliku vidi čovjek. Vidi objašnjenje
     ispod ovog bloka. Namjerno `background-color`, ne skraćeni `background`:
     skraćeni bi pri svakoj kasnijoj izmjeni ugasio sliku. */
  background-color: var(--ink);
  background-image: linear-gradient(var(--paper), var(--paper));

  /* Duga neprekinuta riječ ne smije odlučivati o širini stranice.

     Klijent se zove kako se zove, a u bilješku ode i e-mail i poveznica. Bez
     ovoga jedan takav niz razvuče zaslon: mjereno 22.08.2026., popis klijenata
     je s jednom dugom adresom bio 946 piksela na ekranu od 402.

     `anywhere`, a ne `break-word`: samo `anywhere` ulazi u računicu najmanje
     širine, a upravo ta računica napuhuje flex i grid rasporede. */
  overflow-wrap: anywhere;
  min-height: 100vh;
  min-height: 100dvh;
}

/* Ono što se vidi je papir, ono što Safari čita je tamno.
   ======================================================
   Pokus s prugom je pokazao da Safari **ne** gleda iscrtanu pozadinu nego
   izračunatu boju: pozadina s tamnim vrhom nije promijenila traku. Ta razlika
   je ovdje rješenje, a ne smetnja. `background-color` ostaje tamna i nju čita
   traka; `background-image` je puni papir i nju vidi čovjek.

   Bez ijednog omotača i bez sloja ispod svega. Prvi popravak je papir stavio
   u `body::after` s negativnim z-indexom i zacrnio cijelu aplikaciju, jer se
   dijete s negativnim slojem crta prije pozadine roditelja. */

h1, h2, h3 { font-family: var(--font-head); margin: 0; }
h1 { font-size: 28px; font-weight: 700; letter-spacing: -.02em; line-height: 1.2; }
h2 { font-size: 22px; font-weight: 700; line-height: 1.25; }
.display { font-size: 40px; font-weight: 800; line-height: 1.1; letter-spacing: -.03em; }

.label {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-60);
}
/* Never browser-blue. Every component that needs its own colour sets one. */
a { color: var(--accent-ink); }

.mono { font-family: var(--font-mono); font-size: 15px; font-weight: 600; }
.small { font-size: 14px; font-weight: 600; }
.muted { color: var(--ink-60); }

/* Focus. Required on every interactive element, mouse and keyboard alike.
   A weaker ring than this does not pass. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
/* `textarea` je nedostajao, pa je jedino polje za opis salona dobivalo plavi
   okvir preglednika dok su sva ostala dobivala naš. Vlasnik je to primijetio
   prije nas: "polje za opis dobije plavi okvir, sva ostala smeđe-crveni". */
textarea:focus-visible,
[tabindex]:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 3px;
}

/* Kvadratići i kružići. Bez ovoga ih crta operativni sustav, pa su usred
   smeđe-bež aplikacije stajale plave Windowsove kvačice. Jedno svojstvo mijenja
   boju i kvačice i okvira, i radi u svim preglednicima koje ciljamo. */
input[type="checkbox"],
input[type="radio"] {
  accent-color: var(--accent);
}

/* ---------------------------------------------------------------- buttons */
/* `nowrap` i `flex: none` postoje iz istog razloga kao kod `.seg a`:
   `overflow-wrap: anywhere` na <body> je jedina vrijednost koja ulazi u
   računicu najmanje širine, pa bez ovoga gumb koji stoji u flex retku (npr.
   „Prikaži" u `.filterrow form` na Izvještajima) smije se stisnuti na jedan
   znak i na telefonu ispisati okomito.

   To vrijedi za `flex`, ne i za `nowrap`. Kontekst koji gumb rasteže preko
   cijelog retka (npr. `.entryfoot .btn`, `.row-form .btn`) postavlja svoj
   `flex` i time nadjačava `flex: none`, ali `white-space: nowrap` time nije
   dotaknut: gumb i dalje odbija prijelom retka. Dva retka s po dva gumba
   (`absence_report.html`, `appointment_new.html`) zato dobivaju `flex-wrap:
   wrap` na svom retku, isti obrazac kao `absence_workflow.html` i
   `appointment_detail.html` već koriste, da gumb koji ne stane padne u
   sljedeći red umjesto da gura susjeda izvan zaslona.

   `.btn-block` (natpis koji dolazi iz podataka: klijentovo ime, ili
   `undoable.summary`) nema retka koji bi mu ustupio mjesto, pa je jedini
   ispravan izlaz prijelom unutar samog gumba, ne bijeg iz njega. Zato niže
   vraća `white-space: normal`. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 52px;
  padding: 0 24px;
  border: 0;
  border-radius: var(--r);
  font: 700 17px var(--font-body);
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  flex: none;
}
.btn-primary { background: var(--accent); color: var(--surface); }
.btn-primary:hover, .btn-primary:active { background: var(--accent-ink); }
.btn-confirm { background: var(--ink); color: var(--surface); }
.btn-secondary {
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--line-soft);
  padding: 0 22px;
}
.btn-danger { background: var(--danger); color: var(--surface); }
.btn[disabled] { background: var(--disabled-bg); color: var(--disabled-ink); cursor: default; }
/* `white-space: normal` nadjačava bazni `nowrap`: natpis ovdje zna doći iz
   podataka (klijentovo ime i broj, `undoable.summary`), pa duljinu određuje
   salon ili njegov klijent, ne predložak. Gumb nema retka koji bi mu ustupio
   mjesto kao `.entryfoot`, pa je prijelom teksta jedini izlaz koji ne gura
   ništa izvan zaslona. */
.btn-block { width: 100%; white-space: normal; }
.btn-compact { height: 48px; padding: 0 18px; font-size: 16px; }

/* ----------------------------------------------------------------- fields */
/* `min-width: 0` jer polje često stoji kao član retka (`display:flex` uz
   `flex:1`), a član flex retka se zadano ne da stisnuti ispod vlastite najmanje
   širine: polje za vrijeme je u Chromeu široko 175 piksela, pa dva takva u
   retku drže 358 i ne popuštaju. Ovdje nije bio uzrok (vidi `.staff` niže),
   ali je isti mehanizam i sljedeći redak s dva polja bi na njega naletio. */
.field { display: block; margin-bottom: 16px; min-width: 0; }
.field > .label { display: block; margin-bottom: 6px; }
.input, .select {
  width: 100%;
  height: 56px;
  padding: 0 14px;
  background: var(--surface-max);
  border: 1px solid var(--line-soft);
  border-radius: var(--r);
  font: 500 16px var(--font-body);
  color: var(--ink);
}
.input--error { border: 2px solid var(--danger); }
.error-text { color: var(--danger); font: 600 14px var(--font-body); margin-top: 6px; }

.card {
  background: var(--surface);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-lg);
}

/* --------------------------------------------------------------- the shell
   A rail on the left that never moves, a bar across the top for where you are
   and what you are looking for, and the work in the middle. The rail is what
   makes six sections reachable without any of them costing a click to find. */
.shell { display: flex; min-height: 100vh; min-height: 100dvh; align-items: stretch; }
/* iOS reports 100vh as the viewport with the address bar hidden, so a page
   with nothing in it is still a toolbar taller than the screen and scrolls
   for no reason. `svh` is the small viewport: it never overshoots and, unlike
   `dvh`, it does not resize while the toolbar slides. */
@supports (min-height: 100svh) {
  .shell { min-height: 100svh; }
  .rail { height: 100svh; }
  body.site-page { min-height: 100svh; }
}
.shell-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }

.rail {
  width: 224px; flex: none;
  background: var(--ink); color: var(--surface);
  display: flex; flex-direction: column; padding: 20px 14px 16px;
  position: sticky; top: 0; height: 100vh;
}
.rail-brand {
  display: flex; align-items: center; gap: 10px;
  padding: 0 8px 22px; text-decoration: none;
}
.rail-brand span {
  font-family: var(--font-head); font-size: 21px; font-weight: 800;
  letter-spacing: -.02em; color: var(--surface);
}
.rail-nav { display: flex; flex-direction: column; gap: 3px; }
.railtab {
  display: flex; align-items: center; gap: 12px;
  min-height: 44px; padding: 0 12px; border-radius: var(--r);
  color: #C9BEB2; text-decoration: none;
  font: 600 16px var(--font-body);
}
.railtab:hover { background: rgba(251,247,241,.08); color: var(--surface); }
/* The active section is the only filled thing in the rail, so it reads at a
   glance from a metre away. */
.railtab.is-on { background: var(--accent); color: var(--surface); }
.railtab.is-on svg { color: var(--surface); }
.railtab .cnt {
  margin-left: auto; min-width: 22px; height: 22px; padding: 0 6px;
  background: var(--accent); color: var(--surface);
  border-radius: var(--r-sm); font: 700 13px var(--font-mono); font-style: normal;
  display: inline-flex; align-items: center; justify-content: center;
}
.railtab.is-on .cnt { background: var(--surface); color: var(--accent-ink); }

.rail-foot {
  margin-top: auto; padding-top: 16px;
  border-top: 1px solid rgba(251,247,241,.14);
  display: flex; flex-direction: column; gap: 8px;
}
.rail-me {
  display: flex; align-items: center; gap: 10px;
  padding: 8px; border-radius: var(--r); text-decoration: none;
}
.rail-me:hover { background: rgba(251,247,241,.08); }
.rail-me .nm { display: block; font: 700 15px var(--font-body); color: var(--surface); }
.rail-me .ro { display: block; font: 600 12px var(--font-mono); color: #9C9086; }
.rail-out {
  width: 100%; height: 40px; border: 1px solid rgba(251,247,241,.18);
  background: transparent; color: #C9BEB2; border-radius: var(--r);
  font: 600 14px var(--font-body); cursor: pointer;
}
.rail-out:hover { color: var(--surface); border-color: rgba(251,247,241,.4); }

/* ------------------------------------------------------------- app chrome */
/* Gornje trake ostaju na ekranu.
   ==============================
   Dvije koristi, i obje su tražene. Prva: boja gornjeg pojasa (sat, signal,
   baterija) u Safariju prati ono što je na vrhu prozora, pa traka koja ostaje
   gore drži i tu boju - isti razlog zbog kojeg index.hr ima crvenu traku
   dok se skrola. Druga: zaglavlje s adresom i danom je ono na što se čovjek
   vraća najčešće, a dosad je odlazilo gore s prvim pomakom.

   `z-index` iznad ljepljivih zaglavlja u kalendaru (2 i 3), ispod trake iza
   sata (50). */
.topbar {
  background: var(--surface); border-bottom: 1px solid var(--line-soft);
}
/* Namjerno **nije** ljepljiva, za razliku od djelatnikove i konzolne.
   Te dvije su tamne, pa pojas iznad njih ostaje taman i dok se skrola. Ova je
   svijetla, i čim se prikvači na vrh Safari boju pojasa uzima s nje umjesto iz
   pozadine tijela - i sat opet sjedi na bež. Dok voditeljevo zaglavlje ne
   postane tamno, ljepljivo je gore nego obično. */
.topbar-inner {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 20px; flex-wrap: wrap;
}
.spacer { flex: 1; }

/* Prebacivač lokacije: puna tamna ploha, oznaka mjesta lijevo, strelica desno.
   Iz `ds/components/navigacija-i-logotip.html`. Bio je svijetla kutija s
   obrubom i bez ičega što bi reklo da se otvara, jer je `appearance: none`
   maknuo i strelicu koju inače crta preglednik.

   Ostaje pravi `<select>`, pa izbornik crta operativni sustav i radi
   tipkovnicom i bez JavaScripta. Ukrasi su iznad njega i ne primaju klik. */
.locpick { position: relative; display: inline-flex; align-items: center; }
.locpick > svg,
.locpick .locpick-caret {
  position: absolute; pointer-events: none; color: var(--surface-max);
  display: inline-flex; align-items: center;
}
.locpick > svg { left: 14px; opacity: .85; }
.locpick .locpick-caret { right: 14px; font-size: 13px; }

.locbox {
  height: 46px; padding: 0 34px 0 40px; min-width: 180px;
  background: var(--ink); border: 1px solid var(--ink);
  border-radius: var(--r); font: 700 16px var(--font-body); color: var(--surface-max);
  appearance: none; cursor: pointer;
}
.locbox:hover { background: #342A25; border-color: #342A25; }
/* Popis koji otvori sustav crta se u svojim bojama, ne u našima: bijeli tekst
   na bijelom bio bi popis koji se ne može pročitati. */
.locbox option { background: var(--surface-max); color: var(--ink); }

/* ------------------------------------------------------- odabir datoteke
   `Choose file / No file chosen` je ono što preglednik nacrta kad mu se ništa
   ne kaže, i ne izgleda kao nijedno drugo polje u aplikaciji. Gumb unutar
   polja je zaseban element (`::file-selector-button`) i može se obući kao i
   svaki drugi, bez JavaScripta i bez gubljenja pravog dijaloga za odabir. */
.input[type="file"] {
  padding: 8px 10px; line-height: 1.4; cursor: pointer;
  color: var(--ink-60); font-size: 14px;
}

/* Vlastiti gumb za odabir datoteke. Tekst na urođenom gumbu piše preglednik i
   ne da se ni prevesti ni stilizirati, pa je usred hrvatskog zaslona stajalo
   "Choose file / No file chosen". Ovdje polje prekriva gumb i prozirno je:
   klik, tipkovnica i čitač ekrana i dalje idu na pravo polje, a piše naše.
   Ime odabrane datoteke se time gubi, ali odabir je ionako korak prije
   spremanja, a poslije spremanja se vidi sama slika. */
.filebtn { position: relative; display: inline-flex; align-items: center;
  gap: 8px; padding: 10px 16px; cursor: pointer;
  background: var(--surface-max); color: var(--ink);
  border: 1px solid var(--line); border-radius: var(--r);
  font: 600 15px var(--font-body); }
.filebtn:hover { border-color: var(--ink-60); }
.filebtn:focus-within { outline: 3px solid var(--accent); outline-offset: 3px; }
.filebtn input[type="file"] {
  position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: 0; cursor: pointer; }
.input[type="file"]::file-selector-button {
  margin-right: 12px; padding: 7px 14px; cursor: pointer;
  background: var(--surface-max); color: var(--ink);
  border: 1px solid var(--line); border-radius: var(--r-sm);
  font: 600 14px var(--font-body);
}
.input[type="file"]::file-selector-button:hover {
  background: var(--ink); border-color: var(--ink); color: var(--surface-max);
}
.input[type="file"]:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* Chevron, date, chevron - one group, so the date reads as the thing being
   stepped through rather than a label between two unrelated buttons. */
.daystep { display: inline-flex; align-items: center; }
.daystep a, .daystep .now {
  height: 46px; display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--line-soft); background: var(--surface-max);
  color: var(--ink); text-decoration: none; font: 700 16px var(--font-body);
}
.daystep a { width: 46px; }
.daystep a:first-child { border-radius: var(--r) 0 0 var(--r); }
.daystep a:last-child { border-radius: 0 var(--r) var(--r) 0; }
.daystep .now {
  padding: 0 18px; background: var(--ink); border-color: var(--ink);
  color: var(--surface); font-family: var(--font-mono); font-size: 15px;
}

.search {
  display: flex; align-items: center; gap: 10px;
  height: 46px; padding: 0 14px; min-width: 220px;
  background: var(--surface-max); border: 1px solid var(--line-soft);
  border-radius: var(--r); color: var(--ink-60);
}
.search input {
  border: 0; background: transparent; outline: none; width: 100%;
  font: 500 15px var(--font-body); color: var(--ink);
}
.search:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-08); }

.badge-count {
  min-width: 22px; height: 22px; padding: 0 6px;
  background: var(--accent); color: var(--surface);
  font: 600 12px var(--font-mono);
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 11px; margin-left: 6px;
}

.page { padding: 20px; flex: 1; }
.callout { max-width: 78ch; margin: 12px 0 0; }

/* ------------------------------------------------------------ side panel
   What is waiting on the manager, kept beside the work rather than behind a
   tab, because a queue you have to go looking for is a queue that grows. */
.aside {
  width: 340px; flex: none; padding: 18px 18px 40px;
  background: var(--surface); border-left: 1px solid var(--line-soft);
}
.aside-head { display: flex; align-items: center; gap: 10px; margin-bottom: 14px; }
.aside-head h2 { font-size: 19px; }
.aside-chip {
  margin-left: auto; padding: 4px 10px; border-radius: var(--r-sm);
  background: var(--accent); color: var(--surface);
  font: 700 12px var(--font-mono);
}
.mini-req {
  background: var(--surface-max); border: 1px solid var(--line-soft);
  border-radius: var(--r-lg); padding: 14px; margin-bottom: 10px;
}
.mini-req-who { display: flex; gap: 10px; align-items: center; margin-bottom: 10px; }
.mini-req-who .nm { font-size: 16px; font-weight: 600; }
.mini-req-who .wh { font: 600 13px var(--font-mono); color: var(--ink-60); }
.mini-note {
  display: flex; gap: 8px; padding: 9px 11px; border-radius: var(--r);
  font-size: 13.5px; font-weight: 600; margin-bottom: 10px;
}
.mini-note.ok { background: var(--paper); color: var(--ink-70); }
.mini-note.clash { background: #F7E4DC; color: var(--late); }
.mini-acts { display: flex; gap: 8px; }
.mini-acts form { flex: 1; }
.mini-acts .btn { width: 100%; height: 42px; font-size: 15px; padding: 0 12px; }

.gauge { margin-top: 8px; }
.gauge-row { display: flex; align-items: baseline; justify-content: space-between; font-size: 14px; }
.gauge-bar { height: 8px; border-radius: 4px; background: var(--line); margin: 6px 0 14px; overflow: hidden; }
.gauge-bar i { display: block; height: 100%; background: var(--ink); }
.gauge-bar.is-accent i { background: var(--accent); }

/* --------------------------------------------------------- bottom bar */
.bottombar { display: none; }
/* The "Više" summary is listed beside `.bottomtab` everywhere, not styled
   separately. Styled separately it picked up one of the two blocks below and
   not the other, laid itself out as a `list-item` instead of a flex column,
   and its label sat three pixels above the other four. A tab bar is the one
   place where three pixels are visible: the labels form a line. */
.bottomtab, .moretab summary {
  flex: 1; text-align: center; padding: 7px 0 5px;
  color: var(--ink-60); text-decoration: none;
  font: 700 12px var(--font-body);
  display: flex; flex-direction: column; align-items: center; gap: 3px;
}
.bottomtab .ic, .moretab summary .ic { position: relative; line-height: 0; }
.bottomtab .dot {
  position: absolute; top: -6px; left: 12px;
  min-width: 18px; height: 18px; padding: 0 5px;
  background: var(--accent); color: var(--surface);
  border-radius: 9px; font: 700 11px var(--font-mono); font-style: normal;
  display: inline-flex; align-items: center; justify-content: center;
}
.bottomtab.is-on { color: var(--accent-ink); background: var(--surface-max); }
.bottomtab.is-on svg { color: var(--accent); }

/* -------------------------------------------------------------- day bar */
.daybar {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 14px 18px; margin-bottom: 16px;
  background: var(--surface); border: 1px solid var(--line-soft);
  border-radius: var(--r-lg);
}
.daytitle h1 { font-size: 26px; line-height: 1.15; }
.daysummary {
  font: 600 13px var(--font-mono); color: var(--ink-60); margin-top: 3px;
}
.daynav { display: flex; gap: 6px; align-items: center; }
.daynav a, .daynav button {
  min-width: 44px; height: 44px;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0 12px;
  background: var(--surface-max); border: 1px solid var(--line-soft);
  border-radius: var(--r); color: var(--ink);
  font: 700 16px var(--font-body); text-decoration: none;
}
/* Jedan `.seg`, ne dva. Do 02.09.2026. su postojala dva bloka s različitim
   visinama, a drugi je pobjeđivao, pa je prvi bio mrtav kod.

   `nowrap` i `flex: none` postoje zbog `overflow-wrap: anywhere` na <body>:
   to je jedina vrijednost koja ulazi u računicu najmanje širine, pa bez ovoga
   raspored smije stisnuti natpis na jedan znak i „Prikaži" se na telefonu
   ispiše okomito.

   Do 03.09.2026. je rub bio `overflow: hidden`, radi zaobljenih uglova. Ali
   kad `.seg` ima više stavki nego što stane (Dnevnik zna imati četiri
   filtra), `nowrap` više ne dopušta stiskanje, pa se zadnja stavka odrezala
   i do nje se nije dalo doskrolati - gore od izvornog kvara. Rub je sad
   `overflow-x: auto`, isti obrazac kao `.rasporedwrap`/`.daystrip`, a
   zaobljeni uglovi dolaze izravno s prvog i zadnjeg `.seg a`, isti obrazac
   kao `.daystep a:first-child`/`:last-child`.

   Taj `overflow-x: auto` sam po sebi nije bio dovoljan: `.seg` je i dalje
   `inline-flex`, dakle vlastita širina mu se računa kao "shrink-to-fit", a ta
   računica ne ide ispod širine svog sadržaja kad ništa vanjsko ne kaže
   drukčije. Gdje god `.seg` nije flex stavka koju rasteže tuđi red (Dnevnik:
   gol `<nav class="seg">`, izvan `.day-head`, izvan `.topbar-inner`) nije se
   imao od čega stisnuti, pa se sama kutija širila preko dostupnog prostora i
   vukla cijelu stranicu vodoravno - novi kvar umjesto starog. `max-width:
   100%` je vanjska ograda koja to zaustavlja bez obzira je li `.seg` u tom
   trenutku flex stavka ili ne; `overflow-x: auto` onda doista ima što
   skrolati unutar te ograde. */
.seg { display: inline-flex; flex: none; max-width: 100%; border: 1px solid var(--line-soft); border-radius: var(--r); overflow-x: auto; -webkit-overflow-scrolling: touch; }
.seg a {
  height: 42px; padding: 0 16px; display: inline-flex; align-items: center;
  white-space: nowrap; flex: none;
  background: var(--surface-max); color: var(--ink-70);
  font: 700 15px var(--font-body); text-decoration: none;
}
.seg a:first-child { border-radius: var(--r) 0 0 var(--r); }
.seg a:last-child { border-radius: 0 var(--r) var(--r) 0; }
.seg a.is-on { background: var(--ink); color: var(--surface); }
.seg a[aria-disabled="true"] { color: var(--disabled-ink); }

/* --------------------------------------------------------------- calendar */
.cal-scroll {
  overflow-x: auto; background: var(--surface);
  border: 1px solid var(--line-soft); border-radius: var(--r-lg);
}
.cal { display: grid; min-width: 860px; }

.cal-head {
  display: flex; align-items: center; gap: 9px;
  padding: 10px 10px;
  border-bottom: 1px solid var(--line); border-left: 1px solid var(--line);
  position: sticky; top: 0; background: var(--surface); z-index: 2;
}
.cal-head.is-off { background: var(--paper); }
.cal-head .who { min-width: 0; }
.cal-head .nm {
  display: block; font: 700 15px var(--font-body);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cal-head .state {
  display: block; font: 600 12px var(--font-mono); color: var(--ink-60); margin-top: 1px;
}
/* Accent means somebody is waiting on a decision. Nothing else in the header
   earns it. */
.cal-head .state.is-waiting { color: var(--accent-ink); }
.cal-corner { border-bottom: 1px solid var(--line); position: sticky; top: 0; background: var(--surface); z-index: 3; }

.cal-times { position: relative; }
.cal-hour {
  height: var(--hour-row); padding: 4px 8px;
  font: 600 13px var(--font-mono); color: var(--ink-60);
  border-bottom: 1px solid var(--line);
}
.cal-hour.is-now { color: var(--accent); font-weight: 700; }

.cal-col {
  position: relative; border-left: 1px solid var(--line);
  background: var(--surface-max);
  background-image: repeating-linear-gradient(
    to bottom, transparent 0, transparent 71px, var(--line) 71px, var(--line) 72px);
}

/* Hatched: never bookable. The label explains why, because a blank hatched
   morning otherwise reads as a broken rota. */
.cal-offshift {
  position: absolute; left: 0; right: 0;
  background: repeating-linear-gradient(45deg,
    #F0E8DC, #F0E8DC 3px, #DDCFBE 3px, #DDCFBE 7px);
  display: flex; align-items: flex-start; justify-content: center;
  padding-top: 10px; overflow: hidden;
  pointer-events: none;
}
.cal-offshift span {
  font: 600 13px var(--font-body); color: var(--ink-60);
  background: rgba(251,247,241,.82); padding: 3px 10px; border-radius: var(--r);
}

/* White: free, and a click opens a new appointment already filled in. */
.cal-free {
  position: absolute; left: 3px; right: 3px;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--r); text-decoration: none;
  color: var(--ink-60); font: 600 13px var(--font-body);
}
.cal-free span { opacity: 0; font: 700 13px var(--font-body); }
.cal-free:hover { background: var(--accent-08); box-shadow: inset 0 0 0 1px var(--accent-40); color: var(--accent-ink); }
.cal-free:hover span, .cal-free:focus-visible span { opacity: 1; }

.now-line { position: absolute; left: 0; right: 0; height: 2px; background: var(--accent); z-index: 4; }
.now-dot { position: absolute; left: -5px; width: 12px; height: 12px; background: var(--accent); z-index: 5; }

/* ---- appointment blocks. Colour is never the only signal: each state also
   carries a border, a stroke, a mark or a word. ---- */
.appt {
  position: absolute; left: 3px; right: 3px;
  border-radius: var(--r); padding: 5px 8px; overflow: hidden;
  text-decoration: none; display: block; z-index: 3;
}
.appt .t { display: block; font: 600 12px var(--font-mono); opacity: .8; }
.appt .n { display: block; font: 600 14px var(--font-body); margin-top: 1px; }
.appt .s { display: block; font: 600 13px var(--font-body); margin-top: 1px; }
.appt.tight { padding: 3px 8px; }
.appt.tight .t { display: inline; margin-right: 6px; }
.appt.tight .n { display: inline; font-size: 13px; }
.appt.tight .s { display: none; }

.appt.s-booked { background: var(--ink); color: var(--surface); }
.appt.s-completed { background: var(--done); color: var(--surface); }
.appt.s-unconfirmed {
  background: var(--accent-08); color: var(--ink);
  border: 2px dashed var(--accent);
}
.appt.s-unconfirmed .s { color: var(--accent-ink); }
.appt.s-cancelled_in_time {
  background: var(--paper); color: var(--ink-60);
  border-left: 6px solid var(--ink-60);
}
.appt.s-cancelled_in_time .n { text-decoration: line-through; }
.appt.s-cancelled_late {
  background: var(--paper); color: var(--ink);
  border-left: 6px solid var(--late);
}
.appt.s-cancelled_late .n { text-decoration: line-through; }
.appt.s-cancelled_late .s { color: var(--late); }
.appt.s-no_show {
  background: var(--paper); color: var(--danger);
  border-left: 6px solid var(--danger);
}

/* The one action allowed to sit inside the grid, because leaving it out means
   the decision never gets made. */
.cal-rate { position: absolute; left: 6px; right: 6px; z-index: 5; }
.cal-rate button {
  width: 100%; height: 26px; border: 0; border-radius: var(--r-sm);
  background: var(--accent); color: var(--surface);
  font: 700 13px var(--font-body); cursor: pointer;
}
.cal-rate button:hover { background: var(--accent-ink); }

/* ------------------------------------------------------- phone: day as list
   Six columns do not fit on a phone. The day becomes a list by time, with a
   standing strip on top - on a phone the first question is where the holes
   are, not what is next. */
.daylist { display: none; background: var(--surface); border: 1px solid var(--line-soft); border-radius: var(--r-lg); overflow: hidden; }

.standing { padding: 14px 16px; border-bottom: 1px solid var(--line-soft); }
.standrow {
  display: flex; align-items: center; gap: 10px;
  padding: 5px 0; text-decoration: none; color: inherit;
}
.standrow .bars {
  position: relative; flex: 1; height: 18px;
  background: var(--surface-max); border-radius: var(--r-sm); overflow: hidden;
}
.standrow .bars i { position: absolute; top: 0; bottom: 0; }
.standrow .b-off { background: repeating-linear-gradient(45deg, #F0E8DC, #F0E8DC 2px, #DDCFBE 2px, #DDCFBE 5px); }
.standrow .b-booked { background: var(--ink); }
.standrow .b-completed { background: var(--done); }
.standrow .b-unconfirmed { background: var(--accent-08); box-shadow: inset 0 0 0 1.5px var(--accent); }
.standrow .b-cancelled_in_time,
.standrow .b-cancelled_late,
.standrow .b-no_show { background: var(--line); }
.standstate {
  font: 600 12px var(--font-mono); color: var(--ink-60);
  width: 88px; text-align: right; flex: none;
}
.standstate.is-waiting { color: var(--accent-ink); }

.timeband {
  padding: 8px 16px; background: var(--paper);
  border-top: 1px solid var(--line-soft); border-bottom: 1px solid var(--line-soft);
  font: 600 13px var(--font-mono); color: var(--ink-60);
  position: sticky; top: 0; z-index: 2;
}
.daylist-row {
  display: flex; gap: 12px; padding: 10px 16px; align-items: flex-start;
  text-decoration: none; color: inherit;
}
.daylist-body { flex: 1; border-radius: var(--r); padding: 9px 12px; }
.daylist-body .t { display: block; font: 600 12px var(--font-mono); opacity: .8; }
.daylist-body .n { display: block; font-size: 17px; font-weight: 600; margin-top: 1px; }
.daylist-body .s { display: block; font-size: 13px; font-weight: 600; margin-top: 1px; }
.daylist-body.s-booked { background: var(--ink); color: var(--surface); }
.daylist-body.s-completed { background: var(--done); color: var(--surface); }
.daylist-body.s-unconfirmed { background: var(--accent-08); border: 2px dashed var(--accent); }
.daylist-body.s-cancelled_in_time { background: var(--paper); color: var(--ink-60); border-left: 6px solid var(--ink-60); }
.daylist-body.s-cancelled_late { background: var(--paper); border-left: 6px solid var(--late); }
.daylist-body.s-no_show { background: var(--paper); color: var(--danger); border-left: 6px solid var(--danger); }
.daylist-body.s-cancelled_in_time .n,
.daylist-body.s-cancelled_late .n { text-decoration: line-through; }

.empty { padding: 44px 24px; text-align: center; color: var(--ink-70); }
.empty h2 { margin-bottom: 8px; }

/* --------------------------------------------------------- bottom bar */
.bottombar { display: none; }
/* NOTE: this is the second complete "bottom bar" block in this file. The two
   disagree about padding, about `.ic`, about where the dot sits and about what
   `.is-on` looks like, and the tabs end up wearing a mix of both. Left as it
   is here because untangling it changes how the bar looks, which is a separate
   decision; it is written down in the backlog. The summary is listed alongside
   so that whatever the two blocks settle on, the fifth tab settles on it too. */
.bottomtab, .moretab summary {
  flex: 1; text-align: center; padding: 8px 0 6px;
  color: var(--ink-60); text-decoration: none;
  font: 700 12px var(--font-body);
}
.bottomtab .ic, .moretab summary .ic {
  display: block; font-size: 20px; line-height: 1.1; position: relative;
}
.bottomtab .dot {
  position: absolute; top: -4px; right: 50%; margin-right: -20px;
  min-width: 18px; height: 18px; padding: 0 5px;
  background: var(--accent); color: var(--surface);
  border-radius: 9px; font: 600 11px var(--font-mono); font-style: normal;
  display: inline-flex; align-items: center; justify-content: center;
}
.bottomtab.is-on { color: var(--ink); }
.bottomtab.is-on .ic { color: var(--accent); }

@media (max-width: 1119px) {
  .cal { min-width: 720px; }
  :root { --time-col: 56px; }
}

@media (max-width: 1180px) {
  .aside { width: 300px; }
}

@media (max-width: 1000px) {
  .shell { flex-wrap: wrap; }
  /* Not decoration: without it the calendar is invisible on a phone.
     `flex: 1` means `flex-basis: 0%`, so this column's hypothetical size is
     zero, the aside at width:100% always "fits" beside it, the row never
     wraps, and the grow step hands the main column the leftover space, which
     is none. It measured 0px wide on an iPhone while the aside sat at 390px,
     so the whole day was there in the DOM and nothing of it on the screen.
     A basis of 100% forces the line break the wrap was written for. */
  .shell-main { flex-basis: 100%; }
  .aside { width: 100%; border-left: 0; border-top: 1px solid var(--line-soft); }
}

@media (max-width: 767px) {
  .rail { display: none; }
  /* Enough room under the last row for the bar plus whatever the phone
     reserves for its own gesture area. Without the inset the final
     appointment of the day hides behind the tabs. */
  .page { padding: 12px 12px calc(88px + env(safe-area-inset-bottom)); }
  .cal-scroll, .callout { display: none; }
  .daylist { display: block; }

  /* Five controls wrapping into four rows put about 180px of chrome above the
     first appointment of the day. Two of them earn their place on a phone: the
     day you are looking at, and the button that adds one.

     The client search goes. It is the same search that sits at the top of the
     Klijenti tab, one thumb away in the bar at the bottom, so on this screen it
     is a whole row spent on a duplicate.

     The location picker and "+ Novi termin" share a row instead of taking one
     each: a select and a button both fit across 390px and neither needs the
     full width the way the day stepper does. */
  /* Traka koja na telefonu nema što pokazati ne smije uzeti prostor.

     Tražilica i razmak se ovdje skrivaju, pa na zaslonima kojima je tražilica
     bila jedini sadržaj (Smjene, Postavke, Usluge, Klijenti) ostaje prazna
     bijela ploha s obrubom, visoka koliko i sam obrub plus dva puta deset
     piksela. Vlasnik ju je vidio prije nas i pitao što je to.

     Traka se zato skriva, pa se vraća samo ako u njoj stoji nešto što na
     telefonu doista ostaje vidljivo: prebacivač dana, prebacivač prikaza,
     glavni gumb ili odabir lokacije. `:has` je u ovoj datoteci već u
     upotrebi. */
  .topbar { display: none; }
  .topbar:has(.daystep, .seg, .btn-primary, .locpick) { display: block; }

  .topbar-inner { padding: 10px 12px; gap: 8px; }
  .topbar-inner .search { display: none; }
  .topbar-inner .spacer { display: none; }
  .locbox { min-width: 0; flex: 1; }
  .topbar-inner > form:first-child { flex: 1; min-width: 0; order: 1; }
  .topbar-inner .btn-primary { order: 2; white-space: nowrap; }
  .topbar-inner .daystep { order: 3; }
  .topbar-inner .seg { order: 4; }

  .daybar { padding: 12px; }
  .daytitle h1 { font-size: 22px; }
  /* The same two arrows as the stepper above, sixty pixels below it and
     without the date to say what they step through. On a desktop they sit
     beside the day title and have room to be a convenience; stacked under a
     full-width stepper they are just the duplicate you have to look past. */
  .daybar .daynav { display: none; }

  /* The day stepper is the control you actually use on a phone: it is how you
     get to tomorrow. Left as an inline pill it sat in the middle of its own
     row with both arrows within a centimetre of each other, which on a thumb
     is one target, not two. Full width puts each arrow at the edge it belongs
     to and the date between them.

     The view switcher goes with it because it sits directly underneath: a
     half-width row under a full-width one reads as something that failed to
     load rather than as a choice. Scoped to the bar, so the filter rows that
     borrow `.seg` elsewhere keep their own width. */
  .topbar-inner .daystep { display: flex; width: 100%; }
  .topbar-inner .daystep .now { flex: 1; }
  .topbar-inner .seg { display: flex; width: 100%; }
  /* `justify-content`, not `text-align`: `.seg a` is itself an inline-flex
     box, so the label is an anonymous flex item and sits wherever the main
     axis puts it. `text-align: center` on a flex container does nothing to
     it, which is why the first attempt left "Dan" against the left edge of a
     button three times its width. Padding goes too, or it fights the even
     thirds. */
  .topbar-inner .seg a { flex: 1; justify-content: center; padding: 0 8px; }

  /* The background runs to the edge of the glass, the taps do not.
     `max()` rather than the bare inset because the inset is 0 on every phone
     without a home indicator and on desktop, and the row still needs a few
     millimetres under it there. Left and right matter in landscape, where the
     notch takes a bite out of one side. */
  .bottombar {
    display: flex;
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
    background: var(--surface); border-top: 1px solid var(--line-soft);
    padding-bottom: max(8px, env(safe-area-inset-bottom));
    padding-left: env(safe-area-inset-left);
    padding-right: env(safe-area-inset-right);
  }

  /* Traka je fiksna, dakle stoji iznad sadržaja, a zadnja stvar na stranici je
     u pravilu gumb "Spremi". Bez ovoga on završi ispod trake: vlasnik ga na
     telefonu vidi napola i pogodi ikonu izbornika umjesto njega. Mjera je
     visina trake plus sigurni rub plus prst razmaka. */
  .page, .staff { padding-bottom: calc(78px + env(safe-area-inset-bottom)); }
}

/* ----------------------------------------------------------- shift queue
   Faza A2: the list on the left, the argument for the decision on the right.
   A row with two buttons is a decision made blind. */
.split { display: grid; grid-template-columns: minmax(0, 1fr) 400px; gap: 20px; align-items: start; }
.split-list { min-width: 0; }
.split-detail { padding: 22px; position: sticky; top: 16px; }

.reqrow {
  display: flex; gap: 12px; align-items: flex-start;
  padding: 14px 16px; margin-bottom: 8px;
  background: var(--surface); border: 1px solid var(--line-soft);
  border-radius: var(--r-lg); text-decoration: none; color: var(--ink);
}
.reqrow.is-on { border-color: var(--ink); box-shadow: inset 3px 0 0 var(--accent); }
.reqrow.is-clash { border-left: 6px solid var(--late); }
.reqmeta { min-width: 0; flex: 1; }
.reqmeta .nm { display: block; font-size: 17px; font-weight: 600; }
.reqmeta .loc { font: 600 13px var(--font-mono); color: var(--ink-60); margin-left: 6px; }
.reqmeta .wh { display: block; font: 600 14px var(--font-mono); color: var(--ink-70); margin-top: 2px; }
.reqmeta .sub { display: block; font-size: 14px; color: var(--ink-60); margin-top: 2px; }
.ok-line { display: block; font-size: 14px; font-weight: 600; color: var(--done); margin-top: 6px; }
.clash-line { display: block; font-size: 14px; font-weight: 600; color: var(--late); margin-top: 6px; }
.rowacts { display: flex; gap: 8px; margin-top: 10px; }

.detail-who { display: flex; gap: 14px; align-items: center; margin: 10px 0 18px; }
.factlist { width: 100%; border-collapse: collapse; }
.factlist th {
  text-align: left; padding: 8px 0; width: 40%;
  font: 600 11px var(--font-mono); letter-spacing: .14em;
  text-transform: uppercase; color: var(--ink-60);
  border-bottom: 1px solid var(--line-soft); vertical-align: middle;
}
.factlist td {
  padding: 8px 0; font-size: 16px; font-weight: 600;
  border-bottom: 1px solid var(--line-soft);
}

.whoday { display: flex; flex-direction: column; gap: 6px; }
.whochip { display: flex; align-items: center; gap: 8px; font-size: 15px; font-weight: 600; }

.verdict {
  margin-top: 16px; padding: 12px 14px; border-radius: var(--r);
  background: var(--paper); font-size: 15px; font-weight: 600;
  border-left: 6px solid var(--line);
}
.verdict.is-gap { border-left-color: var(--done); color: var(--done); }
.verdict.is-clash { border-left-color: var(--late); color: var(--late); }

.quote {
  margin: 0; padding: 12px 14px;
  background: var(--surface-max); border: 1px solid var(--line-soft);
  border-radius: var(--r); font-size: 15px;
}

@media (max-width: 1100px) {
  .split { grid-template-columns: 1fr; }
  .split-detail { position: static; }
}

/* ------------------------------------------------------------ public flow
   Phone first: 390px wide, one hand, primary action always reachable. */
.public { max-width: 430px; margin: 0 auto; padding: 20px 16px 64px; }
.public-head { margin-bottom: 18px; }
.crumbs { font: 600 14px var(--font-body); color: var(--ink-60); }
.crumbs a { color: var(--accent-ink); }

/* Five steps, drawn rather than counted in words. */
.progress { display: flex; gap: 4px; margin-bottom: 18px; }
.progress i { flex: 1; height: 4px; border-radius: 2px; background: var(--line); }
.progress i.is-done { background: var(--brand, var(--accent)); }

.entryhead { text-align: left; }
.entryhead h1 { margin-top: 14px; font-size: 30px; }
.pills { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px; }
.pill {
  display: inline-block; padding: 5px 11px; border-radius: 13px;
  font: 600 13px var(--font-body); background: var(--paper); color: var(--ink-70);
}
.pill.ok { background: #DCE8DE; color: var(--done); }
.pill.brand { background: var(--accent-08); color: var(--brand, var(--accent-ink)); }
.pill.wait { background: var(--accent-08); color: var(--accent-ink); }
.pill.no { background: #F0DCD6; color: var(--danger); }

/* The three ways in. Equal weight by default; only the commonest is filled. */
.wayin {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  min-height: 68px; padding: 14px 16px; margin-bottom: 8px;
  background: var(--surface-max); border: 1px solid var(--line-soft);
  border-radius: var(--r); text-decoration: none; color: var(--ink);
}
.wayin.is-primary { background: var(--brand, var(--accent)); border-color: transparent; color: #FBF7F1; }
.wayin.is-primary .sub { color: rgba(251,247,241,.82); }
.wayin .big { display: block; font-size: 18px; font-weight: 600; }
.wayin .sub { display: block; font-size: 14px; font-weight: 500; color: var(--ink-60); margin-top: 2px; }
.wayin .chev { font-size: 22px; opacity: .6; }
.entryfoot { display: flex; gap: 10px; margin-top: 16px; }
.entryfoot .btn { flex: 1; }

.choice {
  width: 100%; min-height: 60px;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  background: var(--surface-max); border: 1px solid var(--line-soft);
  border-radius: var(--r); padding: 12px 14px; margin-bottom: 8px;
  text-align: left; text-decoration: none; color: var(--ink);
  font-family: inherit; cursor: pointer;
}
.choice .big { display: block; font-size: 18px; font-weight: 600; }
.choice .sub { font: 600 14px var(--font-mono); color: var(--ink-60); }
.choice .price { font: 600 16px var(--font-mono); color: var(--ink-70); }
.choice-person { min-height: 68px; justify-content: flex-start; gap: 12px; }
.choice-person.is-full { opacity: .6; }
/* "Svejedno tko" is often the commonest choice in a barbershop, so it is drawn
   as an equal option, not as a fallback tucked underneath. */
.choice-anyone { background: var(--accent-08); border: 2px solid var(--brand, var(--accent)); }
.choice-anyone .big, .choice-anyone .sub { color: var(--accent-ink); }

/* A week at a glance, above the times. */
.daystrip {
  display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
  gap: 6px; margin-bottom: 18px; overflow-x: auto;
}
.dayc {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  min-height: 62px; padding: 6px 4px;
  background: var(--surface-max); border: 1px solid var(--line-soft);
  border-radius: var(--r); text-decoration: none; color: var(--ink);
}
.dayc .wd { font: 600 11px var(--font-mono); color: var(--ink-60); text-transform: lowercase; }
.dayc .dd { font: 700 17px var(--font-body); }
.dayc .ct { font: 600 10px var(--font-mono); color: var(--ink-60); margin-top: 1px; }
.dayc.is-on { background: var(--ink); border-color: var(--ink); color: var(--surface); }
.dayc.is-on .wd, .dayc.is-on .ct { color: var(--line); }
.dayc.is-shut { background: var(--paper); color: var(--disabled-ink); }
.dayc.is-shut .dd { color: var(--disabled-ink); }

.slothead { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 8px; }
.slots { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-bottom: 18px; }
.slot {
  position: relative; height: 52px;
  background: var(--surface-max); border: 1px solid var(--line-soft);
  border-radius: var(--r); text-decoration: none; color: var(--ink);
  display: inline-flex; align-items: center; justify-content: center;
}
.slot .hh { font: 600 16px var(--font-mono); }
/* Who the time would be with, so "svejedno tko" is not a blind pick. */
.slot .wi {
  position: absolute; right: 5px; bottom: 4px;
  width: 17px; height: 17px; border-radius: 50%;
  background: var(--paper); color: var(--ink-60);
  font: 700 10px var(--font-body);
  display: inline-flex; align-items: center; justify-content: center;
}
.slot:hover { border-color: var(--brand, var(--accent)); }

.ticket-mark {
  width: 56px; height: 56px; border-radius: 50%;
  background: var(--done); color: var(--surface);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 26px; margin-bottom: 12px;
}
.ticket-mark.cancelled { background: var(--ink-60); }
.notice {
  background: var(--paper); border-left: 6px solid var(--late);
  border-radius: var(--r); padding: 14px; margin-bottom: 12px;
}
.notice strong { color: var(--late); display: block; margin-bottom: 4px; }
.powered {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  margin-top: 32px; font-size: 14px; color: var(--ink-60);
}

/* ------------------------------------------------------------- undo bar */
.undobar {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  padding: 10px 24px;
  background: var(--ink);
  color: var(--surface);
  font-weight: 600;
}
.undobar .muted { color: var(--line); }

@media (max-width: 640px) {
  .sitelogo-ime { display: none; }
}

/* --------------------------------------------------------------- tables */
.grid-table { width: 100%; border-collapse: collapse; background: var(--surface); }
.grid-table th {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  text-align: left;
  padding: 10px 12px;
  border-bottom: 1px solid var(--line);
  color: var(--ink-60);
  white-space: nowrap;
}
.grid-table td {
  padding: 10px 12px;
  border-bottom: 1px solid var(--line-soft);
  vertical-align: middle;
}
.grid-table tr:last-child td { border-bottom: 0; }
.grid-table .num { font-family: var(--font-mono); text-align: right; }

/* The table already scrolls inside .scroller, so wrapping buys nothing and
   costs a lot: on a phone "15,00 €" was breaking after the number and client
   names were going to two lines, which made every row taller without making
   any of them readable. Wider and one line per row is the better trade when
   the box scrolls anyway. An explicit <br> still breaks, so the cells that
   deliberately carry a second line keep it. */
.grid-table th, .grid-table td { white-space: nowrap; }
.grid-table input.cell {
  width: 92px;
  height: 44px;
  padding: 0 10px;
  background: var(--surface-max);
  border: 1px solid var(--line-soft);
  border-radius: var(--r);
  font: 600 15px var(--font-mono);
  text-align: right;
}
/* A table wider than the phone scrolls inside its own box, which is right and
   which nobody discovers. On a 364px screen the services grid is 748px wide,
   so half the columns exist and are invisible with nothing saying so.

   The shadow is four backgrounds and no JavaScript: the two `local` ones
   scroll away with the content, the two fixed ones sit under them, so a
   shadow shows on whichever side still has something beyond the edge and
   disappears when there is nothing left to reach. */
.scroller {
  overflow-x: auto;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-lg);
  background:
    linear-gradient(to right, var(--surface) 30%, transparent) left center / 28px 100% no-repeat local,
    linear-gradient(to left,  var(--surface) 30%, transparent) right center / 28px 100% no-repeat local,
    radial-gradient(farthest-side at 0    50%, rgba(36,29,26,.13), transparent) left  center / 12px 100% no-repeat scroll,
    radial-gradient(farthest-side at 100% 50%, rgba(36,29,26,.13), transparent) right center / 12px 100% no-repeat scroll;
  background-color: var(--surface);
}

/* -------------------------------------------------------------- panels */
.panel { margin-bottom: 32px; }
.panel > h2 { margin-bottom: 4px; }
.panel > .lede { color: var(--ink-70); margin: 0 0 16px; max-width: 70ch; }
.row-form {
  display: flex;
  gap: 8px;
  align-items: flex-end;
  flex-wrap: wrap;
  padding: 16px;
  background: var(--surface);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-lg);
  margin-top: 12px;
}
/* Each control is a column: its caption above it, not beside it. `display:
   block` left the caption inline, so on a narrow card "IME" sat against the
   left edge of its own input and the row read as a pile rather than a set of
   fields. */
.row-form label { display: flex; flex-direction: column; gap: 5px; }
.row-form label > .label { display: block; margin: 0; }

/* Na telefonu polje dobiva barem pola retka. Natpisi su širi od svojih uskih
   polja, pa su se dva susjedna spajala u jedan red: "RAD PRIJE PAUZE PAUZA,
   MIN" je vlasnik pročitao kao jedan natpis i nije znao čemu služi. Uz to
   zadnje polje i gumb više ne završavaju stisnuti uz donji rub. */
@media (max-width: 640px) {
  .row-form label { flex: 1 1 46%; min-width: 140px; }
  .row-form label .input,
  .row-form label .input.narrow { width: 100%; }
  .row-form .btn { flex: 1 1 100%; justify-content: center; }
}
/* `max-width: 100%` jer se `<select>` mjeri po najduljoj stavci, a stavka
   „Salon · 69 EUR · 1000 poruka" je šira od telefona s uvećanim prikazom: u
   konzoli je odabir paketa izlazio 16 piksela van ekrana od 320 piksela. */
.row-form .input, .row-form .select { width: auto; min-width: 160px; max-width: 100%; }
.row-form label { min-width: 0; }
.row-form .narrow { min-width: 90px; width: 110px; }
/* The avatar is a marker for the row, not a field, so it lines up with the
   inputs rather than with the captions above them. */
.row-form > .avatar { align-self: flex-end; margin-bottom: 4px; }
.checkline { display: flex; align-items: center; gap: 8px; min-height: 44px; font-weight: 600; }
.checkline input { width: 22px; height: 22px; }
.chips { display: flex; flex-wrap: wrap; gap: 8px; }
.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 44px;
  padding: 0 12px;
  background: var(--surface-max);
  border: 1px solid var(--line-soft);
  border-radius: var(--r);
  font-size: 14px;
  font-weight: 600;
}
.chip input { width: 20px; height: 20px; }

/* ------------------------------------------------------- absence flow */
.step { font-family: var(--font-mono); font-size: 11px; font-weight: 600; letter-spacing: .14em; text-transform: uppercase; color: var(--accent-ink); }
.affected { padding: 16px; margin-bottom: 12px; }
.affected.orphan { border-left: 6px solid var(--danger); }
.affected .when { font: 600 15px var(--font-mono); color: var(--ink-60); }
.affected .who { font-size: 18px; font-weight: 600; margin-top: 2px; }
.warnbox {
  background: var(--paper);
  border-left: 6px solid var(--late);
  border-radius: var(--r);
  padding: 14px;
  margin-bottom: 16px;
  font-weight: 600;
}
.warnbox.hard { border-left-color: var(--danger); color: var(--danger); }
.costbox {
  background: var(--accent-08);
  border: 2px solid var(--accent);
  border-radius: var(--r-lg);
  padding: 16px;
  margin-bottom: 16px;
}
.costbox .big { font-family: var(--font-head); font-size: 28px; font-weight: 700; }

/* ------------------------------------------------------------- loyalty */
.stampcard { display: flex; flex-wrap: wrap; gap: 8px; margin: 12px 0; }
.stamp {
  width: 44px; height: 44px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  border: 2px solid var(--line);
  color: var(--ink-60);
  font: 600 14px var(--font-mono);
}
.stamp.filled { background: var(--accent); border-color: var(--accent); color: var(--surface); }

/* ------------------------------------------------------------ staff app
   A barber is not managing a salon, they are working a shift. Their own face
   and their own hours come first, and the day is one screen. */
.staffbar {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 14px; background: var(--ink); color: var(--surface);
  position: sticky; top: 0; z-index: 40;
}
.staffbar .whoblock { min-width: 0; }
.staffbar .nm { display: block; font: 700 16px var(--font-body); }
.staffbar .sub { display: block; font: 600 12px var(--font-mono); color: var(--line); }
/* 520px is a phone column, and the 88px at the bottom is room for the bar
   under the thumb. Neither is right on a desktop, where the bar is in the
   header instead: the space was reserved for something that does not render
   and the column stayed as narrow as a phone on a 27-inch screen. */
/* `width: 100%` nije ukras nego uvjet.

   Otkad djelatnikova ljuska ima izbornik lijevo (22.08.2026), ovo je član flex
   stupca, a ne blok. Član flexa s `margin: 0 auto` u poprečnoj osi **ne**
   rasteže se na širinu spremnika - automatska margina to isključi - nego se
   sam sebi izmjeri po sadržaju. Zaslon Smjena tako je bio 424 piksela na
   ekranu od 402: dva polja za vrijeme drže 358, i to je odlučivalo o širini
   cijele stranice umjesto da se polja stisnu.

   Sa `width: 100%` poprečna veličina je određena, `max-width` je i dalje kapa,
   a `margin: 0 auto` i dalje centrira na širokom zaslonu. Mjereno na 402
   piksela: 424 -> 402, polje za vrijeme 175 -> 164. */
.staff { width: 100%; max-width: 760px; margin: 0 auto; padding: 16px 16px 32px; }
@media (max-width: 767px) {
  .staff { max-width: 520px; padding-bottom: 88px; }
}

.daycard {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 16px;
  background: var(--surface); border: 1px solid var(--line-soft);
  border-radius: var(--r-lg); padding: 16px; margin-bottom: 16px;
}
.daycard .display { font-size: 34px; }
.daycard-right { text-align: right; }
.daycard-right .big { font: 700 17px var(--font-body); }

.agenda-row { display: flex; gap: 12px; padding: 6px 12px; align-items: flex-start;
  color: inherit; text-decoration: none; }
.agenda-row:hover .agenda-body { filter: brightness(0.97); }
.agenda-time {
  font: 600 15px var(--font-mono); color: var(--ink-60);
  width: 52px; flex: none; padding-top: 10px;
}
.agenda-body { flex: 1; border-radius: var(--r); padding: 10px 12px; }
.agenda-body .n { font-size: 17px; font-weight: 600; }
.agenda-body .s { font-size: 13px; font-weight: 600; margin-top: 1px; opacity: .85; }
.agenda-body.s-booked { background: var(--ink); color: var(--surface); }
.agenda-body.s-completed { background: var(--done); color: var(--surface); }
.agenda-body.s-unconfirmed { background: var(--accent-08); border: 2px dashed var(--accent); }
.agenda-body.s-cancelled_in_time { background: var(--paper); color: var(--ink-60); border-left: 6px solid var(--ink-60); }
.agenda-body.s-cancelled_late { background: var(--paper); border-left: 6px solid var(--late); }
.agenda-body.s-no_show { background: var(--paper); color: var(--danger); border-left: 6px solid var(--danger); }

/* ------------------------------------------------------- salon website
   The salon supplies one accent and a logo. Everything else stays neutral,
   which is what lets a barbershop in rust and a hair salon in plum read as
   the same product. `--brand` is set per page from the tenant's colour. */
.site { max-width: 940px; margin: 0 auto; padding: 0 20px 64px; }

/* Traka koja kaže da stranica nije objavljena. Vidi je samo vlasnik.

   Namjerno nije u boji salona nego u neutralnoj tamnoj: ovo je poruka o stanju
   računa, ne dio stranice koju salon gradi, i mora se vidjeti da ne pripada
   dizajnu ispod nje. Isti razlog zbog kojeg je traka o tuđem računu crvena. */
.nijeobjavljeno { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px;
  background: var(--ink); color: var(--surface-max); padding: 10px 20px;
  font-size: 14px; line-height: 1.45; }
.nijeobjavljeno b { font-weight: 700; }
.nijeobjavljeno a { margin-left: auto; color: inherit; font-weight: 600;
  border: 1px solid currentColor; border-radius: var(--r-sm); padding: 4px 12px;
  text-decoration: none; white-space: nowrap; }
.nijeobjavljeno a:hover { background: var(--surface-max); color: var(--ink); }

.sitebar { background: var(--surface); border-bottom: 1px solid var(--line-soft); }
.sitebar-inner { display: flex; align-items: center; gap: 18px; padding: 14px 20px; flex-wrap: wrap; }
.sitelogo { display: flex; align-items: center; gap: 12px; text-decoration: none; color: var(--ink); }
.sitelogo span {
  font-family: var(--font-head); font-size: 20px; font-weight: 700;
  letter-spacing: -.01em; text-transform: uppercase;
}
.sitenav { display: flex; gap: 22px; }
.sitenav a {
  font: 700 14px var(--font-body); color: var(--ink-70);
  text-decoration: none; letter-spacing: .04em; text-transform: uppercase;
  min-height: 44px; display: inline-flex; align-items: center;
}

/* The salon's own colour, used for exactly one thing: the action. */
.btn-brand { background: var(--brand, var(--accent)); color: #FBF7F1; }
.btn-brand:hover { filter: brightness(.92); }

.site-hero { padding: 56px 0 40px; }
.site-hero h1 {
  font-size: 52px; font-weight: 800; letter-spacing: -.03em; line-height: 1.05;
  max-width: 14ch;
}
.site-hero.is-centred { text-align: center; }
.site-hero.is-centred h1 { max-width: 20ch; margin: 0 auto; }
.herorow { display: flex; align-items: center; gap: 18px; margin-top: 28px; flex-wrap: wrap; }
.herorow.is-centred { justify-content: center; }

.sectiontitle {
  font-family: var(--font-body); font-size: 13px; font-weight: 700;
  letter-spacing: .16em; text-transform: uppercase; color: var(--ink-60);
  margin-bottom: 16px;
}
.twocol {
  display: grid; grid-template-columns: 1.4fr 1fr; gap: 40px;
  padding: 32px 0; border-top: 1px solid var(--line-soft);
}

/* Dotted leaders: a price list is read across, and the rule is what makes
   that possible without turning it into a table nobody scans. */
/* Cjenik po lokaciji, bez JavaScripta.

   Skriveni `radio` prije panela, pa `:checked ~` odlučuje koji se vidi. Radiji
   ostaju u toku fokusa (pomaknuti su izvan pogleda, ne `display:none`), pa se
   kartice mijenjaju strelicama kao i svaki drugi izbor. Sve cijene su u HTML-u
   i onda kad se ne vide, što je i namjera: tražilica i čitač zaslona dobiju
   cijeli cjenik. */
.pricetabs { position: relative; }
.pricetabs > input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.pricetabs-row { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 14px; }
.pricetabs-row label {
  padding: 7px 14px; cursor: pointer; border-radius: var(--r-sm);
  border: 1px solid var(--line); background: var(--surface-max);
  font: 600 14px var(--font-body); color: var(--ink-70);
}
.pricetabs-row label:hover { border-color: var(--ink); color: var(--ink); }
.pricetabs > .pricelist { display: none; }

/* Do tri lokacije doslovno, jer CSS ne zna brojati. Salon s više od tri vidi
   prvu karticu i sve ostale ispod nje, što je nezgrapno ali istinito - a ne
   praznu stranicu, koja bi bila tiha greška. */
.pricetabs > input:nth-of-type(1):checked ~ .pricelist:nth-of-type(1),
.pricetabs > input:nth-of-type(2):checked ~ .pricelist:nth-of-type(2),
.pricetabs > input:nth-of-type(3):checked ~ .pricelist:nth-of-type(3) { display: block; }
.pricetabs > input:nth-of-type(1):checked ~ .pricetabs-row label:nth-child(1),
.pricetabs > input:nth-of-type(2):checked ~ .pricetabs-row label:nth-child(2),
.pricetabs > input:nth-of-type(3):checked ~ .pricetabs-row label:nth-child(3) {
  background: var(--ink); border-color: var(--ink); color: var(--surface-max);
}
.pricetabs > input:focus-visible ~ .pricetabs-row label { outline: 2px solid var(--accent); outline-offset: 1px; }

.pricelist { list-style: none; margin: 0; padding: 0; }
.pricelist li {
  display: flex; align-items: baseline; gap: 10px;
  padding: 11px 0; border-bottom: 1px solid var(--line-soft);
}
/* Not nowrap. "Kognitivno-motorički trening" is a real service name from a
   real tenant, and with the name unable to wrap the row simply grew past the
   viewport and took the duration and the price out with it: the whole page
   scrolled sideways on a phone. The dotted-leader design assumed short names
   because the first three tenants were barbershops. */
.pricelist .nm { font-size: 17px; font-weight: 600; min-width: 0; overflow-wrap: anywhere; }
.pricelist .lead {
  flex: 1; height: 1px; min-width: 24px;
  background-image: radial-gradient(circle, var(--line) 1px, transparent 1px);
  background-size: 5px 1px; background-repeat: repeat-x;
  align-self: flex-end; margin-bottom: 5px;
}
.pricelist .dur { font: 600 13px var(--font-mono); color: var(--ink-60); white-space: nowrap; }
.pricelist .amt { font: 600 17px var(--font-mono); white-space: nowrap; min-width: 74px; text-align: right; }

/* On a phone the row becomes two: the name on its own line, the duration and
   the price under it on the right. The leader is dropped rather than stretched
   across a wrapped line, where it stops reading as a leader and starts reading
   as a mistake. */
@media (max-width: 560px) {
  .pricelist li { flex-wrap: wrap; row-gap: 2px; }
  .pricelist .nm { flex: 1 1 100%; }
  .pricelist .lead { display: none; }
  .pricelist .dur { margin-left: auto; }
}

.hours { margin-bottom: 16px; }
.hrow {
  display: flex; justify-content: space-between; gap: 16px;
  padding: 7px 0; border-bottom: 1px solid var(--line-soft);
  font-size: 15px;
}
.addrcard {
  background: var(--ink); color: var(--surface);
  border-radius: var(--r); padding: 14px 16px; font-size: 15px;
}
.addrcard a { color: var(--surface); }

.site-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 16px; }
.site-card { background: var(--surface); border: 1px solid var(--line-soft); border-radius: var(--r-lg); padding: 20px;
  /* Stupac, pa se ono što je zadnje može gurnuti na dno. Kartice u istom redu
     nisu jednako pune - lokacija s dvoje ljudi ima kraći popis od one s
     četvero - pa je bez ovoga gumb "Naruči se" svugdje na drugoj visini, a red
     gumba koji se ne poklapaju izgleda kao greška u iscrtavanju. */
  display: flex; flex-direction: column; }
/* `auto` gura na dno, `padding` drži razmak iznad. Prvi pokušaj je imao oboje
   na gumbu, `margin-top: auto` pa `margin-block-start: 14px` - a to je isto
   svojstvo napisano dvaput, pa je fiksna brojka pobijedila i gumb se nije
   pomicao nikamo. Razdvojeno na dva elementa, ne mogu se više svađati. */
.site-card > .cardfoot { margin-top: auto; padding-top: 14px; }
.facerow { display: flex; align-items: center; gap: -6px; margin-top: 12px; flex-wrap: wrap; }
.facerow > svg, .facerow > img { margin-right: -8px; box-shadow: 0 0 0 2px var(--surface); }
.facerow .small { margin-left: 16px; }

.site-foot {
  margin-top: 56px; padding-top: 18px; border-top: 1px solid var(--line-soft);
  color: var(--ink-60); font-size: 14px;
}
.powered { display: flex; align-items: center; gap: 8px; margin-top: 10px; }

/* A salon page is a column: bar, page, booking strip, credit. The column is at
   least as tall as the window and .page takes the slack, so on a one-chair
   salon with three services the credit is at the bottom of the screen rather
   than halfway up it with nothing underneath. */
body.site-page { display: flex; flex-direction: column; min-height: 100vh; min-height: 100dvh; }

.sitecredit {
  display: flex; align-items: center; justify-content: center; gap: 7px;
  padding: 16px 20px 20px; font-size: 13px; color: var(--ink-60);
  text-decoration: none;
}
/* The credit sits at the very foot of a salon's page, which on a phone is the
   last thing above the home indicator, so it takes the inset too. */
.sitecredit { padding-bottom: max(20px, env(safe-area-inset-bottom)); }
.sitecredit:hover { color: var(--ink); }
.sitecredit:hover svg { opacity: 1; }
.sitecredit svg { opacity: .85; }

/* The salon's own privacy notice. Long prose, and the only page on a salon
   site that is read rather than scanned, so it gets a measure and generous
   leading instead of the card grid everything else uses. */
.sitedoc { max-width: 640px; margin: 0 auto; padding: 40px 0 8px; }
.sitedoc h1 { font-size: 30px; line-height: 1.12; margin: 0 0 12px; }
.sitedoc .lede { font-size: 17px; line-height: 1.55; color: var(--ink-70); margin: 0 0 8px; }
/* Zvao se `.stamp` i time nasljeđivao žig s kartice vjernosti: krug 44x44 s
   obrubom od dva piksela, koji je oko datuma crtao kružić. Ovdje se ne
   poništava tuđe pravilo nego se ne posuđuje tuđe ime. */
.sitedoc .doc-updated {
  font-size: 12px; color: var(--ink-60); margin: 0 0 6px;
  padding-bottom: 22px; border-bottom: 1px solid var(--line-soft);
}
.sitedoc section { padding-top: 26px; }
.sitedoc h2 { font-size: 19px; margin: 0 0 8px; }
.sitedoc p { font-size: 15.5px; line-height: 1.62; color: var(--ink-70); margin: 0 0 11px; }

@media (max-width: 720px) {
  .site-hero { padding: 36px 0 28px; }
  .site-hero h1 { font-size: 34px; max-width: none; }
  .twocol { grid-template-columns: 1fr; gap: 28px; }
  .sitenav { display: none; }
}

/* A placeholder in the price grid means "no override, base price applies".
   It has to read as absent rather than as a value somebody typed. */
.grid-table input.cell::placeholder { color: var(--disabled-ink); font-weight: 500; }
.grid-table input.cell:not(:placeholder-shown) { border-color: var(--accent); font-weight: 600; }

/* ------------------------------------------------- salon page, continued */
.sitecta { flex: none; }

/* On a phone the nav collapses to a menu; the booking button never does. */
.sitemenu { display: none; position: relative; }
.sitemenu summary {
  list-style: none; cursor: pointer;
  width: 44px; height: 44px; border-radius: var(--r);
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--line-soft); background: var(--surface-max); color: var(--ink);
}
.sitemenu summary::-webkit-details-marker { display: none; }
.sitemenu-panel {
  position: absolute; right: 0; top: 50px; z-index: 30; min-width: 180px;
  background: var(--surface-max); border: 1px solid var(--line-soft);
  border-radius: var(--r-lg); box-shadow: 0 10px 26px rgba(0,0,0,.18);
  padding: 6px;
}
.sitemenu-panel a {
  display: block; padding: 12px 14px; min-height: 44px;
  text-decoration: none; color: var(--ink); font-weight: 600;
  border-radius: var(--r);
}
.sitemenu-panel a:hover { background: var(--paper); }

/* Three plain facts under the hero. */
.reasons {
  display: grid; grid-template-columns: repeat(3, 1fr);
  border-top: 1px solid var(--line-soft); border-bottom: 1px solid var(--line-soft);
}
.reasons > div { padding: 22px 24px 22px 0; }
.reasons > div + div { padding-left: 24px; border-left: 1px solid var(--line-soft); }
.reasons svg { color: var(--brand, var(--accent)); margin-bottom: 8px; }
.reasons .rn { font-size: 16px; font-weight: 700; }
.reasons .rs { font-size: 14px; color: var(--ink-60); margin-top: 3px; }

/* The bar that carries actual times. */
.bookbar { background: var(--brand, var(--accent)); color: #FBF7F1; }
.bookbar-inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: 20px; padding: 18px 20px; flex-wrap: wrap;
}
.bookbar strong { display: block; font-family: var(--font-head); font-size: 21px; font-weight: 700; }
.bookbar span { font-size: 14px; opacity: .85; }
.bookbar .btn-brand { background: var(--surface-max); color: var(--ink); }
.bookbar .btn-brand:hover { background: var(--surface); filter: none; }

@media (max-width: 720px) {
  .sitenav { display: none; }
  .sitemenu { display: block; }
  /* The sticky bar at the foot already carries "Naruči se" and it follows the
     reader down the page. A second one in the header only costs a row. */
  .sitecta { display: none; }
  .sitebar-inner { padding: 12px 16px; gap: 12px; flex-wrap: nowrap; }
  .sitelogo span { font-size: 16px; }
  .reasons { grid-template-columns: 1fr; }
  .reasons > div { padding: 18px 0; }
  .reasons > div + div { padding-left: 0; border-left: 0; border-top: 1px solid var(--line-soft); }
  /* Pinned, as the design says: "Naruči se" zalijepljen na dno zaslona.
     Same reasoning as the manager's tab bar: the colour runs to the edge and
     the button keeps its distance from the home indicator. */
  .bookbar { position: sticky; bottom: 0; z-index: 30; }
  .bookbar-inner { padding-bottom: max(12px, env(safe-area-inset-bottom)); }
  .bookbar-inner { padding: 12px 16px; gap: 12px; }
  .bookbar strong { font-size: 17px; }
  .bookbar .btn { flex: none; }
}

/* The four states, named beside the day heading. Colour is never the only
   signal, and the legend is where the words live so the blocks need not carry
   them all. */
.legend { display: flex; gap: 8px; flex-wrap: wrap; }
.lg {
  padding: 5px 11px; border-radius: var(--r);
  font: 600 13px var(--font-body);
}
.lg.s-booked { background: var(--ink); color: var(--surface); }
.lg.s-completed { background: var(--done); color: var(--surface); }
.lg.s-unconfirmed { background: var(--accent-08); color: var(--accent-ink); border: 1px dashed var(--accent); }
.lg.s-cancelled_late { background: var(--paper); color: var(--ink-60); border-left: 5px solid var(--late); }

/* ------------------------------------------------------------- izvještaji */
.kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 14px; }
.kpi {
  background: var(--surface); border: 1px solid var(--line-soft);
  border-radius: var(--r-lg); padding: 18px 20px;
}
.kpi b { display: block; font-family: var(--font-head); font-size: 34px; font-weight: 800; letter-spacing: -.03em; }
.kpi span { display: block; font-size: 14px; color: var(--ink-60); margin-top: 2px; }
.kpi.is-warn b { color: var(--late); }

.repcols { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 16px; margin-top: 20px; }
.repline { display: grid; grid-template-columns: 1fr 90px 88px; gap: 10px; align-items: center; padding: 7px 0; }
.repname { display: flex; align-items: center; gap: 8px; min-width: 0; font-size: 15px; font-weight: 600; }
.repname span:first-of-type { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.repbar { height: 8px; background: var(--line); border-radius: 4px; overflow: hidden; }
.repbar i { display: block; height: 100%; background: var(--ink); }
.repamt { text-align: right; font-size: 14px; }

/* --------------------------------------------------- salon photographs
   The place is what the page is selling, so the picture is not decoration and
   never a stock library - Faza C is explicit that these are the salon's own. */
.site-hero.has-art { display: grid; grid-template-columns: 1fr 0.85fr; gap: 44px; align-items: center; }
.site-hero.has-art h1 { max-width: none; }
.heroart { border-radius: var(--r-xxl); overflow: hidden; background: var(--line); aspect-ratio: 3 / 2; }
.heroart img { width: 100%; height: 100%; object-fit: cover; display: block; }
.heroart.is-wide { aspect-ratio: 21 / 9; margin-bottom: 8px; }

.gallery { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 12px; }
.gallery figure { margin: 0; border-radius: var(--r-lg); overflow: hidden; background: var(--line); position: relative; }
.gallery img { width: 100%; height: 220px; object-fit: cover; display: block; }
.gallery figcaption {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 18px 12px 8px; font-size: 13px; font-weight: 600; color: #FBF7F1;
  background: linear-gradient(to top, rgba(36,29,26,.72), transparent);
}

@media (max-width: 720px) {
  .site-hero.has-art { grid-template-columns: 1fr; gap: 24px; }
  .heroart.is-wide { aspect-ratio: 3 / 2; }
  .gallery img { height: 180px; }
}

/* ── Tjedan i mjesec ────────────────────────────────────────────────────────
   The same day read from further away. Neither view tries to be the day grid:
   at seven columns a pixel-accurate block is unreadable and at thirty-one
   cells there is no room for one, so both trade position for a count and a
   bar. The bar is capacity used, never money. */

.spanhead { display:flex; align-items:flex-end; justify-content:space-between;
  gap:24px; flex-wrap:wrap; margin-bottom:18px; }
.spanhead h1 { font-family:Archivo,sans-serif; font-size:26px; font-weight:800;
  letter-spacing:-.01em; margin:0 0 2px; }
.spanstats { display:flex; gap:26px; }
.spanstats div { display:flex; flex-direction:column; align-items:flex-end; }
.spanstats b { font-family:Archivo,sans-serif; font-size:22px; font-weight:800; line-height:1.1; }
.spanstats span { font-size:12px; color:var(--muted); text-transform:lowercase; }

.weekgrid { display:grid; grid-template-columns:repeat(7,minmax(0,1fr)); gap:10px; align-items:start; }
.weekcol { background:var(--card); border:1px solid var(--line); border-radius:14px;
  padding:10px 8px 12px; min-height:180px; }
.weekcol.is-today { border-color:var(--accent); box-shadow:0 0 0 1px var(--accent); }
.weekcol.is-closed { background:transparent; border-style:dashed; }
.weekhead { display:flex; align-items:baseline; gap:6px; text-decoration:none;
  color:inherit; padding:0 4px 8px; }
.weekhead .wd { font-size:12px; color:var(--muted); text-transform:uppercase; letter-spacing:.06em; }
.weekhead .dn { font-family:Archivo,sans-serif; font-weight:800; font-size:18px; }
.weekhead .wu { margin-left:auto; font-size:11px; font-weight:700; color:var(--muted); }
.wbar { height:4px; border-radius:2px; background:var(--line); overflow:hidden; margin:0 4px 10px; }
.wbar i { display:block; height:100%; background:var(--accent); }
.wlist { display:flex; flex-direction:column; gap:5px; }
.wchip { display:block; text-decoration:none; border-radius:9px; padding:6px 8px; line-height:1.25; }
.wchip .t { font-family:"IBM Plex Mono",monospace; font-size:11px; font-weight:600; display:block; opacity:.85; }
.wchip .s { font-size:12px; font-weight:600; display:block; }
.wchip .c { font-size:11px; display:block; opacity:.8; }
.wchip.is-off .s { text-decoration:line-through; }
.wempty { font-size:12px; color:var(--muted); text-align:center; padding:14px 0 0; margin:0; }

.monthgrid { display:grid; grid-template-columns:repeat(7,minmax(0,1fr)); gap:6px; }
.mhead { font-size:11px; color:var(--muted); text-transform:uppercase;
  letter-spacing:.06em; text-align:center; padding-bottom:4px; }
.mcell { position:relative; display:block; min-height:74px; padding:7px 8px;
  background:var(--card); border:1px solid var(--line); border-radius:11px;
  text-decoration:none; color:inherit; }
.mcell.is-other { opacity:.4; }
.mcell.is-closed { background:transparent; border-style:dashed; }
.mcell.is-today { border-color:var(--accent); box-shadow:0 0 0 1px var(--accent); }
.mn { font-family:Archivo,sans-serif; font-weight:800; font-size:15px; }
.mc { display:block; font-size:20px; font-weight:800; font-family:Archivo,sans-serif;
  line-height:1.1; margin-top:4px; }
.mfree { display:block; font-size:11px; color:var(--muted); margin-top:6px; }
.mbar { display:block; height:3px; border-radius:2px; background:var(--line);
  overflow:hidden; margin-top:6px; }
.mbar i { display:block; height:100%; background:var(--accent); }
.mabs { position:absolute; top:6px; right:8px; font-size:10px; font-weight:700; color:var(--warn,#B8621A); }
.spannote { margin-top:14px; }

.spanrows { display:flex; flex-direction:column; gap:2px; }
.spanrow { display:flex; align-items:center; gap:10px; padding:7px 4px;
  text-decoration:none; color:inherit; border-radius:8px; }
.spanrow:hover { background:var(--line); }
.sr-day { font-size:12px; width:74px; color:var(--muted); }
.sr-bar { flex:1; height:6px; border-radius:3px; background:var(--line); overflow:hidden; }
.sr-bar i { display:block; height:100%; background:var(--accent); }
.sr-n { font-size:12px; font-weight:700; width:20px; text-align:right; }

@media (max-width: 900px) {
  .weekgrid { grid-template-columns:repeat(2,minmax(0,1fr)); }
  .spanstats { gap:18px; }
  .mcell { min-height:58px; padding:5px 6px; }
  .mc { font-size:16px; }
  .mfree { display:none; }
}

/* ── Karta sustava, samo na /test ───────────────────────────────────────────
   Moderela is four products over one database, and no single screen says which
   one you are on. The four doors say it with the address, because the address
   is the part that is actually true everywhere. */

.mapgrid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px;
  margin: 0 0 22px; }
.door { display: flex; flex-direction: column; gap: 8px; padding: 20px 18px 18px;
  border: 1px solid var(--line); border-radius: 14px; background: var(--card);
  text-decoration: none; color: inherit; position: relative;
  border-top: 4px solid var(--muted); transition: transform .12s ease, box-shadow .12s ease; }
.door:hover { transform: translateY(-2px); box-shadow: 0 8px 22px rgba(36,29,26,.10); }
.door-tag { font-family: "IBM Plex Mono", monospace; font-size: 11px; font-weight: 600;
  letter-spacing: .1em; color: var(--muted); }
.door strong { font-family: Archivo, sans-serif; font-size: 17px; font-weight: 700;
  letter-spacing: -.015em; }
.door p { font-size: 13.5px; line-height: 1.5; color: var(--ink-2, #40352F); margin: 0; }
.door-who { margin-top: auto; padding-top: 10px; font-size: 12px; color: var(--muted); }

/* One colour per audience, kept in the same order everywhere they are listed:
   sell it, run it, work in it, be a client of it. */
.door-web { border-top-color: #6B6055; }
.door-adm { border-top-color: #241D1A; }
.door-emp { border-top-color: #C1502E; }
.door-biz { border-top-color: #3F6B4A; }
.door-web .door-tag { color: #6B6055; }
.door-adm .door-tag { color: #241D1A; }
.door-emp .door-tag { color: #C1502E; }
.door-biz .door-tag { color: #3F6B4A; }

@media (max-width: 1000px) { .mapgrid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px)  { .mapgrid { grid-template-columns: 1fr; } }

/* The salon's own profiles, in its own footer. Icons only: four wordmarks
   would be four brands competing with the one whose page this is. */
.socials { display: flex; gap: 14px; margin-bottom: 12px; }
.socials a {
  display: inline-flex; padding: 7px; border-radius: 8px;
  color: var(--ink-60); background: var(--surface);
  border: 1px solid var(--line-soft);
}
.socials a:hover, .socials a:focus-visible { color: var(--brand, var(--accent)); border-color: var(--brand, var(--accent)); }

/* ── touch targets ─────────────────────────────────────────────────────────
   Keyed on `pointer: coarse` rather than on width. The question is not how
   wide the screen is but whether the thing pointing at it is a fingertip, and
   a tablet in landscape is wide and still touched. 44px is Apple's figure and
   roughly the pad of a thumb; below about 30 the mis-tap rate is what makes
   people give up on a booking flow halfway.

   Inline links inside a sentence are deliberately left alone: growing them to
   44px would blow the paragraph apart, and a reader tapping a word in prose is
   aiming at the word, not at a button. */
@media (pointer: coarse) {
  .site-foot a,
  .addrcard a,
  .sitedoc > a.small,
  .socials a {
    display: inline-flex; align-items: center; min-height: 44px;
  }
  /* The location tabs on the booking page are the first thing a client taps,
     and they were 20px tall. */
  .loctab { padding: 12px 14px; min-height: 44px; display: inline-flex; align-items: center; }
}

/* Page head: title on the left, the one action on the right. The class was
   being used on two pages as if it were a flex row and was never defined
   anywhere, so on both of them the action fell underneath the title and sat
   against the left margin looking like a mistake. */
.day-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap; margin-bottom: 26px;
}
.day-head h1 { margin: 0; }

/* ── settings ──────────────────────────────────────────────────────────────
   The old screen was ten stacked panels in one 640px column inside a 1400px
   window: half the screen empty, no way to reach the ninth section except by
   scrolling past the other eight, and every section drawn at the same visual
   weight so nothing looked more important than anything else.

   Now: a sticky index on the left, cards on the right, and each card led by an
   icon and one line saying what it is for. Same forms, same field names, same
   routes - this is layout, not a rewrite of what the page does. */
.setwrap { display: grid; grid-template-columns: 210px minmax(0, 1fr); gap: 34px; align-items: start; }

.setnav { position: sticky; top: 18px; display: flex; flex-direction: column; gap: 2px; }
.setnav a {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 11px; border-radius: var(--r); font-size: 14.5px;
  color: var(--ink-70); text-decoration: none; min-height: 40px;
}
.setnav a:hover { background: var(--surface); color: var(--ink); }
.setnav a svg { color: var(--ink-60); flex: none; }
.setnav a:hover svg { color: var(--brand, var(--accent)); }
.setnav hr { border: 0; border-top: 1px solid var(--line-soft); margin: 8px 4px; }

/* Every section is a card with a head. The head carries the icon and the one
   sentence; the body carries the form. Without the split the explanation and
   the fields competed, and the explanation won by being first. */
.setcard {
  background: var(--surface); border: 1px solid var(--line-soft);
  border-radius: var(--r-lg); margin-bottom: 22px; overflow: hidden;
  scroll-margin-top: 18px;
}
.setcard > header {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 18px 20px; border-bottom: 1px solid var(--line-soft);
  background: var(--surface-max);
}
.setcard > header svg { color: var(--brand, var(--accent)); margin-top: 2px; }
.setcard > header h2 { font-size: 18px; margin: 0 0 2px; }
.setcard > header p { margin: 0; font-size: 14px; color: var(--ink-60); line-height: 1.5; max-width: 74ch; }
.setcard > .body { padding: 20px; }
.setcard > .body > :last-child { margin-bottom: 0; }

/* A row of controls that belongs to one record. Replaces the inline
   `style="border-style:dashed"` that used to mark "this one adds". */
.setcard .row-form { margin-bottom: 10px; }
.setcard .row-form.is-new { border-style: dashed; background: transparent; }

.setnote {
  display: flex; gap: 10px; align-items: flex-start;
  background: var(--surface-max); border: 1px solid var(--line-soft);
  border-radius: var(--r); padding: 13px 15px; font-size: 14px;
  color: var(--ink-70); line-height: 1.55; margin: 14px 0 0; max-width: 80ch;
}
.setnote svg { color: var(--ink-60); flex: none; margin-top: 1px; }
.setnote code { font-size: 13px; }

/* ── the setup checklist ───────────────────────────────────────────────────
   Shown until the account can actually do something. A new salon used to land
   on an empty calendar that answered 404 because it had no location, which is
   a first impression nobody recovers from. */
.setup { border: 1px solid var(--brand, var(--accent)); border-radius: var(--r-lg);
  background: var(--surface); margin-bottom: 26px; overflow: hidden; }
.setup > header { padding: 16px 20px; background: var(--brand, var(--accent)); color: var(--surface); }
.setup > header h2 { margin: 0 0 2px; font-size: 17px; color: inherit; }
.setup > header p { margin: 0; font-size: 14px; opacity: .9; }
.setup ol { list-style: none; margin: 0; padding: 6px 0; }
.setup li { display: flex; align-items: center; gap: 11px; padding: 10px 20px; font-size: 15px; }
.setup li + li { border-top: 1px solid var(--line-soft); }
.setup li svg { flex: none; }
.setup li.is-done { color: var(--ink-60); }
.setup li.is-done svg { color: var(--ok, #2E7D5B); }
.setup li.is-todo svg { color: var(--ink-40, #A79C90); }
.setup li a { margin-left: auto; font-size: 14px; white-space: nowrap; }

@media (max-width: 900px) {
  /* The index becomes a scrolling strip above the cards. Sticky and vertical
     on a phone would eat a third of the screen.

     minmax(0, 1fr) and not 1fr, and `min-width: 0` on the strip: a bare 1fr is
     minmax(auto, 1fr) and will not go below its contents, so the strip of
     twelve links refused to shrink and took the whole page sideways instead of
     scrolling inside itself, which is the one thing it was built to do. */
  .setwrap { grid-template-columns: minmax(0, 1fr); gap: 18px; }
  .setnav { position: static; flex-direction: row; overflow-x: auto; gap: 6px;
    padding-bottom: 6px; min-width: 0; }
  .setnav a { white-space: nowrap; background: var(--surface);
    border: 1px solid var(--line-soft); }
  .setnav hr { display: none; }
  .setcard > .body { padding: 16px; }
}

/* ── one employee ──────────────────────────────────────────────────────────
   The old version stacked two forms with no boundary between them, so the
   password field for app access read as one more property of the person, and
   the only way to tell whose card you were looking at was to read the value
   inside the name input. The avatar floated loose at the left with nothing to
   line up against.

   Now the card has three parts and they look like three parts: who this is,
   what they do, and whether they can log in. */
.person { border: 1px solid var(--line-soft); border-radius: var(--r-lg);
  background: var(--surface); margin-bottom: 16px; overflow: hidden; }

.person-head {
  display: flex; align-items: center; gap: 12px;
  padding: 13px 18px; background: var(--surface-max);
  border-bottom: 1px solid var(--line-soft);
}
.person-head .who { font-size: 16.5px; font-weight: 700; }
.person-head .tags { margin-left: auto; display: flex; gap: 7px; flex-wrap: wrap; }

/* Status at a glance, so a manager scanning six people sees who is off and
   who cannot log in without opening anything. */
.stag {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px; border-radius: 999px;
  font-size: 12.5px; font-weight: 600; white-space: nowrap;
  background: var(--surface); border: 1px solid var(--line-soft); color: var(--ink-60);
}
.stag.ok { color: #2E7D5B; border-color: #BFDDCD; background: #F1F8F4; }
.stag.off { color: var(--danger); border-color: #E8C4BA; background: #FCF2EF; }

/* Details on the left, what they actually do on the right. They are different
   kinds of question and were previously one undifferentiated wall. */
.person-grid {
  display: grid; grid-template-columns: minmax(240px, 300px) minmax(0, 1fr);
  gap: 26px; padding: 18px;
}
.person-grid .field { margin-bottom: 14px; }
.person-grid .field:last-of-type { margin-bottom: 10px; }
.person-what > .label { margin-bottom: 7px; }
.person-what .chips { margin-bottom: 18px; }
.person-what .chips:last-child { margin-bottom: 0; }

.person-save { padding: 0 18px 18px; }

/* Access is a different kind of thing from the rest of the card: it creates a
   login and takes a password. It gets its own strip so it cannot be mistaken
   for one more field about the person. */
.person-access {
  border-top: 1px solid var(--line-soft); background: var(--surface-max);
  padding: 15px 18px;
}
.person-access > .label { display: flex; align-items: center; gap: 7px; margin-bottom: 10px; }
.person-access > .label svg { color: var(--ink-60); }
.person-access form { display: flex; gap: 10px; align-items: flex-end; flex-wrap: wrap; margin: 0; }
.person-access label { display: flex; flex-direction: column; gap: 5px; }
.person-access .input { min-width: 190px; }
.person-access .hint { font-size: 13px; color: var(--ink-60); margin: 10px 0 0; max-width: 62ch; line-height: 1.5; }

@media (max-width: 820px) {
  /* minmax(0, 1fr) and not 1fr: a bare 1fr is minmax(auto, 1fr) and refuses to
     go below the width of its contents, so on a phone the card grew to 546px
     and took the whole page sideways with it. */
  .person-grid { grid-template-columns: minmax(0, 1fr); gap: 18px; }
  .person-access .input { min-width: 0; width: 100%; }
  .person-access label { flex: 1 1 100%; }
  .person-head { flex-wrap: wrap; }
  .person-head .tags { margin-left: 0; flex-basis: 100%; }
}

/* ── the employee list ─────────────────────────────────────────────────────
   A table because it is scanned, not read: the questions are "who is off",
   "who cannot log in" and "who has no services and is therefore invisible to
   booking", and all three are answered by running an eye down a column. */
.stafftable td { vertical-align: middle; }
.stafftable tr.is-off td { color: var(--ink-60); }
.whocell { display: flex; align-items: center; gap: 11px; text-decoration: none; color: inherit; }
.whocell > span { display: flex; flex-direction: column; gap: 1px; }
.whocell strong { font-size: 15.5px; }
.whocell:hover strong { color: var(--brand, var(--accent)); }
/* An empty cell would read as "nothing to say here". These two mean the
   opposite: the person exists and cannot be booked. */
.warncell { display: inline-flex; align-items: center; gap: 6px; color: var(--danger); font-weight: 600; }

/* ── the subscription bar ──────────────────────────────────────────────────
   Shown three days before the trial ends and then after it lapses, and never
   in between. A banner that is always there is furniture, and the day it says
   something new is the day nobody looks at it. */
.subbar {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 11px 20px; font-size: 14.5px;
  background: var(--surface-max); border-bottom: 1px solid var(--line-soft);
  color: var(--ink-70);
}
.subbar > span { flex: 1; min-width: 240px; }
.subbar.is-over { background: #FCF2EF; border-bottom-color: #E8C4BA; color: #8A3418; }
.subbar.is-over strong { color: inherit; }

/* ── the trail ─────────────────────────────────────────────────────────────
   A list and not a table, because the interesting part of a line is the
   before-and-after pair and that does not fit a column. Time on the left so
   the eye can run down it, which is how somebody looks for "last Tuesday". */
.trail { display: flex; flex-direction: column; gap: 2px; }
.trailrow {
  display: flex; gap: 16px; padding: 13px 16px;
  background: var(--surface); border: 1px solid var(--line-soft); border-radius: var(--r);
}
.trailrow.is-warn { border-color: #E8C4BA; background: #FCF2EF; }
.trailrow .when { flex: none; width: 92px; font-size: 12.5px; color: var(--ink-60); line-height: 1.45; }
.trailrow .when span { font-size: 13.5px; color: var(--ink); }
.trailrow .what { min-width: 0; flex: 1; }
.trailrow .line { display: flex; align-items: baseline; gap: 9px; flex-wrap: wrap; }
.trailrow .subj {
  font-size: 13px; padding: 2px 8px; border-radius: 999px;
  background: var(--surface-max); border: 1px solid var(--line-soft); color: var(--ink-70);
}
.trailrow .who { margin-top: 3px; }

/* before -> after, one row per field that moved. */
.diff { margin: 9px 0 0; display: flex; flex-direction: column; gap: 4px; }
.diff > div { display: flex; gap: 10px; align-items: baseline; flex-wrap: wrap; font-size: 13.5px; }
.diff dt { flex: none; min-width: 130px; color: var(--ink-60); }
.diff dd { margin: 0; display: flex; align-items: center; gap: 7px; min-width: 0; }
.diff .was { color: var(--ink-60); text-decoration: line-through; }
.diff dd svg { color: var(--ink-60); flex: none; }
.diff .now { font-weight: 600; }

@media (max-width: 640px) {
  .trailrow { flex-direction: column; gap: 6px; }
  .trailrow .when { width: auto; display: flex; gap: 6px; }
  .trailrow .when br { display: none; }
  .diff dt { min-width: 0; flex-basis: 100%; }
}

/* ------------------------------------------------------- dojam (ocjena) */
/* Five real radio buttons, laid out as rows big enough for a thumb. No
   JavaScript star widget: this form is answered on a phone by somebody who
   has thirty seconds, and every device that renders HTML renders this. */
.ratings { display: grid; gap: 8px; }
.rating {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  grid-template-areas: "radio name" "radio hint";
  align-items: center;
  column-gap: 12px;
  padding: 12px 14px;
  min-height: 56px;
  background: var(--surface-max);
  border: 1px solid var(--line-soft);
  border-radius: var(--r);
  cursor: pointer;
}
.rating input { grid-area: radio; width: 22px; height: 22px; accent-color: var(--brand, var(--accent)); }
.rating .rn { grid-area: name; font-weight: 600; }
.rating .rh { grid-area: hint; font-size: 14px; color: var(--ink-60); }
.rating:has(input:checked) {
  border-color: var(--brand, var(--accent));
  box-shadow: inset 0 0 0 1px var(--brand, var(--accent));
}
/* Keyboard users get the same outline the rest of the product uses. */
.rating:focus-within { outline: 2px solid var(--brand, var(--accent)); outline-offset: 2px; }

/* The comment box borrows the input's skin but not its fixed height. */
textarea.input {
  height: auto;
  min-height: 96px;
  padding: 12px 14px;
  line-height: 1.5;
  resize: vertical;
}

/* --------------------------------------------------------------- dojmovi */
.dojmovi { display: grid; gap: 10px; }
.dojam {
  display: grid;
  grid-template-columns: 64px minmax(0, 1fr);
  gap: 14px;
  align-items: start;
  padding: 14px 16px;
  background: var(--surface);
  border: 1px solid var(--line-soft);
  border-radius: var(--r);
}
.dojam .score {
  font-family: var(--font-head);
  font-size: 28px; font-weight: 800; letter-spacing: -.03em;
  text-align: center; line-height: 1.1;
}
.dojam .score span { display: block; font-size: 12px; font-weight: 500; color: var(--ink-60); }
.dojam.is-warn { border-color: var(--late); }
.dojam.is-warn .score { color: var(--late); }
.dojam .line { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.dojam .subj {
  font-family: var(--font-mono); font-size: 12px;
  padding: 2px 8px; border-radius: 999px;
  background: var(--paper); color: var(--ink-70);
}
.dojam .said {
  margin: 8px 0 0;
  padding-left: 12px;
  border-left: 3px solid var(--line);
  color: var(--ink-70);
  white-space: pre-wrap;
}
.grid-table td.is-warn { color: var(--late); font-weight: 700; }

/* ------------------------------------------------------------------ upute
   The documentation pages. A narrower measure than the rest of the app: this
   is the only place in the product somebody reads top to bottom rather than
   scanning, and 100 characters of Croatian prose across a desktop column is
   how a page stops being read at the second paragraph. */
.doc { max-width: 780px; }
.doc-head { padding-bottom: 22px; border-bottom: 1px solid var(--line-soft); }
.doc-who {
  font: 600 11px var(--font-mono); letter-spacing: .14em;
  text-transform: uppercase; color: var(--accent);
}
.doc-head h1 { margin: 6px 0 10px; }
.doc-lede { font-size: 18px; line-height: 1.55; color: var(--ink-70); margin: 0; max-width: 62ch; }

.doc-toc { display: flex; flex-wrap: wrap; gap: 8px; margin: 20px 0 8px; }
.doc-toc a {
  padding: 7px 12px; border-radius: 999px;
  background: var(--surface); border: 1px solid var(--line-soft);
  font-size: 14px; text-decoration: none; color: var(--ink-70);
}
.doc-toc a:hover { border-color: var(--accent); color: var(--ink); }

.doc-sec { padding-top: 34px; }
/* The heading has to clear the sticky top bar when a table-of-contents link
   lands on it, or the first line of the section sits underneath it. */
.doc-sec { scroll-margin-top: 90px; }
.doc-sec h2 { font-size: 23px; margin: 0 0 12px; }
.doc-sec p { font-size: 16.5px; line-height: 1.62; color: var(--ink-70); margin: 0 0 12px; max-width: 68ch; }

.doc-fig { margin: 22px 0 0; }
/* The diagram scrolls inside its own box. Without this a wide flowchart makes
   the whole page scroll sideways on a phone, which is the bug that has already
   been fixed twice elsewhere in this file. */
.doc-canvas {
  overflow-x: auto;
  padding: 18px;
  background: var(--paper);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-lg);
}
/* Natural size, capped at the column. Not `width: 100%`: every diagram is
   drawn at the same type size, so stretching a narrow one and shrinking a wide
   one to the same box gives one page three different sizes of label. On a
   phone the cap bites and the box scrolls sideways instead of the page. */
.doc-canvas img { display: block; width: auto; height: auto; max-width: 100%; }
.doc-fig figcaption {
  margin-top: 10px; font-size: 14px; color: var(--ink-60); max-width: 62ch;
}

@media (max-width: 767px) {
  .doc-lede { font-size: 16.5px; }
  .doc-sec { padding-top: 26px; scroll-margin-top: 20px; }
  .doc-sec h2 { font-size: 20px; }
  .doc-canvas { padding: 12px; }
}

/* ------------------------------------------------- "Više" u donjoj traci
   The fifth tab, and the only way to six manager screens on a phone. It has
   to look like the four beside it and behave like a menu, which is what the
   summary-styled-as-a-tab is doing here. */
/* Deliberately NOT `position: relative`. The panel below is absolutely
   positioned and wants the whole width of the bar; a relative tab would make
   itself the containing block and trap the panel in its own 78 pixels, which
   is exactly what it did the first time. `.bottombar` is fixed, so it is
   already the containing block, and the panel spans it. */
.moretab { flex: 1; }
/* Only what makes it a summary rather than an anchor. Everything about how it
   sits in the row comes from the `.bottomtab` rules it is listed beside, or
   the two would drift again the moment one of them was edited. */
.moretab summary { list-style: none; cursor: pointer; }
.moretab summary::-webkit-details-marker { display: none; }
.moretab[open] summary, .moretab.is-on summary { color: var(--ink); }
.moretab[open] summary .ic, .moretab.is-on summary .ic { color: var(--accent); }

/* Opens upward, because the bar it hangs off is already at the bottom of the
   screen. Full width rather than a dropdown: at this size a panel narrower
   than the screen is a panel with a dead strip beside it. */
.morepanel {
  position: absolute; bottom: 100%; left: 0; right: 0;
  background: var(--surface-max);
  border-top: 1px solid var(--line-soft);
  box-shadow: 0 -12px 30px rgba(0,0,0,.16);
  padding: 8px;
  max-height: 70vh; overflow-y: auto;
}
.morelinks { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; }
.morelinks a {
  display: flex; align-items: center; gap: 10px;
  min-height: 52px; padding: 0 12px;
  border-radius: var(--r); text-decoration: none;
  color: var(--ink); font: 600 15px var(--font-body);
  background: var(--paper);
}
.morelinks a.is-on { background: var(--accent); color: var(--surface); }
.morelinks a.is-on svg { color: var(--surface); }

/* Who you are and how to leave. Both live in the rail on a desktop, and the
   rail is not here, so without this a phone could not sign out at all. */
.moreme {
  display: flex; align-items: center; gap: 10px;
  margin-top: 8px; padding: 10px 4px 2px;
  border-top: 1px solid var(--line-soft);
}
.moreme .nm { display: block; font: 700 15px var(--font-body); }
.moreme .ro { display: block; font: 600 12px var(--font-mono); color: var(--ink-60); }
.moreme form { margin-left: auto; }

/* A past appointment nobody marked. Not an error and not a client's fault, so
   it borrows the late colour rather than the danger one: it is a nudge at the
   salon, not an accusation about the person whose card it is on. */
.pill.warn { background: #F3E3D2; color: var(--late); }

/* The banner that survives a redirect. Three copies of the same inline style
   lived on Moj dan when every form posted back to it; now that each tab is its
   own page the banner is shared, so it gets a class instead. */
.flash { padding: 14px; margin-bottom: 16px; border-left: 6px solid var(--line); }
.flash.ok { border-left-color: var(--done); }
.flash.bad { border-left-color: var(--danger); }

/* The employee's week: down the page, not across it. The manager's seven
   columns need a desktop; this application is as wide as a phone. */
.wkweek { display: flex; flex-direction: column; gap: 10px; margin-bottom: 24px; }
.wkday { background: var(--surface); border: 1px solid var(--line); border-radius: 10px;
  padding: 12px 14px; }
.wkday.is-today { border-color: var(--accent); }
.wkhead { display: flex; align-items: baseline; justify-content: space-between;
  gap: 10px; text-decoration: none; color: inherit; }
.wkd { font-weight: 700; }
.wkn { font-family: "IBM Plex Mono", monospace; font-size: 13px; color: var(--ink-60); }
.wkday .wbar { margin: 10px 0 4px; }

/* The desktop half of the employee's menu. `.bottombar` is hidden above 767px,
   which left an employee on the salon's desktop machine with no navigation at
   all: they could reach Moj dan and nothing else without typing a URL. */
.stafftabs { display: flex; gap: 4px; margin-left: 18px; }
.stafftabs a {
  padding: 7px 13px; border-radius: 999px; text-decoration: none;
  font-size: 14px; font-weight: 600; color: var(--on-dark, #C9BEB2);
}
.stafftabs a:hover { color: var(--surface); }
.stafftabs a.is-on { background: rgba(255, 255, 255, .14); color: var(--surface); }

@media (max-width: 767px) {
  /* Below here the bottom bar takes over, under the thumb where it belongs. */
  .stafftabs { display: none; }
}

/* The salon's own gallery, in Settings. Small tiles: this is for checking what
   is there and removing one, not for admiring them. */
.galgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; }
.galgrid figure { margin: 0; background: var(--surface); border: 1px solid var(--line);
  border-radius: 10px; overflow: hidden; }
.galgrid img { display: block; width: 100%; height: 110px; object-fit: cover; }
.galgrid form { padding: 8px; }

/* ----------------------------------------------------------- mrtvo vrijeme
   Pojas unutar termina u kojem je djelatnik slobodan, a klijent je i dalje u
   salonu: boja djeluje, trajna se hvata. Crta se šrafurom preko bloka, jer
   blok mora ostati jedan termin - klijentica nije otišla pa se vratila. */
.appt-pauza {
  position: absolute;
  left: 0; right: 0;
  pointer-events: none;
  border-radius: 4px;
  background: repeating-linear-gradient(
    -45deg,
    rgba(255, 255, 255, .55) 0 5px,
    rgba(255, 255, 255, 0) 5px 10px
  );
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .5),
              inset 0 -1px 0 rgba(255, 255, 255, .5);
}

/* --------------------------------------------------------------- red filtera
   Gumbi razdoblja, raspon datuma i "Prikaži" stoje u jednom retku, pa moraju
   biti iste visine. Zatečene su bile tri različite (46px za `.seg`, 56px za
   `.input`, 48px za `.btn-compact`), i red je izgledao kao tri kontrole
   slučajno stavljene jedna do druge. Poravnanje je po dnu, jer natpisi OD i DO
   stoje iznad polja. */
.filterrow { display: flex; align-items: flex-end; gap: 10px; flex-wrap: wrap; }
.filterrow .seg a,
.filterrow .input,
.filterrow .btn { height: 46px; }
.filterrow .input { width: 158px; font-size: 15px; }
.filterrow form { display: flex; align-items: flex-end; gap: 10px; margin: 0; }
.filterrow label { display: flex; flex-direction: column; gap: 4px; }
.filterrow .label { margin: 0; }

@media (max-width: 700px) {
  /* Na telefonu red pada u dva: gumbi gore, raspon ispod, i oba se rastegnu
     preko cijele širine umjesto da se stisnu u nečitke kvadratiće. Sam
     redak OD/DO/Prikaži smije dodatno puknuti u dva: otkad `.btn` (od
     03.09.2026) ne smije stisnuti natpis, Od i Do ostaju zajedno, a
     Prikaži padne ispod umjesto da gura ostatak izvan zaslona. */
  .filterrow { align-items: stretch; }
  .filterrow .seg { width: 100%; }
  .filterrow .seg a { flex: 1; justify-content: center; padding: 0 10px; }
  .filterrow form { width: 100%; flex-wrap: wrap; }
  .filterrow label { flex: 1; }
  .filterrow .input { width: 100%; }
}

/* ── traka o obavijestima ─────────────────────────────────────────────────
   Pojavljuje se samo kad obavijesti na ovom uređaju ne rade, i nestaje čim
   prorade. Namjerno je tanka i bez boje upozorenja: ovo nije kvar nego
   postavka koja se nije dogodila, a traka koja viče na svakom zaslonu se
   prestane vidjeti prije nego se posluša. */
/* Prvo ovo, pa tek onda izgled: `hidden` je atribut koji preglednik provodi
   svojim `display: none`, a naše `display: flex` je autorsko pravilo i
   pobjeđuje ga. Bez ovog retka traka stoji na svakom zaslonu, prazna, bez
   obzira što skripta kaže - i to je točno ono što se dogodilo Tomu na
   iPhoneu 22.08.2026. */
.obavtraka[hidden] { display: none; }

.obavtraka {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  background: var(--surface); border-bottom: 1px solid var(--line-soft);
  color: var(--ink); font-size: 14px; padding: 10px 16px;
}
.obavtraka-gumbi { margin-left: auto; display: flex; gap: 8px; }
@media (max-width: 560px) {
  .obavtraka { font-size: 13px; padding: 9px 12px; }
  .obavtraka-gumbi { margin-left: 0; width: 100%; }
  .obavtraka-gumbi .btn { flex: 1; }
}

/* ── zasloni prije prijave ────────────────────────────────────────────────
   Prijava, zaboravljena lozinka i postavljanje nove. Jedini zasloni koje
   čovjek vidi prije nego išta zna o proizvodu, i jedini koji stanu u ekran.

   `100dvh`, ne `100vh`: na iPhoneu `vh` računa visinu bez adresne trake i u
   pregledniku daje stranicu koja je uvijek za tu traku previsoka, pa se
   klati gore-dolje iako nema što pokazati. `dvh` je stvarna visina, koja se i
   mijenja kad se traka skloni ili kad iskoči tipkovnica.

   `overscroll-behavior: none` gasi odbijanje pri povlačenju u instaliranoj
   aplikaciji: ondje nema adresne trake, pa je to jedini pokret koji odaje da
   je ovo web a ne aplikacija. */
body.ulaz-body { overscroll-behavior: none; }

body.ulaz-body .page {
  /* `.page` inace ostavlja mjesta donjoj traci (88px na telefonu). Ovdje te
     trake nema, pa bi taj razmak samo produzio stranicu preko ekrana. */
  padding: 0;
  display: flex;
}

.ulaz {
  flex: 1;
  max-width: 420px;
  margin: 0 auto;
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: max(24px, env(safe-area-inset-top)) 16px
           max(24px, env(safe-area-inset-bottom));
}

/* Kad tipkovnica pojede pola ekrana, sadržaj se smije pomaknuti gore umjesto
   da se stisne ili nestane pod njom. */
@media (max-height: 560px) {
  .ulaz { justify-content: flex-start; }
}

/* Glava zaslona prije prijave. Bila je tri puta prepisana inline stilom i
   razišla se: centrirana na jednom, uz lijevi rub na drugom, rečenica samo na
   trećem. Sad je jedan predložak i jedno pravilo. */
.ulaz-glava {
  display: flex; align-items: center; justify-content: center;
  gap: 12px; margin-bottom: 8px;
}
.ulaz-lede { color: var(--ink-60); text-align: center; margin: 0 0 32px; }

/* Koraci unutar trake: pune širine ispod teksta i gumba, jer numerirani
   popis uz gumb u istom retku nije popis nego gužva. */
.obavtraka-koraci { flex: 1 0 100%; }
.obavtraka-koraci ol { margin: 6px 0 2px; padding-left: 22px; }
.obavtraka-koraci li { margin-bottom: 4px; }
.obavtraka-koraci[hidden] { display: none; }

/* Djelatnikova ljuska na širokom zaslonu.
   ======================================
   Do 22.08.2026. je djelatnik i na računalu salona dobivao mobilni raspored:
   donju traku (koja je iznad 767px skrivena) i ništa lijevo, dakle nikakav
   izbornik. Sad nosi isti okvir kao voditelj, s istim klasama.

   Gornja traka ostaje samo na telefonu: na širokom zaslonu ime i odjava stoje
   u izborniku, pa bi ista stvar bila dvaput. */
@media (min-width: 768px) {
  .staffbar { display: none; }
  /* Bez gornje trake sadržaj bi krenuo skroz uz vrh. */
  .staff { padding-top: 24px; }
}

/* Odziv na dodir.
   ===============
   Tomova primjedba 22.08.2026: kretanje po donjoj traci djeluje sporo, „u
   milisekundama". Poslužitelj crta zaslon za 5 do 20 ms, pa ono što se osjeća
   nije crtanje nego čekanje: između dodira i prvog piksela nove stranice
   preglednik ne pokaže ništa, jer dosad nijedna kartica nije imala stanje
   „pritisnuto".

   `touch-action: manipulation` uz to skida čekanje na dvostruki dodir koje
   preglednik inače drži prije nego što klik proslijedi stranici. */
a, button, summary, label, .bottomtab, .railtab, .bottomtab .ic {
  touch-action: manipulation;
}
.bottomtab:active, .moretab summary:active, .railtab:active {
  background: var(--surface-max);
}
.btn:active { transform: translateY(1px); }

/* Raspored smjena
   ===============
   Tjedan kao tablica: redak je čovjek, stupac je dan. Vodoravni klizač je
   namjeran i jedini na cijelom zaslonu: sedam dana ne stane na telefon, a
   raspored koji se lomi u sedam kartica prestaje biti raspored - ono što se u
   njemu čita je usporedba, tko radi kad u odnosu na ostale. */
.rasporedwrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.raspored { border-collapse: collapse; width: 100%; min-width: 720px; }
.raspored th, .raspored td {
  border: 1px solid var(--line-soft); padding: 8px; vertical-align: top;
  background: var(--surface);
}
.raspored thead th {
  background: var(--surface-max); text-align: center; vertical-align: middle;
  font: 700 12px var(--font-body); color: var(--ink-60);
  position: sticky; top: 0; z-index: 1;
}
.raspored thead th .dan { display: block; text-transform: uppercase; }
.raspored thead th .datum { display: block; font: 600 13px var(--font-mono); color: var(--ink); }
.raspored th.tko {
  text-align: left; width: 180px; white-space: nowrap;
  display: table-cell;
}
.raspored tbody th.tko { font: 600 14px var(--font-body); }
.raspored tbody th.tko .avatar { vertical-align: middle; margin-right: 8px; }
.raspored td.sati, .raspored th.sati {
  width: 56px; text-align: right; font: 600 14px var(--font-mono); color: var(--ink-60);
}
.raspored .je-danas { background: var(--surface-max); }

.raspored .smjena {
  display: block; margin-bottom: 4px; padding: 5px 7px; border-radius: 6px;
  background: var(--ink); color: var(--surface);
  font: 600 13px var(--font-mono); text-decoration: none; text-align: center;
}
.raspored .smjena:hover { background: var(--accent); }
/* Zahtjev je prijedlog, ne raspored: obris umjesto plohe, i upitnik. */
.raspored .smjena.je-zahtjev {
  background: transparent; color: var(--ink-70);
  border: 1px dashed var(--ink-40, #B9AFA4);
}
.raspored .odsutan {
  display: block; margin-bottom: 4px; padding: 5px 7px; border-radius: 6px;
  background: var(--line); color: var(--ink-70);
  font: 600 12px var(--font-body); text-align: center;
}
/* Traka iznad tablice: koraci kroz tjedne, pa gumbi. Lomi se, jer na telefonu
   „Kopiraj prošli tjedan" i strelice ne stanu u isti redak. */
.rasporedbar {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-bottom: 16px;
}
.rasporedbar form { margin: 0; }
.raspored thead th .datum, .raspored .smjena { white-space: nowrap; }

/* Plus se vidi tek kad je polje na redu, da tablica ne izgleda kao šahovnica
   plusića. Na dodir ga nema smisla skrivati, pa ga na telefonu vidiš uvijek. */
.raspored .dodaj {
  display: block; text-align: center; padding: 3px; border-radius: 6px;
  color: var(--ink-40, #B9AFA4); text-decoration: none; font-size: 18px; line-height: 1;
}
.raspored td:hover .dodaj { color: var(--accent); background: var(--surface-max); }
@media (hover: none) {
  .raspored .dodaj { color: var(--ink-60); }
}
