/* ==========================================================================
   Tarino components (v1.0 kit). Loads after tokens.css and layout.css.

   Source: the component CSS of "Tarino A refined" (mock-a-refined.html lines 84-183), without the mock chrome
   (.intro .changes .frames .phone .scr, captions, .footnote, the rise animation), extended to the full set.
   Mock values are kept literal where they were measured (7px gaps, 13px radius ...): the mock is the contract.
   Each block names its macro (templates/_macros.html) and the mock class it grew from.

   Contract: page seats use these classes through the macros. Do not restyle them in page CSS; add a modifier here.

   Tap targets are >= 44px. Where the mock's visual is smaller (chips 34px, scan button 30px, stepper 32px) the element's
   box is 44px and the visual is painted by an inner element or ::before, so the look is the mock's and the target is real.
   ========================================================================== */


/* ==========================================================================
   Icons and logo           macros: icon(), cat_icon(), logo()
   ========================================================================== */
.icon{
  flex:0 0 auto;display:inline-block;vertical-align:middle;
  fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round;
}
.icon--cat{stroke-width:1.6}
.icon-mark{flex:0 0 auto;display:block}

/* App tile: 58px, radius 15, višnja, white mark 40px (mock .m-app). */
.app-tile{
  flex:0 0 auto;width:58px;height:58px;border-radius:var(--radius-tile);
  background:var(--visnja);color:var(--on-visnja);display:grid;place-items:center;box-shadow:var(--shadow-app);
}
/* Lockup: mark 36px + Onest 800 1.55rem (mock .m-lock). */
.lockup{display:inline-flex;align-items:center;gap:8px;font-weight:var(--fw-heavy);font-size:1.55rem;letter-spacing:-.025em;color:var(--ink)}
.lockup .icon-mark{color:var(--mark)}


/* ==========================================================================
   Header, nav, language switch      macros: site_header(), lang_switch()
   mock: .bar .brand
   Phones: brand + language; the bottom tab bar carries navigation and the basket (the mock's header basket button is gone: two
   entries to one basket on a phone were one too many). From 720px: the nav, with the basket and its count, replaces the tab bar.
   ========================================================================== */
.site-header{position:relative;z-index:var(--z-header);background:var(--bg)}
.site-header__inner{display:flex;align-items:center;gap:var(--space-3);min-height:64px;padding-block:10px}
.site-header__tools{display:flex;align-items:center;gap:var(--space-1);margin-left:auto}

.brand{
  display:inline-flex;align-items:center;gap:7px;min-height:var(--tap);
  font-weight:var(--fw-heavy);font-size:1.16rem;letter-spacing:-.02em;color:var(--ink);text-decoration:none;
}
.brand .icon-mark{color:var(--mark)}

/* Desktop nav. Hidden on phones. */
.nav{display:none}
.nav__list{display:flex;align-items:center;gap:var(--space-1)}
.nav__link{
  display:inline-flex;align-items:center;gap:8px;min-height:var(--tap);padding:0 14px;
  border-radius:var(--radius-pill);color:var(--ink-2);font-weight:var(--fw-semi);font-size:.94rem;text-decoration:none;
}
.nav__link:hover{background:color-mix(in srgb,var(--visnja) 8%,transparent);color:var(--ink)}
.nav__link[aria-current="page"]{color:var(--visnja-ink);background:color-mix(in srgb,var(--visnja) 10%,transparent)}

/* Language switch: HR | EN. Current is a plain bold word, the other is a link. Each item is a 44px target. */
.lang-switch{display:flex;align-items:center}
.lang-switch__item{
  position:relative;display:inline-grid;place-items:center;min-width:var(--tap);min-height:var(--tap);
  font-size:.84rem;font-weight:var(--fw-bold);letter-spacing:.02em;color:var(--muted);text-decoration:none;
}
a.lang-switch__item:hover{color:var(--ink)}
.lang-switch__item[aria-current="true"]{
  color:var(--ink);text-decoration:underline;text-decoration-thickness:2px;text-underline-offset:.4em;
  text-decoration-color:var(--visnja-ink);
}
.lang-switch li+li .lang-switch__item::before{content:"";position:absolute;left:0;top:50%;height:16px;border-left:1px solid var(--line);transform:translateY(-50%)}

/* Icon button: 44px square. The round "+" on chain cards. */
.icon-btn{
  position:relative;display:inline-grid;place-items:center;flex:0 0 auto;
  width:var(--tap);height:var(--tap);border-radius:var(--radius-14);
  border:1px solid var(--line);background:var(--raise);color:var(--ink);text-decoration:none;cursor:pointer;
}
.icon-btn:hover{background:color-mix(in srgb,var(--visnja) 6%,var(--raise))}
.icon-btn--round{border-radius:50%}
.icon-btn--primary{background:var(--visnja);border-color:transparent;color:var(--on-visnja);box-shadow:var(--shadow-btn)}
.icon-btn--primary:hover{background:var(--visnja-deep)}

/* Count badge (mock .basket .n): min 20px, višnja, white .72rem 700. */
.count-badge{
  display:inline-grid;place-items:center;min-width:20px;height:20px;padding:0 5px;border-radius:var(--radius-pill);
  background:var(--visnja);color:var(--on-visnja);font-size:.72rem;font-weight:var(--fw-bold);line-height:1;
  font-variant-numeric:tabular-nums;
}
.count-badge--float{position:absolute;top:-6px;right:-6px}

.site-header--static{position:relative}

@media (min-width:720px){
  .site-header{position:sticky;top:0;border-bottom:1px solid var(--line)}
  .site-header--static{position:relative}
  .site-header__inner{min-height:68px;gap:var(--space-6)}
  .nav{display:block;margin-left:auto}
  .site-header__tools{margin-left:0}
}
@media (min-width:720px) and (max-width:959px){
  .nav__link{padding:0 12px}
  .nav__link .icon{display:none}   /* labels only: brand + four items + HR | EN fit a 720px tablet */
  .site-header__inner{gap:var(--space-3)}
}


/* ==========================================================================
   Bottom tab bar (phones)      macro: tab_bar()
   Početna, Akcije, Košarica (count badge), Račun. Hidden from 720px.
   ========================================================================== */
.tabbar{
  position:fixed;left:0;right:0;bottom:0;z-index:var(--z-tabbar);display:flex;
  background:var(--surface);border-top:1px solid var(--line);padding-bottom:env(safe-area-inset-bottom,0px);
}
.tabbar__item{
  flex:1 1 0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;
  min-height:var(--tabbar-h);padding:6px 4px;color:var(--muted);text-decoration:none;font-size:.72rem;font-weight:var(--fw-semi);
}
.tabbar__item[aria-current="page"]{color:var(--visnja-ink)}
.tabbar__icon{position:relative;display:grid;place-items:center}
.tabbar__icon .count-badge--float{top:-7px;right:-12px}
.tabbar--static{position:static}
@media (min-width:720px){.tabbar:not(.tabbar--static){display:none}}


/* ==========================================================================
   Footer      macro: site_footer()
   Copy from the S3 chrome: how we calculate, independence + no cookies, contact. Brand "tarino".
   ========================================================================== */
.site-footer{margin-top:var(--space-10);background:var(--surface);border-top:1px solid var(--line);color:var(--ink-2);font-size:.9rem;line-height:1.5}
.site-footer__inner{display:grid;gap:var(--space-2);padding-block:var(--space-6) var(--space-8)}
.site-footer__note{max-width:52ch}
.site-footer a:not(.brand){color:var(--visnja-ink);display:inline-flex;align-items:center;min-height:var(--tap);font-weight:var(--fw-semi)}
.site-footer p{margin:0}
/* The static preview's line back to the index of pages (the macro prints it only when preview is true): a quiet row under the three columns */
.site-footer__preview{padding-top:var(--space-2);border-top:1px dashed var(--line);font-size:.84rem}
@media (min-width:720px){.site-footer__preview{grid-column:1 / -1}}
@media (min-width:720px){
  .site-footer{margin-top:var(--space-16)}
  .site-footer__inner{grid-template-columns:minmax(0,1fr) minmax(0,2fr) auto;align-items:center;gap:var(--space-8);padding-block:var(--space-8)}
}


/* ==========================================================================
   Hero, search, scan, city chip, popular chips      macros: hero(), search_field(), loc_chip(), popular()
   mock: .hero .search .mag .scan .loc .often .chips .chip
   ========================================================================== */
.hero{background:var(--visnja);color:var(--on-visnja);padding:18px 0 22px;margin:0}
.hero__inner{
  --hero-gutter:calc(var(--gutter) + 2px);   /* the mock insets the hero text 18px, the page 16px */
  width:100%;margin-inline:auto;max-width:calc(var(--container) + 2 * var(--gutter));padding-inline:var(--hero-gutter);
}
@supports (padding:max(0px)){
  .hero__inner{padding-left:max(var(--hero-gutter),env(safe-area-inset-left,0px));padding-right:max(var(--hero-gutter),env(safe-area-inset-right,0px))}
}
.hero__title{
  font-family:var(--serif);font-weight:var(--fw-regular);font-size:1.72rem;line-height:1.08;letter-spacing:-.005em;
  margin:2px 0 16px;text-wrap:balance;
}
.hero :focus-visible{outline-color:var(--on-visnja)}
/* An eyebrow inside the title (the error code of the 404 page) and one line of help under it. */
.hero__eyebrow{display:block;margin:0 0 var(--space-1);font-family:var(--sans);font-size:.85rem;font-weight:var(--fw-bold);letter-spacing:.12em;color:var(--on-visnja-soft)}
.hero__text{margin:calc(var(--space-2) * -1) 0 var(--space-4);max-width:52ch;font-size:1rem;color:var(--on-visnja-soft);text-wrap:pretty}

/* Search field. White in both themes inside the hero (S1); .search--page is the themed version for other pages. */
.search{
  position:relative;display:flex;align-items:center;gap:10px;min-height:var(--input-h);
  background:var(--field-bg);color:var(--field-ink);border-radius:var(--radius-field);padding:12px 12px;box-shadow:var(--shadow-search);
}
/* The leading icon is the submit button: 44px box, the icon stays where the mock has it (12px from the edge, 10px to the text). */
.search__icon{display:grid;place-items:center;flex:0 0 auto;width:var(--tap);height:var(--tap);margin:-12px -13px -12px -12px;color:var(--field-icon)}
.search__icon:focus-visible{outline:none}
.search__icon:focus-visible .icon{outline:var(--focus-w) solid var(--focus);outline-offset:var(--focus-offset);border-radius:50%}
.hero .search__icon:focus-visible .icon{outline-color:var(--focus)}
/* 1rem, not the mock's .98rem: below 16px iOS Safari zooms the page when the field takes focus.
   The input box is stretched over the field's padding (negative margin) so the whole 48px field is the tap target. */
.search__input{flex:1;min-width:0;margin-block:-12px;padding:12px 0;border:0;background:transparent;color:inherit;font:inherit;font-size:1rem;line-height:1.5}
.search__input::placeholder{color:var(--field-placeholder);opacity:1}
.search__input::-webkit-search-cancel-button{-webkit-appearance:none;appearance:none}
/* Focus ring on the whole field (not on the scan button inside it). Browsers without :has keep the ring on the input. */
@supports selector(:has(*)){
  .search__input:focus-visible{outline:0}
  .search:has(.search__input:focus-visible){outline:var(--focus-w) solid var(--focus);outline-offset:var(--focus-offset)}
  .hero .search:has(.search__input:focus-visible){outline-color:var(--on-visnja)}
}

.search--page{
  --field-bg:var(--surface);--field-ink:var(--ink);--field-placeholder:var(--muted);--field-icon:var(--muted);--scan-bg:color-mix(in srgb,var(--visnja) 10%,var(--surface));
  border:1px solid var(--line-strong);box-shadow:none;
}
.search--page .scan-btn{color:var(--visnja-ink)}

/* Scan button: 44px box, the mock's 34x30 pill painted inside. Negative margins keep the field height at 48px. */
.scan-btn{position:relative;display:grid;place-items:center;flex:0 0 auto;width:var(--tap);height:var(--tap);margin:-10px -5px -10px 0;color:var(--visnja)}
.scan-btn__pill{display:grid;place-items:center;width:34px;height:30px;border-radius:var(--radius-8);background:var(--scan-bg)}
.scan-btn:focus-visible{outline:none}
.scan-btn:focus-visible .scan-btn__pill{outline:var(--focus-w) solid var(--focus);outline-offset:var(--focus-offset)}

/* City chip: 44px box, 36px glass pill (mock .loc). */
.loc-chip{
  position:relative;isolation:isolate;display:inline-flex;align-items:center;gap:6px;min-height:var(--tap);
  margin:10px 0 0;padding:0 12px;color:var(--on-visnja);font-weight:var(--fw-link);font-size:.9rem;text-decoration:none;
}
.loc-chip::before{
  content:"";position:absolute;inset:4px 0;z-index:-1;border-radius:var(--radius-pill);
  background:var(--glass);border:1px solid var(--glass-line-2);
}
.loc-chip>span{min-width:0;overflow-wrap:anywhere}   /* a long name (the stored city is shown as it is) wraps inside the chip instead of widening the page */
.loc-chip{max-width:100%}
.loc-chip:focus-visible{outline:none}
.loc-chip:focus-visible::before{outline:var(--focus-w) solid var(--on-visnja);outline-offset:var(--focus-offset)}

/* Popular searches (mock .often + .chips + .chip). */
.popular{margin:12px 0 0}
.popular__label{font-size:.85rem;color:var(--on-visnja-soft);margin:0 0 4px}
/* popular(variant='page'): the same chips on the page background (search, no results, empty basket) */
.popular.popular--page{margin:0}   /* two classes: the 720px rule that opens the hero's chips up must not reach this one */
.popular--page .popular__label{margin:0 0 var(--space-1);color:var(--muted)}
.chips{display:flex;flex-wrap:wrap;gap:0 7px}
.chip{
  position:relative;isolation:isolate;display:inline-flex;align-items:center;justify-content:center;min-width:var(--tap);min-height:var(--tap);padding:0 13px;
  color:var(--on-visnja);font-size:.86rem;font-weight:var(--fw-semi);text-decoration:none;
}
.chip::before{
  content:"";position:absolute;inset:5px 0;z-index:-1;border-radius:var(--radius-pill);
  background:var(--glass);border:1px solid var(--glass-line);
}
.chip:focus-visible{outline:none}
.chip:focus-visible::before{outline:var(--focus-w) solid var(--on-visnja);outline-offset:var(--focus-offset)}
/* The same chip on the page background (filters, suggestions). */
.chip--page{color:var(--ink-2)}
.chip--page::before{background:var(--surface);border-color:var(--line)}
.chip--page:hover::before{border-color:var(--line-strong)}
.chip--page[aria-current="true"]{color:var(--visnja-ink);font-weight:var(--fw-bold)}
.chip--page[aria-current="true"]::before{background:color-mix(in srgb,var(--visnja) 10%,var(--surface));border-color:color-mix(in srgb,var(--visnja) 40%,var(--line))}
.chip--page:focus-visible::before{outline-color:var(--focus)}

/* Chip group      macro: chip_group(label, options)
   A label and a row of page chips that are links (sort, filter by chain, by category). The label sits above the chips, so three chips
   fit one line on a 390px phone; --inline puts it to the left of them from 720px. */
.chip-group{display:grid}
.chip-group__label{margin:0;font-size:.84rem;color:var(--muted)}
@media (min-width:720px){
  .chip-group--inline{grid-template-columns:6.5rem minmax(0,1fr);align-items:center}
  .chip-group--inline .chip-group__label{font-size:.85rem;font-weight:var(--fw-semi)}
}

@media (min-width:720px){
  .hero{padding:var(--space-12) 0 var(--space-12)}
  .hero__inner{--hero-gutter:var(--gutter)}
  .hero__title{font-size:2.7rem;max-width:20ch;margin:0 0 var(--space-6)}
  .hero .search{max-width:640px}
  .hero .search__input{font-size:1.06rem}
  .popular{margin-top:var(--space-3)}
}


/* ==========================================================================
   Section heading      macro: section_head()
   mock: .sec-h h3 / a
   ========================================================================== */
.section-head{display:flex;align-items:center;justify-content:space-between;gap:var(--space-3);margin:0 0 6px;min-height:var(--tap)}
.section-head__title{font-family:var(--serif);font-weight:var(--fw-regular);font-size:1.2rem;letter-spacing:-.005em;color:var(--ink)}
.section-head__link{
  display:inline-flex;align-items:center;justify-content:flex-end;gap:2px;min-width:var(--tap);min-height:var(--tap);padding-left:var(--space-3);
  font-size:.86rem;font-weight:var(--fw-link);color:var(--visnja-ink);text-decoration:none;white-space:nowrap;
}
.section-head__link:hover{text-decoration:underline}
@media (min-width:720px){.section-head__title{font-size:1.5rem}}


/* ==========================================================================
   Page head      macro: page_head(title, lead, count, note)
   The h1 of a list page with what follows it: a lead line, a count ("20 rezultata"), the price-list date. --spaced adds the air
   under the block when the next block does not bring its own (basket, deals, lists).
   ========================================================================== */
.page-head{display:grid;gap:var(--space-1)}
.page-head .page-title{margin-bottom:var(--space-1)}
.crumbs+.page-head .page-title{margin-top:var(--space-1)}   /* the breadcrumb row is 44px tall already */
.page-head .lead,.page-head .fine{margin:0}
.page-head__count{margin:0;font-weight:var(--fw-semi);color:var(--ink-2);font-variant-numeric:tabular-nums}
.page-head--spaced{margin-bottom:var(--space-4)}
@media (min-width:720px){.page-head--spaced{margin-bottom:var(--space-6)}}


/* ==========================================================================
   Category tiles      macros: cat_grid(), cat_tile()
   mock: .cats .cat .ic .t
   ========================================================================== */
.cat-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:9px}
.cat-grid>li{display:flex}
.cat-grid>li>.cat-tile{flex:1 1 auto;min-width:0}
.cat-tile{
  display:flex;flex-direction:column;align-items:center;gap:7px;min-height:var(--tap);padding:12px 6px 10px;
  border-radius:var(--radius-tile);border:1px solid var(--line-2);background:var(--tint,var(--line-2));text-decoration:none;
}
.cat-tile:hover{border-color:color-mix(in srgb,var(--tint-i,var(--visnja)) 45%,var(--line-2))}
.cat-tile__icon{display:block;width:32px;height:32px;color:var(--tint-i,var(--visnja))}
.cat-tile__icon .icon{width:100%;height:100%;display:block}
.cat-tile__label{font-size:.78rem;font-weight:var(--fw-semi);color:var(--ink-2);text-align:center;overflow-wrap:anywhere}
@media (max-width:359px){.cat-tile{padding-inline:2px}.cat-tile__label{font-size:.72rem}}   /* "Grickalice" must not break at 320px */
@media (min-width:720px){
  .cat-grid{gap:var(--space-3)}
  .cat-tile{gap:10px;padding:18px 8px 14px}
  .cat-tile__icon{width:40px;height:40px}
  .cat-tile__label{font-size:.86rem}
}
@media (min-width:960px){.cat-grid{grid-template-columns:repeat(8,minmax(0,1fr))}}
/* Large tiles      cat_grid(size='lg'), cat_tile(size='lg'): the Categories page. 2 across on phones, 4 from 720px, icon 48 / 60px.
   The strip's 8 in a row is too small to be a page. */
.cat-grid--lg{grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--space-3)}
.cat-tile--lg{justify-content:center;gap:var(--space-3);min-height:132px;padding:var(--space-5) var(--space-3) var(--space-4)}
.cat-tile--lg .cat-tile__icon{width:48px;height:48px}
.cat-tile--lg .cat-tile__label{font-weight:var(--fw-bold);font-size:1rem;color:var(--ink)}
@media (min-width:720px){
  .cat-grid--lg{grid-template-columns:repeat(4,minmax(0,1fr));gap:var(--space-4)}
  .cat-tile--lg{min-height:176px;gap:var(--space-4);padding:var(--space-5) var(--space-3) var(--space-4)}
  .cat-tile--lg .cat-tile__icon{width:60px;height:60px}
  .cat-tile--lg .cat-tile__label{font-size:1.1rem}
}


/* ==========================================================================
   Pinned snapshot frame      macro: snap()
   mock: .snap. No product photos yet (Q7): the frame holds the category icon on its tint.
   With a photo (<img class="snap__img">) it is the white print of the mock.
   ========================================================================== */
.snap{
  --snap:86px;
  position:relative;flex:0 0 auto;display:grid;place-items:center;overflow:hidden;
  width:var(--snap);height:var(--snap);border-radius:var(--radius-photo);
  background:var(--photo-bg);border:1px solid var(--line);
  transform:rotate(-2.5deg);box-shadow:var(--shadow-snap);
}
.snap::before{
  content:"";position:absolute;top:-7px;left:50%;transform:translateX(-50%) rotate(3deg);
  width:34px;height:14px;background:var(--tape);border:1px solid var(--tape-line);border-radius:var(--radius-tape);
}
.snap--icon{background:var(--tint,var(--line-2));color:var(--tint-i,var(--visnja))}
.snap__icon{display:block;width:calc(var(--snap) * .56);height:calc(var(--snap) * .56)}
.snap__img{display:block;width:100%;height:100%;object-fit:cover}
.snap--md{--snap:74px}
.snap--lg{--snap:104px}
@media (min-width:720px){.deal-card .snap{--snap:96px}}


/* ==========================================================================
   Marker loop around a saving      macro: marker()
   mock: .save-wrap .amt .loop. The path is the mock's, verbatim. On the višnja total card use marker(on_visnja=True).
   vector-effect keeps the stroke 2.4px however the text width stretches the loop.
   ========================================================================== */
.marker{position:relative;display:inline-block}
.marker__text{position:relative;z-index:1;padding:0 4px;font-weight:var(--fw-heavy);font-variant-numeric:tabular-nums;color:var(--save-ink);font-size:1.12rem}
.marker__loop{
  position:absolute;left:-6px;top:-5px;width:calc(100% + 12px);height:calc(100% + 10px);color:var(--save);pointer-events:none;
  overflow:visible;
}
.marker__loop path{vector-effect:non-scaling-stroke}
.marker--on-visnja .marker__text{color:var(--on-visnja)}
.marker--on-visnja .marker__loop{color:var(--on-visnja-mid)}


/* ==========================================================================
   Panel and card (surfaces)
   .card  = the mock's deal card surface (--raise, border, shadow). .panel = white container for lists of rows.
   The page is --bg; --line-2 hairlines only read on --surface, so rows live in a .panel.
   ========================================================================== */
.card{background:var(--raise);border:1px solid var(--line);border-radius:var(--radius-card);padding:14px;box-shadow:var(--shadow)}
.panel{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius-card);padding:var(--space-2) var(--space-4)}
.panel--pad{padding:var(--space-4)}
.panel--flush{padding:0}
.panel__title{font-family:var(--serif);font-weight:var(--fw-regular);font-size:1.12rem;color:var(--ink);margin:var(--space-2) 0 var(--space-1)}


/* ==========================================================================
   Deal card      macro: deal_card()
   mock: .deal .info .nm .meta. The whole card is the link (name carries it). The saving always shows its baseline (Q8).
   ========================================================================== */
.deal-card{position:relative;display:flex;gap:13px;align-items:center}
.deal-card__info{min-width:0}
.deal-card__name{font-size:.98rem;font-weight:var(--fw-bold);color:var(--ink);margin:0 0 2px}
.deal-card__link{color:inherit;text-decoration:none}
.deal-card__link::after{content:"";position:absolute;inset:0;border-radius:var(--radius-card)}
.deal-card__link:focus-visible{outline:none}
.deal-card:has(.deal-card__link:focus-visible){outline:var(--focus-w) solid var(--focus);outline-offset:var(--focus-offset)}
.deal-card:hover{border-color:color-mix(in srgb,var(--visnja) 30%,var(--line))}
.deal-card__meta{font-size:.82rem;color:var(--muted);margin:0 0 8px}
.deal-card__meta b{color:var(--ink-2);font-weight:var(--fw-bold)}
.deal-card__baseline{margin:6px 0 0;font-size:.78rem;color:var(--muted)}
.deal-card .marker{pointer-events:none}
/* the store a price list comes from (city page): the small muted line, pulled up under "najjeftinije u ..." */
.deal-card__store{margin:-4px 0 8px;font-size:.78rem;color:var(--muted)}
/* --verdict: the Deals page card. The snapshot and the text are the top part, the verdict and its proof link sit under it inside
   the card. The product link is stretched over the top part only (the proof link is its own target below). */
.deal-card--verdict{display:grid;gap:var(--space-3);align-content:start}
.deal-card__top{position:relative;display:flex;gap:13px;align-items:center}
.deal-card--verdict .deal-card__link::after{inset:-14px -14px 0 -14px;border-radius:var(--radius-card) var(--radius-card) 0 0}


/* ==========================================================================
   Receipt price + stats      macros: receipt(), stat(), price_figure()
   mock: .receipt .top .lbl .big .at .bot .stat. The scalloped edge is the mock's mask, verbatim (--scallop in tokens.css).
   The price is split into euros / cents / currency by price_figure(); in EN the currency comes first.
   ========================================================================== */
.receipt{margin:0}
.receipt__top{
  background:var(--visnja);color:var(--on-visnja);border-radius:16px 16px 0 0;padding:16px 16px 20px;
  -webkit-mask:var(--scallop);mask:var(--scallop);
}
.receipt__label{display:inline-block;background:var(--on-visnja);color:var(--visnja);font-weight:var(--fw-bold);font-size:.76rem;border-radius:var(--radius-badge);padding:3px 9px;margin:0 0 6px}
/* One price, a few lines: proportional numerals. Tabular ones give the "1" the width of an "8", so the big "1,65 €" read "1 ,65 €"
   and "11,00 €/kg" read "1 1,00". (Tabular numerals are for columns of prices that must line up: lists, totals, stats.) */
.receipt__unit{font-size:.88rem;color:var(--on-visnja-mid);margin:2px 0 0;font-variant-numeric:proportional-nums}
.receipt__at{font-size:.9rem;color:var(--on-visnja-mid);margin:6px 0 0}
.receipt__at b{color:var(--on-visnja)}
.receipt__stats{
  background:var(--raise);border:1px solid var(--line);border-top:0;border-radius:0 0 16px 16px;
  display:grid;grid-template-columns:1fr 1fr;gap:10px;padding:14px 16px;
}
.stat__k{font-size:.76rem;color:var(--muted);margin:0 0 2px}
.stat__v{font-weight:var(--fw-bold);font-variant-numeric:tabular-nums;color:var(--ink);font-size:1rem}
.stat__v small{font-weight:var(--fw-medium);color:var(--muted);font-size:.8rem}
@media (min-width:960px){
  .receipt__top{padding:20px 24px 24px}
  .receipt__stats{padding:16px 24px}
}


/* ==========================================================================
   Verdict box, three states      macro: verdict(state=...)
   verdict--true    the promotion is below the same store's 30-day low (green)   mock .verdict
   verdict--low     the promotion is NOT below the 30-day low (amber)
   verdict--none    no promotion on this product (neutral)
   ========================================================================== */
.verdict{
  --v:var(--save);--v-ink:var(--save-ink);
  display:flex;gap:9px;align-items:flex-start;padding:11px 13px;border-radius:var(--radius-13);
  background:color-mix(in srgb,var(--v) 12%,var(--surface));
  border:1px solid color-mix(in srgb,var(--v) 30%,var(--line));
}
.verdict--low{--v:var(--warn);--v-ink:var(--warn)}
.verdict--none{--v:var(--muted);--v-ink:var(--ink-2)}
.verdict__icon{color:var(--v-ink);flex:0 0 auto;margin-top:1px}
.verdict__text{margin:0;font-size:.9rem;color:var(--ink-2)}
.verdict__text b{color:var(--ink)}
/* The proof link sits inside the sentence; vertical padding on an inline box widens the hit area without moving the lines. */
.verdict__link{color:var(--visnja-ink);font-weight:var(--fw-link);font-size:.84rem;text-decoration:none;padding-block:14px}
.verdict__link:hover{text-decoration:underline}


/* ==========================================================================
   Buttons      macro: btn()
   mock: .add (primary, full width). Secondary and ghost are new. 44px minimum height everywhere.
   ========================================================================== */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:9px;min-height:var(--tap);max-width:100%;padding:14px 20px;
  border:1px solid transparent;border-radius:var(--radius-field);
  font:inherit;font-weight:var(--fw-bold);font-size:1rem;line-height:1.25;text-align:center;text-decoration:none;cursor:pointer;
  -webkit-tap-highlight-color:transparent;
}
.btn:active{transform:translateY(1px)}
.btn--primary{background:var(--visnja);color:var(--on-visnja);box-shadow:var(--shadow-btn)}
.btn--primary:hover{background:var(--visnja-deep)}
.btn--secondary{background:var(--surface);color:var(--visnja-ink);border-color:color-mix(in srgb,var(--visnja) 38%,var(--line))}
.btn--secondary:hover{background:color-mix(in srgb,var(--visnja) 7%,var(--surface))}
.btn--ghost{background:transparent;color:var(--visnja-ink);padding-inline:14px}
.btn--ghost:hover{background:color-mix(in srgb,var(--visnja) 8%,transparent)}
.btn--on-visnja{background:var(--on-visnja);color:var(--visnja)}
.btn--on-visnja:hover{background:var(--glass-line-2)}
/* danger: outline by default, text --danger (6.5:1 on --surface, 9:1 in dark). The solid one uses --bg as its text, so it flips with the theme. */
.btn--danger{background:var(--surface);color:var(--danger);border-color:var(--danger)}
.btn--danger:hover{background:color-mix(in srgb,var(--danger) 9%,var(--surface))}
.btn--danger-solid{background:var(--danger);color:var(--bg);border-color:transparent}
.btn--danger-solid:hover{background:color-mix(in srgb,var(--danger) 86%,var(--ink))}
.btn--block{display:flex;width:100%}
.btn--sm{padding:10px 16px;font-size:.92rem}
.btn:disabled,.btn[aria-disabled="true"]{opacity:.55;cursor:not-allowed;box-shadow:none;transform:none}
/* Actions row under the product (add / notify / share / report). */
.actions{display:flex;flex-wrap:wrap;gap:var(--space-2) var(--space-3)}
.actions--stack{flex-direction:column;align-items:stretch}


/* ==========================================================================
   Sparkline, 90-day trend      macro: sparkline()
   mock: .spark. The end dot is an HTML element (an SVG circle would turn into an ellipse in a stretched viewBox).
   ========================================================================== */
.spark__title{font-size:.82rem;color:var(--muted);margin:0 0 8px}
.spark__plot{position:relative}
.spark__svg{display:block;width:100%;height:56px;overflow:visible}
.spark__line{fill:none;stroke:var(--chart-line);stroke-width:2.4;stroke-linecap:round;vector-effect:non-scaling-stroke}
.spark__dot{position:absolute;left:var(--x);top:var(--y);width:9px;height:9px;border-radius:50%;background:var(--save);transform:translate(-50%,-50%)}
@media (min-width:960px){.spark__svg{height:72px}}


/* ==========================================================================
   Store badge, tag, pill      macros: store_badge(), tag(), pill()
   mock: .grp .gh .badge (24px, radius 7), .u .pill (size pill). Chains are letter badges (Q7).
   ========================================================================== */
.store-badge{
  flex:0 0 auto;display:inline-grid;place-items:center;width:24px;height:24px;border-radius:var(--radius-badge);
  background:var(--visnja);color:var(--on-visnja);font-size:.74rem;font-weight:var(--fw-heavy);line-height:1;
}
.store-badge--lg{width:40px;height:40px;border-radius:var(--radius-11);font-size:1.05rem}
.pill{display:inline-block;margin-left:6px;background:var(--line);color:var(--ink-2);border-radius:var(--radius-6);padding:1px 7px;font-size:.78rem;font-weight:var(--fw-semi);vertical-align:baseline}
.tag{
  display:inline-flex;align-items:center;padding:1px 8px;border-radius:var(--radius-pill);
  font-size:.72rem;font-weight:var(--fw-bold);letter-spacing:.01em;line-height:1.5;
  color:var(--visnja-ink);background:color-mix(in srgb,var(--visnja) 12%,var(--surface));
}


/* ==========================================================================
   Chain list, "Po lancima"      macro: chain_list(), chain_row()
   Every chain, cheapest first, with an "akcija" tag on promotional rows.
   ========================================================================== */
.chain-list{display:block}
.chain-row{display:flex;align-items:center;gap:12px;min-height:56px;padding:10px 0;border-top:1px solid var(--line-2);color:inherit;text-decoration:none}
.chain-list>li:first-child>.chain-row{border-top:0}
a.chain-row:hover .chain-row__name{text-decoration:underline;text-underline-offset:.2em}
.chain-row__main{display:flex;flex-direction:column;align-items:flex-start;gap:2px;min-width:0;flex:1}
.chain-row__name{font-weight:var(--fw-bold);color:var(--ink);font-size:.96rem;overflow-wrap:anywhere}
.chain-row__figs{text-align:right;white-space:nowrap}
.chain-row__price{display:block;font-weight:var(--fw-heavy);font-variant-numeric:tabular-nums;color:var(--ink);font-size:1rem}
.chain-row__unit{display:block;font-size:.8rem;color:var(--muted);font-variant-numeric:tabular-nums}
.chain-row.is-best .chain-row__price{color:var(--save-ink)}


/* ==========================================================================
   Tabs      macro: tabs()
   Server-driven: each tab is a link, the current one carries aria-current="true". Works without JavaScript.
   ========================================================================== */
.tabs{display:inline-flex;max-width:100%;gap:2px;padding:4px;border-radius:var(--radius-pill);background:var(--seg-track);overflow-x:auto;scrollbar-width:none}
.tabs::-webkit-scrollbar{display:none}
.tab{
  display:inline-flex;align-items:center;gap:5px;min-height:var(--tap);padding:0 16px;border-radius:var(--radius-pill);
  color:var(--ink-2);font-weight:var(--fw-semi);font-size:.9rem;text-decoration:none;white-space:nowrap;
}
.tab:hover{color:var(--ink)}
.tab__count{color:var(--muted);font-weight:var(--fw-medium);font-variant-numeric:tabular-nums}
.tab[aria-current="true"]{background:var(--seg-active);color:var(--ink);font-weight:var(--fw-bold);box-shadow:var(--shadow)}


/* ==========================================================================
   Chain card, "Gdje kupiti"      macro: chain_card()
   From the S2 screenshots: badge, name, store count and loyalty-card note, price, unit price, round add button,
   and the saving with its baseline.
   ========================================================================== */
.chain-cards{display:grid;gap:10px;grid-template-columns:repeat(auto-fill,minmax(min(100%,300px),1fr))}
.chain-cards>.is-best{grid-column:1 / -1}   /* the cheapest card (the one with the saving line) takes the whole row when the cards sit two across */
.chain-card.is-best{border-color:var(--save);box-shadow:0 0 0 1px var(--save),var(--shadow)}
.chain-card__head{display:flex;align-items:center;gap:12px}
.chain-card__id{flex:1;min-width:0}
.chain-card__name{font-size:1.05rem;font-weight:var(--fw-bold);color:var(--ink)}
.chain-card__sub{font-size:.82rem;color:var(--muted)}
.chain-card__price{text-align:right;white-space:nowrap}
.chain-card__amt{font-size:1.3rem;font-weight:var(--fw-heavy);font-variant-numeric:tabular-nums;color:var(--ink);line-height:1.2}
.chain-card.is-best .chain-card__amt{color:var(--save-ink)}
.chain-card__unit{font-size:.8rem;color:var(--muted);font-variant-numeric:tabular-nums}
.chain-card__save{display:flex;flex-wrap:wrap;align-items:center;gap:4px 10px;margin-top:10px;padding-top:10px;border-top:1px dashed var(--line);font-size:.9rem;color:var(--ink-2)}
.chain-card__base{font-size:.78rem;color:var(--muted)}


/* ==========================================================================
   Proof disclosure, chart, sources      macros: proof(), price_chart(), sources(), source_item()
   details/summary with a CSS chevron (S3). Chart geometry is computed by the backend (viewBox + paths + y positions);
   labels are HTML so they stay readable on a phone (S3's SVG text shrank to ~7px at 360px).
   ========================================================================== */
.proof{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius-card)}
.proof__summary{
  display:flex;align-items:center;justify-content:space-between;gap:var(--space-3);min-height:56px;padding:12px 16px;
  color:var(--visnja-ink);font-weight:var(--fw-bold);cursor:pointer;list-style:none;
}
.proof__summary::-webkit-details-marker{display:none}
.proof__summary::after{
  content:"";flex:0 0 auto;width:8px;height:8px;margin-right:4px;
  border-right:2px solid currentColor;border-bottom:2px solid currentColor;transform:translateY(-2px) rotate(45deg);
}
.proof[open]>.proof__summary::after{transform:translateY(3px) rotate(225deg)}
@media (prefers-reduced-motion:no-preference){.proof__summary::after{transition:transform var(--motion-fast) ease-out}}
.proof__body{padding:var(--space-2) 16px var(--space-4);border-top:1px solid var(--line-2)}

.chart{margin:var(--space-3) 0 0}
.chart__plot{position:relative;margin-top:28px}
.chart__svg{position:absolute;inset:0;width:100%;height:100%;overflow:visible}
.chart__grid{stroke:var(--line);stroke-width:1;vector-effect:non-scaling-stroke}
.chart__ref{stroke:var(--muted);stroke-width:1;stroke-dasharray:4 4;vector-effect:non-scaling-stroke}
.chart__step{fill:none;stroke:var(--chart-line);stroke-width:2;stroke-linejoin:round;vector-effect:non-scaling-stroke}
.chart__dot{position:absolute;width:10px;height:10px;border-radius:50%;background:var(--save);box-shadow:0 0 0 3px var(--surface);transform:translate(-50%,-50%)}
.chart__label{position:absolute;font-size:.76rem;line-height:1.2;color:var(--ink-2);font-variant-numeric:tabular-nums;white-space:nowrap}
.chart__label--ref{right:0;transform:translateY(calc(-100% - 5px))}
.chart__label--own{left:0;transform:translateY(5px)}
.chart__axis{display:flex;justify-content:space-between;margin-top:var(--space-2);font-size:.76rem;color:var(--muted);font-variant-numeric:tabular-nums}
.chart__caption{margin-top:var(--space-2)}

.sources{margin:var(--space-2) 0 0}
.sources__item{padding:12px 0;border-top:1px solid var(--line-2)}
.sources__name{font-weight:var(--fw-bold);color:var(--ink)}
.sources__value{margin:2px 0 0;font-size:.92rem;color:var(--ink-2)}
.sources__cite{display:block;margin-top:4px;font-size:.8rem;line-height:1.45;color:var(--muted);overflow-wrap:anywhere}
/* The file link sits on its own line so it is a real 44px target on a phone. */
.sources__cite a{display:flex;align-items:center;width:fit-content;min-height:var(--tap);font-weight:var(--fw-semi)}
.sources__title{font-family:var(--serif);font-weight:var(--fw-regular);font-size:1.1rem;color:var(--ink);margin:var(--space-6) 0 var(--space-1)}


/* ==========================================================================
   Basket      macros: basket_group(), basket_row(), stepper(), search_field(icon='plus'), callout(), total_card()
   mock: .items .grp .gh .row .th .rn .rp .speak .total. Rows live in a .panel (see Panel above).
   ========================================================================== */
.basket-group+.basket-group{margin-top:var(--space-5)}
.basket-group__head{display:flex;align-items:center;justify-content:space-between;gap:var(--space-3);margin:var(--space-2) 0 var(--space-2)}
.basket-group__store{display:inline-flex;align-items:center;gap:8px;font-weight:var(--fw-bold);color:var(--ink);font-size:.96rem}
.basket-group__sub{font-weight:var(--fw-bold);font-variant-numeric:tabular-nums;color:var(--ink);font-size:.94rem}
.basket-group__near{margin:-4px 0 var(--space-2);font-size:.8rem;color:var(--muted)}
.basket-row{display:flex;align-items:flex-start;gap:11px;padding:10px 0;border-top:1px solid var(--line-2)}
.thumb{
  flex:0 0 auto;display:grid;place-items:center;width:44px;height:44px;border-radius:var(--radius-thumb);
  background:var(--tint,var(--line-2));border:1px solid var(--line);color:var(--tint-i,var(--visnja));
}
.thumb .icon{width:26px;height:26px}
.basket-row__main{min-width:0;flex:1;padding-top:1px}
.basket-row__name{font-weight:var(--fw-semi);color:var(--ink);font-size:.92rem}
.basket-row__meta{font-size:.8rem;color:var(--muted)}
.basket-row__alt{font-size:.8rem;color:var(--save-ink);margin-top:1px}
.basket-row__price{padding-top:2px;font-weight:var(--fw-bold);font-variant-numeric:tabular-nums;color:var(--ink);font-size:.94rem;text-align:right}
.basket-row__price small{display:block;font-weight:var(--fw-medium);color:var(--muted);font-size:.78rem}
.basket-row .stepper{margin-top:4px}
/* The stepper and the trash button are two submit buttons of ONE form per row (name="delta" value="-1" | "1", name="remove"): the page works
   without script, the server reads item + delta or remove. */
.basket-row__qty{display:flex;align-items:center;gap:var(--space-2);margin:0}
.basket-row__remove{
  display:grid;place-items:center;flex:0 0 auto;width:var(--tap);height:var(--tap);margin-top:4px;
  border-radius:50%;color:var(--muted);
}
.basket-row__remove:hover{color:var(--danger);background:color-mix(in srgb,var(--danger) 10%,transparent)}

/* Quantity stepper: a 44px-high pill, "-" count "+". Buttons are submit buttons in the app (name="delta" value="-1"|"1"). */
.stepper{display:inline-flex;align-items:center;border-radius:var(--radius-pill);background:color-mix(in srgb,var(--visnja) 9%,var(--surface))}
.stepper__btn{display:grid;place-items:center;width:var(--tap);height:var(--tap);border-radius:50%;color:var(--visnja-ink)}
.stepper__btn:hover{background:color-mix(in srgb,var(--visnja) 12%,transparent)}
.stepper__btn:disabled{opacity:.4;cursor:not-allowed}
.stepper__val{min-width:24px;text-align:center;font-weight:var(--fw-bold);font-variant-numeric:tabular-nums;color:var(--ink)}

/* Callout: the basket speaks up (mock .speak). Also the "how we calculate" strip when given an href. */
.callout{
  display:flex;gap:11px;align-items:center;padding:12px 14px;border-radius:var(--radius-tile);
  background:var(--raise);border:1px dashed color-mix(in srgb,var(--visnja) 40%,var(--line));color:inherit;text-decoration:none;
}
a.callout:hover{border-color:var(--visnja-ink)}
.callout__icon{
  flex:0 0 auto;display:grid;place-items:center;width:40px;height:40px;border-radius:var(--radius-11);
  background:color-mix(in srgb,var(--visnja) 12%,var(--surface));color:var(--visnja-ink);
}
.callout__text{margin:0;font-size:.9rem;color:var(--ink-2)}
.callout__text b{color:var(--ink)}
.callout__go{flex:0 0 auto;margin-left:auto;color:var(--visnja-ink)}

/* Total card (mock .total). The saving carries its baseline (Q8). */
.total-card{
  display:flex;align-items:center;justify-content:space-between;gap:var(--space-3);
  background:var(--visnja);color:var(--on-visnja);border-radius:var(--radius-panel);padding:15px 16px;
}
.total-card__label{margin:0;font-size:.86rem;color:var(--on-visnja-soft)}
.total-card__value{margin:0;font-weight:var(--fw-heavy);font-size:1.4rem;font-variant-numeric:tabular-nums}
.total-card__saved{margin:4px 0 0;font-size:.86rem}
.total-card__base{margin:6px 0 0;font-size:.78rem;color:var(--on-visnja-soft)}
.total-card__check{flex:0 0 auto;color:var(--on-visnja-soft)}
.total-card .btn{flex:0 0 auto}
@media (max-width:420px){.total-card--cta{flex-wrap:wrap}.total-card--cta .btn{width:100%}}


/* ==========================================================================
   Breadcrumb      macro: breadcrumb()
   mock: .crumb ("Početna / Mlijeko / Dukat trajno 2,8 %"). Links are 44px targets.
   ========================================================================== */
.crumbs{padding-top:var(--space-1)}
.crumbs__list{display:flex;flex-wrap:wrap;align-items:center;font-size:.8rem;color:var(--muted)}
.crumbs__list li{display:inline-flex;align-items:center;min-height:var(--tap)}
.crumbs__list li+li::before{content:"/";margin:0 .5em;color:var(--muted)}
.crumbs__list a{display:inline-flex;align-items:center;justify-content:center;min-width:var(--tap);min-height:var(--tap);color:var(--muted);text-decoration:none}
.crumbs__list a:hover{color:var(--ink);text-decoration:underline}
.crumbs__list [aria-current="page"]{color:var(--ink-2);font-weight:var(--fw-semi)}


/* ==========================================================================
   Product head      macro: product_head()
   mock: .phead (snap 74px, serif name, unit line, size pill)
   ========================================================================== */
.product-head{display:flex;gap:13px;align-items:center;padding:var(--space-3) 0 var(--space-1)}
.product-head__title{font-family:var(--serif);font-weight:var(--fw-regular);font-size:1.28rem;line-height:1.2;margin:0 0 2px;color:var(--ink);overflow-wrap:anywhere}
.product-head__sub{font-size:.86rem;color:var(--muted)}
@media (min-width:720px){
  .product-head{gap:var(--space-5);padding-top:var(--space-4)}
  .product-head .snap{--snap:96px}
  .product-head__title{font-size:2rem;line-height:1.1}
  .product-head__sub{font-size:.98rem}
}


/* ==========================================================================
   Product row, link list      macros: product_row(), link_list()
   Search results and the Home "Na primjer" list (S3 rows: name, lowest chain, price, unit price); plain link lists
   (tracker, chain pages).
   ========================================================================== */
.product-row{display:flex;align-items:center;gap:12px;min-height:var(--tap);padding:12px 0;border-top:1px solid var(--line-2);color:inherit;text-decoration:none}
.product-list>li:first-child>.product-row{border-top:0}
.product-row:hover .product-row__name{color:var(--visnja-ink);text-decoration:underline;text-underline-offset:.2em}
.product-row__main{min-width:0;flex:1}
.product-row__name{display:block;font-weight:var(--fw-semi);color:var(--ink);overflow-wrap:anywhere}
.product-row__sub{display:block;font-size:.84rem;color:var(--muted)}
.product-row__figs{text-align:right;white-space:nowrap;font-variant-numeric:tabular-nums}
.product-row__price{display:block;font-weight:var(--fw-heavy);color:var(--ink)}
.product-row__unit{display:block;font-size:.8rem;color:var(--muted)}
/* product_row(add=True): a link cannot hold a button, so the row is a flex <li> of the link and the round "+" (the chain card's control, a form of its own) */
.product-item{display:flex;align-items:center;gap:var(--space-2);border-top:1px solid var(--line-2)}
.product-list>li.product-item:first-child{border-top:0}
.product-item>.product-row{flex:1 1 auto;min-width:0;border-top:0}
.product-add{flex:0 0 auto;margin:0}

.link-list>li:first-child>a,.link-list>li:first-child>.link-list__row{border-top:0}
.link-list__row,.link-list>li>a{
  display:flex;align-items:center;justify-content:space-between;gap:var(--space-3);min-height:48px;padding:8px 0;
  border-top:1px solid var(--line-2);color:var(--ink);font-weight:var(--fw-semi);text-decoration:none;
}
.link-list>li>a:hover{color:var(--visnja-ink)}
.link-list__sub{display:block;font-size:.84rem;font-weight:var(--fw-regular);color:var(--muted)}
.link-list .icon{color:var(--muted)}
/* a row that is the current one (the city picker): its tag sits against the chevron, the label keeps the rest */
.link-list>li>a[aria-current="true"]{color:var(--visnja-ink)}
.link-list__mark{margin-left:auto}


/* ==========================================================================
   Empty state      macro: empty_state()
   S3 city page: "Nema akcija za prikaz."
   ========================================================================== */
.empty{display:flex;flex-direction:column;align-items:center;gap:var(--space-3);padding:var(--space-10) var(--space-4);text-align:center}
.empty__icon{display:grid;place-items:center;width:64px;height:64px;border-radius:var(--radius-card);background:color-mix(in srgb,var(--visnja) 10%,var(--surface));color:var(--visnja-ink)}
.empty__title{font-family:var(--serif);font-weight:var(--fw-regular);font-size:1.2rem;color:var(--ink)}
.empty__text{max-width:40ch;color:var(--ink-2);font-size:.94rem}


/* ==========================================================================
   Form fields      macro: field()
   Controls are at least 48px tall, 1px --line-strong border (3:1 against the page), focus ring 3px.
   ========================================================================== */
.field{display:grid;gap:6px}
.field__label{font-size:.86rem;font-weight:var(--fw-semi);color:var(--ink-2)}
.field__req{color:var(--danger)}
.field__control{
  width:100%;min-height:var(--input-h);padding:0 14px;border:1px solid var(--line-strong);border-radius:var(--radius-field);
  background:var(--surface);color:var(--ink);font:inherit;font-size:1rem;line-height:1.5;
}
.field__control::placeholder{color:var(--muted);opacity:1}
.field__control:hover{border-color:var(--ink-2)}
.field__control:focus-visible{outline:var(--focus-w) solid var(--focus);outline-offset:var(--focus-offset);border-color:var(--focus)}
textarea.field__control{min-height:120px;padding:12px 14px;resize:vertical}
select.field__control{
  appearance:none;-webkit-appearance:none;padding-right:42px;
  background-image:linear-gradient(45deg,transparent 50%,var(--ink-2) 50%),linear-gradient(135deg,var(--ink-2) 50%,transparent 50%);
  background-position:calc(100% - 21px) 50%,calc(100% - 15px) 50%;background-size:6px 6px,6px 6px;background-repeat:no-repeat;
}
.field__control:disabled{background:var(--line-2);color:var(--muted);cursor:not-allowed}
.field__hint{font-size:.82rem;color:var(--muted)}
.field__error{display:flex;gap:6px;align-items:flex-start;font-size:.84rem;font-weight:var(--fw-semi);color:var(--danger)}
.field--error .field__control{border-color:var(--danger);border-width:2px}
/* field(size='code'): the one-time code. Big, centred, tabular, spaced. Same markup as every field. */
.field--code .field__control{min-height:60px;text-align:center;font-size:1.6rem;font-weight:var(--fw-bold);letter-spacing:.3em;text-indent:.3em;font-variant-numeric:tabular-nums}
.field--code .field__label,.field--code .field__hint{text-align:center}
.field--code .field__error{justify-content:center}
.check{display:flex;align-items:center;gap:12px;min-height:var(--tap);color:var(--ink);cursor:pointer}
.check input{flex:0 0 auto;width:22px;height:22px;margin:0;accent-color:var(--focus)}


/* ==========================================================================
   Pager      macro: pager()
   Search results pagination (Q14). Previous / next are 44px targets.
   ========================================================================== */
.pager{display:flex;align-items:center;justify-content:space-between;gap:var(--space-3);margin-top:var(--space-4)}
.pager__status{font-size:.9rem;color:var(--muted);font-variant-numeric:tabular-nums;text-align:center}
/* very narrow phones: the status takes its own line above the two buttons */
@media (max-width:399px){
  .pager{flex-wrap:wrap}
  .pager__status{order:-1;flex:1 0 100%}
  .pager .btn{flex:1 1 0}
}


/* ==========================================================================
   Filter form      macro: filter_form(...)
   A plain GET form (?lanac=dukat&akcije=on&poredaj=cijena): the server filters, no script. Phones: filters above the list, compact (the
   select on its own line, then the box and the button side by side). 720-959px: the whole row on one line. From 960px: a column
   (.layout-catalog puts it in a sticky 288px column).
   ========================================================================== */
.filter-form__body{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-1) var(--space-3);margin-top:var(--space-2)}
.filter-form__body>.field{flex:1 1 100%}
.filter-form__body>.check{flex:1 1 auto}
.filter-form__actions{flex:0 0 auto}
@media (min-width:720px) and (max-width:959px){
  .filter-form__body{align-items:flex-end;gap:var(--space-3) var(--space-5)}
  .filter-form__body>.field{flex:1 1 240px}
  .filter-form__body>.check{flex:0 0 auto}
}
@media (min-width:960px){
  .filter-form__body{flex-direction:column;align-items:stretch;gap:var(--space-3)}
  .filter-form__body>.field,.filter-form__body>.check{flex:0 0 auto}
  .filter-form__actions{margin-top:var(--space-1)}
}


/* ==========================================================================
   Price figure      macro: price_figure(price, size)
   The split price: euros big, cents small, the currency after them (before them in EN). The receipt uses lg, the plan cards md.
   Proportional numerals, as .receipt__unit.
   ========================================================================== */
.price{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px;margin:0;font-variant-numeric:proportional-nums}
.price__e{font-weight:var(--fw-heavy);letter-spacing:-.02em}
.price__cur{margin-left:3px;font-weight:var(--fw-bold)}
.price--cur-first .price__cur{order:-1;margin-left:0;margin-right:3px}
.price--lg .price__e{font-size:2.9rem;line-height:.95}
.price--lg .price__c{font-size:1.5rem;font-weight:var(--fw-heavy)}
.price--lg .price__cur{font-size:1.4rem}
.price--md .price__e{font-size:2.6rem;line-height:1}
.price--md .price__c{font-size:1.4rem;font-weight:var(--fw-heavy)}
.price--md .price__cur{font-size:1.3rem}
.price__per{margin-left:8px;font-size:.9rem;font-weight:var(--fw-medium);color:var(--muted)}
@media (min-width:960px){.price--lg .price__e{font-size:3.4rem}.price--lg .price__c{font-size:1.8rem}}


/* ==========================================================================
   Ticket      macros: ticket(), ticket_bottom()
   The receipt's grammar (višnja top, scalloped edge, one big figure) carrying days or a plan name: a ticket stub. Under it, a bottom
   panel with up to two figures and one button.
   ========================================================================== */
.ticket{
  background:var(--visnja);color:var(--on-visnja);border-radius:16px 16px 0 0;padding:16px 16px 22px;
  -webkit-mask:var(--scallop);mask:var(--scallop);
}
.ticket__label{display:inline-block;margin:0 0 8px;padding:3px 9px;border-radius:var(--radius-badge);background:var(--on-visnja);color:var(--visnja);font-size:.76rem;font-weight:var(--fw-bold);line-height:1.5}
.ticket__big{display:flex;align-items:baseline;gap:8px;margin:0;font-variant-numeric:tabular-nums}
.ticket__num{font-size:2.9rem;font-weight:var(--fw-heavy);line-height:.95;letter-spacing:-.02em}
.ticket__unit{font-size:1.4rem;font-weight:var(--fw-bold)}
.ticket__sub{margin:6px 0 0;font-size:.9rem;color:var(--on-visnja-mid)}
.meter{height:8px;margin-top:14px;border-radius:var(--radius-pill);background:var(--glass-line);overflow:hidden}
.meter>span{display:block;height:100%;width:var(--pct,0%);border-radius:inherit;background:var(--on-visnja)}
.ticket-bottom{
  display:grid;grid-template-columns:1fr 1fr;gap:12px 10px;padding:14px 16px 16px;
  background:var(--raise);border:1px solid var(--line);border-top:0;border-radius:0 0 16px 16px;
}
.ticket-bottom--one{grid-template-columns:1fr}
.ticket-bottom .btn{grid-column:1 / -1}
@media (min-width:960px){
  .ticket{padding:20px 24px 26px}
  .ticket__num{font-size:3.4rem}
  .ticket__unit{font-size:1.6rem}
  .ticket-bottom{padding:16px 24px 20px}
}


/* ==========================================================================
   Show more      macro: show_more(summary, id) + {% call %}
   A native <details> that opens onto the rest of a list ("Još 17 lanaca"). The summary looks like the secondary button, so it is not
   mistaken for the "Dokaz" box row (a box with the chevron at its end); the content is not boxed, so the extra cards sit in the same
   grid as the ones above. A link with data-opens="<id>" or a #<id> in the address opens it. No script needed.
   ========================================================================== */
.show-more{margin-top:var(--space-3)}
.show-more__summary{
  display:flex;align-items:center;justify-content:center;gap:var(--space-2);min-height:48px;padding:10px 16px;
  background:var(--surface);border:1px solid color-mix(in srgb,var(--visnja) 38%,var(--line));border-radius:var(--radius-field);
  color:var(--visnja-ink);font-weight:var(--fw-bold);cursor:pointer;list-style:none;
}
.show-more__summary:hover{background:color-mix(in srgb,var(--visnja) 7%,var(--surface))}
.show-more__summary::-webkit-details-marker{display:none}
.show-more__summary::after{
  content:"";flex:0 0 auto;width:8px;height:8px;margin-top:-2px;
  border-right:2px solid currentColor;border-bottom:2px solid currentColor;transform:translateY(-1px) rotate(45deg);
}
.show-more[open]>.show-more__summary::after{transform:translateY(2px) rotate(225deg)}
@media (prefers-reduced-motion:no-preference){.show-more__summary::after{transition:transform var(--motion-fast) ease-out}}
.show-more__body{margin-top:var(--space-3)}


/* ==========================================================================
   Alert call to action      macro: alert_cta(state, ...)
   "Obavijesti me kad pojeftini" on the product page, in its three states: signed out (a button to sign-in), signed in and off (a form
   button), signed in and on (the callout with a turn-off button where its chevron would be). The forms speak the alerts contract
   (alert_id, action=toggle, enabled=true|false), the same endpoint as the alerts page.
   ========================================================================== */
.alert-cta{display:grid;gap:var(--space-2);margin:0}
.alert-cta__note{margin:0;text-align:center}
.alert-cta__text{flex:1;min-width:0}
.alert-cta__text b{display:block}
.alert-cta__off{margin:-6px -6px -6px 0}


/* ==========================================================================
   Switch      macro: switch(...)
   A real <button role="switch" aria-checked> inside a form of its own (no script): press it and the page comes back with the new state.
   The accessible name is the visible label, the on / off WORD is printed next to the track, so state never rests on colour alone.
   Track: --chart-line on, --line-strong off (3:1 on --surface in both themes).
   ========================================================================== */
.switch-form{margin:0}
.switch{display:inline-flex;align-items:center;gap:12px;min-height:var(--tap);padding-right:var(--space-2);border-radius:var(--radius-pill);color:var(--ink);text-align:left}
.switch__track{position:relative;flex:0 0 auto;width:52px;height:30px;border-radius:var(--radius-pill);background:var(--line-strong)}
.switch__knob{position:absolute;top:3px;left:3px;width:24px;height:24px;border-radius:50%;background:var(--surface);box-shadow:0 1px 2px color-mix(in srgb,var(--ink) 40%,transparent)}
.switch[aria-checked="true"] .switch__track{background:var(--chart-line)}
.switch[aria-checked="true"] .switch__knob{left:25px}
.switch:hover .switch__track{box-shadow:0 0 0 4px color-mix(in srgb,var(--visnja) 12%,transparent)}
.switch__label{font-weight:var(--fw-semi);font-size:.94rem}
.switch__state{font-size:.86rem;color:var(--muted)}
.switch__state::before{content:"\00B7";margin-right:6px}


/* ==========================================================================
   Notice and toast      macro: notice(kind, title, text, floating, close_href) + {% call %} for actions
   One component, two placements. In flow it is a tinted box like the verdict (form errors, "new code sent"). floating=True is the toast:
   opaque surface, border, shadow. Server-rendered after a redirect, so it works without script; role=status (info, success) or
   role=alert (error); the dismiss is a plain link. No slide or fade (Q20). .toasts is the fixed stack a script-driven toast would use
   (above the tab bar on phones, bottom left from 720px); the server-rendered pages do not need it.
   ========================================================================== */
.notice{
  --n:var(--visnja-ink);
  display:flex;align-items:flex-start;gap:12px;padding:12px 14px;border-radius:var(--radius-13);color:var(--ink);
  background:color-mix(in srgb,var(--n) 9%,var(--surface));
  border:1px solid color-mix(in srgb,var(--n) 34%,var(--line));
}
.notice--success{--n:var(--save-ink)}
.notice--error{--n:var(--danger)}
.notice__icon{
  flex:0 0 auto;display:grid;place-items:center;width:32px;height:32px;border-radius:50%;
  background:color-mix(in srgb,var(--n) 16%,var(--surface));color:var(--n);
}
.notice__body{flex:1;min-width:0;padding-top:4px}
.notice__title{margin:0;font-weight:var(--fw-bold);color:var(--ink)}
.notice__text{margin:0;font-size:.92rem;color:var(--ink-2)}
.notice__text--solo{font-size:.94rem;color:var(--ink)}
.notice__actions{display:flex;flex-wrap:wrap;align-items:center;gap:0 var(--space-2);margin:var(--space-1) 0 calc(-1 * var(--space-2)) calc(-1 * var(--space-4))}
.notice__actions form{display:contents}
.notice__close{
  flex:0 0 auto;display:grid;place-items:center;width:var(--tap);height:var(--tap);margin:-6px -8px -6px 0;border-radius:50%;
  color:var(--muted);text-decoration:none;
}
.notice__close:hover{color:var(--ink);background:color-mix(in srgb,var(--n) 10%,transparent)}
.notice--toast{background:var(--surface);border-color:var(--line-strong);box-shadow:var(--shadow-card)}
.toasts{
  position:fixed;z-index:var(--z-tabbar);inset-inline:var(--gutter);display:grid;gap:var(--space-2);pointer-events:none;
  bottom:calc(var(--tabbar-h) + var(--space-3) + env(safe-area-inset-bottom,0px));
}
.toasts>*{pointer-events:auto;width:100%;max-width:26rem;margin-inline:auto}
@media (min-width:720px){.toasts{bottom:var(--space-6);inset-inline:var(--space-6) auto}.toasts>*{margin-inline:0}}


/* ==========================================================================
   Error state      macro: error_state(title, text, retry_href)
   A whole section that could not load. The same shape as the empty state, danger-tinted. The retry is a link (reloads the page).
   ========================================================================== */
.error-state{display:flex;flex-direction:column;align-items:center;gap:var(--space-3);padding:var(--space-8) var(--space-4);text-align:center}
.error-state__icon{display:grid;place-items:center;width:64px;height:64px;border-radius:var(--radius-card);background:color-mix(in srgb,var(--danger) 11%,var(--surface));color:var(--danger)}
.error-state__title{margin:0;font-family:var(--serif);font-weight:var(--fw-regular);font-size:1.2rem;color:var(--ink)}
.error-state__text{margin:0;max-width:40ch;color:var(--ink-2);font-size:.94rem}
.error-state__actions{display:flex;flex-wrap:wrap;justify-content:center;gap:var(--space-2) var(--space-3)}


/* ==========================================================================
   Loading skeleton      macro: skeleton(kind, n)
   Flat placeholder bars with the real component's dimensions, so nothing jumps when the content arrives: cards (an alert or deal card),
   a ticket with its bottom panel, rows (tracker, chain lists). STATIC: Q20 allows no motion, so there is no shimmer (two lines of CSS
   under prefers-reduced-motion: no-preference if the founder allows one). The wrapper is role=status with aria-busy and a visually
   hidden "Učitavanje…"; the bars are aria-hidden.
   ========================================================================== */
.skeleton{--skel:var(--line);--skel-2:color-mix(in srgb,var(--muted) 24%,var(--line))}
.skel{display:block;height:12px;border-radius:var(--radius-6);background:var(--skel,var(--line))}
.skel--title{height:16px;width:58%}
.skel--w40{width:40%}
.skel--w60{width:60%}
.skel--w80{width:80%}
.skel--snap{flex:0 0 auto;width:74px;height:74px;margin-left:4px;border-radius:var(--radius-photo)}
.skel--badge{flex:0 0 auto;width:24px;height:24px;border-radius:var(--radius-badge)}
.skel--btn{width:150px;height:44px;border-radius:var(--radius-pill)}
.skel--btn-sm{width:104px}
.skel-lines{display:grid;gap:8px;flex:1;min-width:0}
.skeleton .ticket{background:var(--skel)}
.skeleton .ticket .skel{background:var(--skel-2)}
.skel--chip{width:150px;height:22px;border-radius:var(--radius-badge)}
.skel--num{width:120px;height:44px;margin:10px 0 12px;border-radius:var(--radius-10)}
.skel--field{height:44px;border-radius:var(--radius-field)}
.skel-cards{display:grid;gap:var(--space-3)}
.skel-cards>li{display:flex}
.skel-card{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:var(--space-3);padding:var(--space-4)}
.skel-card__top{display:flex;align-items:center;gap:16px}
.skel-card__foot{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:0 var(--space-3);padding-top:var(--space-2);border-top:1px dashed var(--line)}
.skel-rows>li{border-top:1px solid var(--line-2)}
.skel-rows>li:first-child{border-top:0}
.skel-row{display:flex;align-items:center;gap:12px;min-height:60px;padding:10px 0}


/* ==========================================================================
   List row      macro: list_row(icon_html, title, text, danger) + {% call %} for a control
   An icon tile, a title and a line of text (what Plus gives), with a control at the end when the row is an action (export, delete).
   Rows live in a .panel, as list items of ul.list-rows or directly.
   ========================================================================== */
.list-rows{display:grid}
.list-row{display:flex;align-items:center;gap:12px;padding:14px 0;border-top:1px solid var(--line-2)}
.list-rows>li:first-child>.list-row,.panel>.list-row:first-child{border-top:0}
.list-row__icon{
  flex:0 0 auto;display:grid;place-items:center;width:40px;height:40px;border-radius:var(--radius-11);
  background:color-mix(in srgb,var(--visnja) 12%,var(--surface));color:var(--visnja-ink);
}
.list-row__main{min-width:0}
.list-row__title{margin:0;font-weight:var(--fw-bold);color:var(--ink)}
.list-row__text{margin:0;font-size:.9rem;color:var(--ink-2)}
/* an action row: the control takes a full line on a phone, the end of the row from 720px */
.list-row--action{display:grid;grid-template-columns:auto minmax(0,1fr);gap:var(--space-2) var(--space-3);padding:var(--space-4) 0}
.list-row--action>form,.list-row--action>.btn{grid-column:1 / -1;margin:0}
.list-row--action>form .btn,.list-row--action>.btn{width:100%}
.list-row--action .list-row__title{font-size:.98rem}
.list-row--action .list-row__text{font-size:.86rem}
.list-row--danger .list-row__icon{background:color-mix(in srgb,var(--danger) 11%,var(--surface));color:var(--danger)}
@media (min-width:720px){
  .list-row--action{grid-template-columns:auto minmax(0,1fr) auto}
  .list-row--action>form,.list-row--action>.btn{grid-column:auto}
  .list-row--action>form .btn,.list-row--action>.btn{width:auto}
}


/* ==========================================================================
   Rich link rows, key / value rows, summary      macros: link_list(rows, badges=True), kv_list(rows), summary_list(rows, total)
   Tracker: a chain badge, the chain name as the link (a ::after covers the 60px row), a sub line. Chain page: a code chip and an address.
   ========================================================================== */
.link-list--rich>li{position:relative;border-top:1px solid var(--line-2)}
.link-list--rich>li:first-child{border-top:0}
.link-row{display:flex;align-items:center;gap:12px;min-height:60px;padding:10px 0}
.link-row__main{flex:1;min-width:0}
.link-row__name{font-weight:var(--fw-bold);font-size:.96rem;color:var(--ink);text-decoration:none}
.link-row__name::after{content:"";position:absolute;inset:0}
.link-row__name:hover{color:var(--visnja-ink);text-decoration:underline;text-underline-offset:.2em}
.link-row__sub{margin:0;font-size:.84rem;line-height:1.4;color:var(--muted)}
.link-row>.icon{color:var(--muted)}

.kv-list>li{display:flex;align-items:center;gap:12px;padding:10px 0;border-top:1px solid var(--line-2)}
.kv-list>li:first-child{border-top:0}
.kv-list__k{
  flex:0 0 auto;min-width:3.6rem;padding:2px 8px;border-radius:var(--radius-6);text-align:center;
  background:color-mix(in srgb,var(--visnja) 9%,var(--surface));color:var(--visnja-ink);
  font-family:var(--mono);font-size:.82rem;font-weight:var(--fw-semi);font-variant-numeric:tabular-nums;
}
.kv-list__v{min-width:0;font-size:.9rem;color:var(--ink-2);overflow-wrap:anywhere}

.summary-list{display:grid}
.summary-list>div{display:flex;align-items:baseline;justify-content:space-between;gap:var(--space-3);padding:12px 0;border-top:1px solid var(--line-2)}
.summary-list>div:first-child{border-top:0}
.summary-list dt{font-size:.88rem;color:var(--ink-2)}
.summary-list dd{margin:0;font-weight:var(--fw-bold);font-variant-numeric:tabular-nums;white-space:nowrap;color:var(--ink)}
.summary-list__total{border-top:1px solid var(--line)!important}
.summary-list__total dt{font-weight:var(--fw-bold);color:var(--ink)}


/* ==========================================================================
   Shopping mode      macros: tick_row(), basket_group(progress=...), running_total()
   One row = one label around a native checkbox, so the whole 56px row is the target. A finished store turns its subtotal and progress
   green. The running total is a sticky card above the tab bar on phones and the sticky aside from 960px (the layout is
   .layout-split--block below 960px, so a sticky item can move in the whole page and not only in its own grid cell).
   ========================================================================== */
.tick-row{border-top:1px solid var(--line-2)}
.tick-row__label{display:flex;align-items:center;gap:14px;min-height:56px;padding:8px 0;cursor:pointer}
.tick-row__box{flex:0 0 auto;width:24px;height:24px;margin:0;accent-color:var(--focus);cursor:pointer}
.tick-row__text{display:grid;gap:1px;flex:1;min-width:0}
.tick-row__name{font-weight:var(--fw-semi);color:var(--ink);font-size:.96rem;overflow-wrap:anywhere}
.tick-row__meta{font-size:.8rem;color:var(--muted)}
.tick-row__price{flex:0 0 auto;font-weight:var(--fw-bold);font-variant-numeric:tabular-nums;color:var(--ink);font-size:.94rem}
/* ticked: the name is struck through and everything steps back to muted */
.tick-row__box:checked~.tick-row__text .tick-row__name{text-decoration:line-through;text-decoration-thickness:1.5px;color:var(--muted)}
.tick-row__box:checked~.tick-row__price{color:var(--muted);font-weight:var(--fw-semi)}

.basket-group--progress.is-done .basket-group__sub,
.basket-group--progress.is-done [data-progress]{color:var(--save-ink)}
.basket-group--progress.is-done [data-progress]{font-weight:var(--fw-semi)}
.basket-group--progress.is-done .basket-group__store::after{
  content:"";flex:0 0 auto;width:12px;height:7px;margin-left:2px;
  border-left:2.5px solid var(--save-ink);border-bottom:2.5px solid var(--save-ink);transform:rotate(-45deg) translate(1px,-2px);
}

.running-total{display:grid;gap:var(--space-2);position:sticky;bottom:calc(var(--tabbar-h) + env(safe-area-inset-bottom,0px) + var(--space-3));z-index:5}
.running-total .total-card{box-shadow:var(--shadow-card)}
.running-total__done{margin:0;text-align:center;font-weight:var(--fw-bold);color:var(--save-ink)}
.running-total__done:empty{display:none}
@media (min-width:720px){.running-total{bottom:var(--space-3)}}
@media (min-width:960px){.running-total{top:88px;bottom:auto}}


/* ==========================================================================
   List card      macro: list_card(l, groups, href)
   A saved list: name (the link, stretched over the card), counts, a badge per store, the total. A saving is not shown on the card.
   ========================================================================== */
.list-card{position:relative;display:grid;gap:var(--space-2);align-content:start}
.list-card__name{font-family:var(--serif);font-weight:var(--fw-regular);font-size:1.28rem;line-height:1.2;color:var(--ink);overflow-wrap:anywhere}
.list-card__link{color:inherit;text-decoration:none}
.list-card__link::after{content:"";position:absolute;inset:0;border-radius:var(--radius-card)}
.list-card__link:focus-visible{outline:none}
.list-card:has(.list-card__link:focus-visible){outline:var(--focus-w) solid var(--focus);outline-offset:var(--focus-offset)}
.list-card:hover{border-color:color-mix(in srgb,var(--visnja) 30%,var(--line))}
.list-card__meta{margin:0;font-size:.86rem;color:var(--muted)}
.list-card__stores{display:flex;flex-wrap:wrap;gap:6px 14px}
.list-card__store{display:inline-flex;align-items:center;gap:6px;font-size:.84rem;font-weight:var(--fw-semi);color:var(--ink-2)}
.list-card__total{margin:var(--space-2) 0 0;padding-top:var(--space-3);border-top:1px dashed var(--line);display:flex;align-items:baseline;justify-content:space-between;gap:var(--space-3)}
.list-card__total-label{font-size:.86rem;color:var(--muted)}
.list-card__total-value{font-weight:var(--fw-heavy);font-size:1.3rem;font-variant-numeric:tabular-nums;color:var(--ink)}


/* ==========================================================================
   Sheet      macros: save_list_sheet(), save_list_form(), save_list_done()
   The app's name sheet ("Spremi kao popis", app-kit SaveListSheet): a native <dialog> that tarino.js opens. A sheet at the bottom of a phone with the
   scrim behind it, a card in the middle from 720px. No slide (Q20). The panel carries the surface and the padding, so a tap on the dialog's own box is a tap
   on the backdrop. Without the script the button is a link to the same form on a page of its own (list_new). .sheet--static: the component page's specimen.
   ========================================================================== */
.sheet{width:100%;max-width:none;max-height:none;margin:auto 0 0;padding:0;border:0;background:transparent;color:var(--ink);overflow:visible}
.sheet::backdrop{background:var(--scrim)}
.sheet__panel{
  display:grid;gap:14px;max-height:calc(100vh - var(--space-6));overflow-y:auto;overscroll-behavior:contain;
  padding:var(--space-4) var(--gutter) calc(var(--space-3) + env(safe-area-inset-bottom,0px));
  border:1px solid var(--line);border-bottom:0;border-radius:var(--radius-card) var(--radius-card) 0 0;background:var(--surface);box-shadow:var(--shadow-card);
}
@supports (height:100dvh){.sheet__panel{max-height:calc(100dvh - var(--space-6))}}
.sheet__title{font-family:var(--serif);font-weight:var(--fw-regular);font-size:1.2rem;line-height:1.25;color:var(--ink)}
.save-list{display:grid;gap:14px}
.save-list__actions{display:grid;gap:var(--space-2);justify-items:center}
.save-list__actions .btn--block{justify-self:stretch}
.save-done{--stack-gap:14px}
.save-done__close{display:grid;justify-items:center}
.sheet--static .sheet__panel{border-bottom:1px solid var(--line);border-radius:var(--radius-card);max-height:none}
@media (min-width:720px){
  .sheet{width:min(92vw,28rem);margin:auto}
  .sheet__panel{padding:var(--space-5);border-bottom:1px solid var(--line);border-radius:var(--radius-card)}
}
.sheet.sheet--static{width:auto;max-width:28rem;margin:0}


/* ==========================================================================
   Camera dialog      built by tarino.js when a [data-scan] button is pressed and the browser has BarcodeDetector and a camera
   ========================================================================== */
.scan-dialog{width:min(92vw,28rem);padding:var(--space-4);border:1px solid var(--line);border-radius:var(--radius-card);background:var(--surface);color:var(--ink);box-shadow:var(--shadow-card)}
.scan-dialog::backdrop{background:var(--scrim)}
.scan-dialog__title{margin:0 0 var(--space-3);font-family:var(--serif);font-weight:var(--fw-regular);font-size:1.2rem}
.scan-dialog__video{display:block;width:100%;aspect-ratio:4 / 3;object-fit:cover;border-radius:var(--radius-13);background:var(--ink)}
.scan-dialog .fine{margin:var(--space-3) 0}


/* ==========================================================================
   Forced colours (Windows high contrast)
   System colours replace fills, so shapes that exist only as a fill get a border, and the two data dots keep their colour.
   ========================================================================== */
@media (forced-colors: active){
  .btn,.icon-btn,.stepper,.tag,.pill,.count-badge,.store-badge,.scan-btn__pill,.hero .search,.tab[aria-current="true"]{border:1px solid CanvasText}
  .receipt__top,.total-card,.hero,.ticket,.ticket-bottom{border-bottom:1px solid CanvasText}
  .marker__loop{color:CanvasText}
  .chart__dot,.spark__dot{forced-color-adjust:none}
  .notice,.skel,.ticket__label,.kv-list__k,.scan-dialog,.sheet__panel{border:1px solid CanvasText}
  .switch__track{forced-color-adjust:none;background:Canvas;border:2px solid ButtonText}
  .switch[aria-checked="true"] .switch__track{background:Highlight}
  .switch__knob{forced-color-adjust:none;background:ButtonText;box-shadow:none}
  .meter{border:1px solid CanvasText}
  .basket-group--progress.is-done .basket-group__store::after{border-color:CanvasText}
}
