@charset "UTF-8";
/* ==========================================================================
   Červený kríž Nižná — sihrdinanizna.sk
   One stylesheet, no build step, no framework.

   Palette logic: ~90% warm neutral, ONE accent (Red Cross red). The deep ink
   panel carries the visual weight so red never has to. Red appears at most
   3–5 times per viewport; its one large-surface moment is the "Si na rade"
   state, which is the only screen that earns it.
   ========================================================================== */

/* ---------------------------------------------------------------- fonts -- */
/* Figtree variable, Google's pre-subset woff2. Two files so Latin-only pages
   skip the extended set. Slovak carons (č ď ľ ĺ ň ŕ š ť ž) live in latin-ext,
   so that file is effectively always needed here — it is only 10 KB.
   Delete both @font-face blocks and the stack below falls back cleanly. */
@font-face {
  font-family: 'Figtree';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url('figtree-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Figtree';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url('figtree-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* --------------------------------------------------------------- tokens -- */
:root {
  /* neutrals — warm, hue 80. A whisper of warmth, not a cream aesthetic. */
  --paper:   oklch(98.5% 0.004 80);
  --surface: oklch(96.5% 0.006 80);
  --sunken:  oklch(94.5% 0.007 80);
  --line:    oklch(92%   0.008 80);
  --line-strong: oklch(86% 0.009 80);
  --ink:     oklch(22%   0.015 60);
  --ink-2:   oklch(54%   0.015 70);
  --ink-3:   oklch(68%   0.012 70);
  --panel:   oklch(26%   0.018 60);
  --panel-2: oklch(32%   0.018 60);

  /* the one accent */
  --red:       oklch(54% 0.19 27);
  --red-hover: oklch(49% 0.19 27);
  --red-tint:  oklch(54% 0.19 27 / 0.09);
  --on-red:    oklch(98.5% 0.004 80);

  /* semantic — deliberately duller + darker than --red so "error" never reads
     as the celebratory brand red. Errors also always carry an icon + text. */
  --danger:      oklch(46% 0.13 27);
  --danger-tint: oklch(46% 0.13 27 / 0.10);
  --success:     oklch(52% 0.12 150);
  --success-tint: oklch(52% 0.12 150 / 0.10);
  --success-row:  oklch(52% 0.12 150 / 0.14);

  /* shape — varied on purpose; uniform radii look stamped out */
  --r-input: 10px;
  --r-card:  14px;
  --r-modal: 20px;
  --r-pill:  999px;

  /* depth — warm-tinted, ambient + direct */
  --shadow-card: 0 1px 2px oklch(30% 0.02 60 / 0.06), 0 4px 12px oklch(30% 0.02 60 / 0.06);
  --shadow-lift: 0 2px 4px oklch(30% 0.02 60 / 0.08), 0 8px 20px oklch(30% 0.02 60 / 0.10);
  --shadow-overlay: 0 2px 4px oklch(30% 0.02 60 / 0.08), 0 16px 40px oklch(30% 0.02 60 / 0.14);

  /* motion */
  --t-fast: 140ms;
  --t-base: 220ms;
  --t-slow: 360ms;
  --ease: cubic-bezier(0.22, 1, 0.36, 1);

  /* type */
  --font: 'Figtree', system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;

  /* spacing rhythm — 4px base */
  --s1: 4px;  --s2: 8px;  --s3: 12px; --s4: 16px;
  --s5: 24px; --s6: 32px; --s7: 48px; --s8: 64px;

  --wrap: 860px;
  --wrap-wide: 1240px;

  /* The banner is the same red as the buttons. The "Si na rade" state shares
     it, so that moment is now signalled by copy and an icon rather than by
     colour — which is why the label, the heading and the icon all change
     together there, and why none of them may be dropped. */
  --hero-bg: oklch(54% 0.19 27);
  --hero-label: oklch(90% 0.035 30);
  --hero-meta: oklch(86% 0.045 30);
}

/* Fallback for browsers without oklch(). Declared first inside @supports-not
   so modern browsers never see them. */
@supports not (color: oklch(0 0 0)) {
  :root {
    --paper: #FBF9F5; --surface: #F6F3EE; --sunken: #F1EDE6;
    --line: #E8E3DC; --line-strong: #D8D1C7;
    --ink: #201914; --ink-2: #756D65; --ink-3: #A39B92;
    --panel: #2B221B; --panel-2: #3B3128;
    --red: #C32C29; --red-hover: #AC2422; --red-tint: rgba(195,44,41,.09);
    --on-red: #FBF9F5;
    --danger: #A32521; --danger-tint: rgba(163,37,33,.10);
    --success: #3F7D52; --success-tint: rgba(63,125,82,.10);
    --success-row: rgba(63,125,82,.14);
    --hero-bg: #C32C29; --hero-label: #F3D8D4; --hero-meta: #EDC8C3;
  }
}

/* ----------------------------------------------------------------- base -- */
*, *::before, *::after { box-sizing: border-box; }

/* Any component that sets `display` outranks the hidden attribute and silently
   un-hides itself. This keeps `hidden` meaning hidden. */
[hidden] { display: none !important; }

html {
  color-scheme: light;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.55;
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4 {
  margin: 0 0 var(--s3);
  line-height: 1.15;
  letter-spacing: -0.02em;
  font-weight: 700;
  text-wrap: balance;
}
h1 { font-size: clamp(1.75rem, 5vw, 2.35rem); }
h2 { font-size: clamp(1.3rem, 3.6vw, 1.6rem); }
h3 { font-size: 1.075rem; letter-spacing: -0.01em; }

p { margin: 0 0 var(--s4); text-wrap: pretty; }
p:last-child { margin-bottom: 0; }

a { color: var(--red); text-underline-offset: 0.18em; text-decoration-thickness: 1px; }
/* :not(.btn) is load-bearing. A plain `a:hover` is specificity (0,1,1), which
   beats `.btn--primary` at (0,1,0) — so hovering a link-styled button repainted
   its label in the same red as the button behind it and the text vanished. */
a:not(.btn):hover { color: var(--red-hover); }

small { font-size: 0.875rem; }

/* Every number in this app is data. Never let digits reflow. */
.num, td.num, .stat__value, .ribbon__n, .hero__number { font-variant-numeric: tabular-nums; }

:where(:focus-visible) {
  outline: 2px solid var(--red);
  outline-offset: 2px;
  border-radius: 4px;
}

::selection { background: var(--red-tint); }

.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap; border: 0;
}

.skip-link {
  position: absolute; left: var(--s4); top: -100px; z-index: 100;
  background: var(--ink); color: var(--paper);
  padding: var(--s3) var(--s4); border-radius: var(--r-input);
  transition: top var(--t-fast) var(--ease);
}
.skip-link:focus { top: var(--s4); }

/* --------------------------------------------------------------- layout -- */
.wrap { width: 100%; max-width: var(--wrap); margin-inline: auto; padding-inline: var(--s4); }
.wrap--wide { max-width: var(--wrap-wide); }

.stack > * + * { margin-top: var(--s4); }
.section { margin-top: var(--s7); }
.section:first-of-type { margin-top: var(--s5); }

.muted { color: var(--ink-2); }
.tiny { font-size: 0.8125rem; color: var(--ink-2); }

/* Eyebrow. Rationed to one per ~3 sections — an eyebrow above every heading is
   template grammar. This is the ONE place uppercase is allowed. */
.eyebrow {
  font-size: 0.75rem; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.09em;
  color: var(--ink-2); margin-bottom: var(--s2);
}

hr.rule { border: 0; border-top: 1px solid var(--line); margin: var(--s6) 0; }

/* The line above the queue panel. Kept to a headline plus one sentence so the
   number itself stays high on the page — the people refreshing this in a
   waiting room came for the number, not the pitch. */
.lede { margin: var(--s6) 0 var(--s5); }
/* Ink, not red. The banner and the primary button are both bright red now, and
   a 4.5rem red line on top of them would leave the page with no quiet ground —
   the red under "tri životy" below does the accent work. */
.lede h1 {
  font-size: clamp(2.75rem, 11vw, 4.5rem);
  letter-spacing: -0.045em;
  line-height: 0.98;
  margin-bottom: var(--s3);
}
.lede h2 {
  font-size: clamp(1.35rem, 4.5vw, 1.9rem);
  letter-spacing: -0.025em;
  margin-bottom: var(--s2);
}
/* The deep panel red, not the bright accent — the headline should rhyme with
   the queue panel rather than compete with the primary button next to it. */
.lede h2 em { font-style: normal; color: var(--red); }
.lede p { font-size: 1.0625rem; color: var(--ink-2); max-width: 34rem; margin: 0; }

/* Segmented control — chart range switches (Týždne / Mesiace / Roky). */
.seg {
  display: inline-flex; gap: 2px;
  background: var(--sunken); padding: 3px;
  border-radius: var(--r-pill);
}
.seg a {
  padding: 6px 15px; border-radius: var(--r-pill);
  font-size: 0.875rem; font-weight: 600;
  color: var(--ink-2); text-decoration: none; white-space: nowrap;
  transition: background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.seg a:hover { color: var(--ink); }
.seg a[aria-current="true"] {
  background: var(--paper); color: var(--ink); box-shadow: var(--shadow-card);
}

/* Matches the .seg pill so the two controls on the stats header read as one
   family instead of a native dropdown parked next to a custom widget. */
/* `.select.select--pill`, not `.select--pill`. The `.select` rule further down
   uses the `background` SHORTHAND, which resets background-image to none — at
   equal specificity it wins on source order and eats the dropdown arrow. */
.select.select--pill {
  appearance: none; -webkit-appearance: none;
  width: auto; min-height: 0;
  padding: 9px 36px 9px 16px;
  border: 0; border-radius: var(--r-pill);
  background-color: var(--sunken);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23756D65' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
  font: inherit; font-size: 0.875rem; font-weight: 600;
  color: var(--ink);
  cursor: pointer;
}
.select--pill:hover { background-color: var(--line); }
.select--pill:focus-visible { outline: 2px solid var(--red); outline-offset: 2px; }

.section-head {
  display: flex; align-items: center; gap: var(--s4);
  flex-wrap: wrap; margin-bottom: var(--s4);
}
.section-head h2 { margin: 0; }
.section-head .seg,
.section-head .sort-actions { margin-left: auto; }
.sort-actions { display: flex; gap: var(--s2); align-items: center; }

/* While there are unsaved moves the list says so, quietly but unmistakably. */
.queue-list.is-dirty { box-shadow: inset 0 0 0 2px var(--red-tint); border-radius: var(--r-input); }

/* --------------------------------------------------------------- header -- */
.site-header {
  border-bottom: 1px solid var(--line);
  background: var(--paper);
}
.site-header__in {
  display: flex; align-items: center; gap: var(--s3);
  min-height: 68px;
}
.brand { display: flex; align-items: center; gap: var(--s3); text-decoration: none; color: inherit; }
.brand__mark { width: 34px; height: 34px; flex: none; color: var(--red); display: block; }
.brand__text { display: flex; flex-direction: column; line-height: 1.1; }
.brand__name { font-weight: 700; font-size: 1rem; letter-spacing: -0.015em; }
.brand__sub { font-size: 0.75rem; color: var(--ink-2); }
.site-header__spacer { margin-left: auto; }

/* Signed-in identity. Quiet by design — it confirms who you are, it is not a
   thing to look at. On a narrow phone the name is dropped before the button:
   knowing you can sign out matters more than being told your own name. */
.site-header__who {
  font-size: 0.875rem;
  color: var(--ink-2);
  text-decoration: none;
  white-space: nowrap;
  margin-right: var(--s1);
}
.site-header__who strong { color: var(--ink); font-weight: 600; }
.site-header__who:hover strong { text-decoration: underline; }
@media (max-width: 400px) {
  .site-header__who { display: none; }
}

.site-footer {
  margin-top: var(--s8);
  border-top: 1px solid var(--line);
  padding: var(--s5) 0 var(--s7);
  font-size: 0.875rem; color: var(--ink-2);
}
.site-footer a { color: var(--ink-2); }
.site-footer a:hover { color: var(--ink); }

/* ----------------------------------------------------- hero number panel -- */
/* The one layout break on the public page. Deep warm ink, not red — which
   frees the accent for the states that actually mean something. */
.hero {
  background: var(--hero-bg);
  color: var(--paper);
  border-radius: var(--r-modal);
  padding: var(--s6) var(--s5) var(--s5);
  text-align: center;
  box-shadow: var(--shadow-card);
  position: relative;
  overflow: hidden;
}
.hero__label {
  font-size: 0.9375rem; font-weight: 500;
  color: var(--hero-label);
  margin-bottom: var(--s2);
}
.hero__number {
  font-size: clamp(5rem, 26vw, 9.5rem);
  font-weight: 800;
  line-height: 0.92;
  letter-spacing: -0.045em;
  display: block;
  margin: var(--s2) 0;
}
.hero__meta { font-size: 0.9375rem; color: var(--hero-meta); margin-top: var(--s3); }

/* "Si na rade" — the panel jumps from the deep resting red to the bright
   accent. Colour is still never the only signal: the label, the icon and the
   copy all change with it. */
.hero.is-mine { background: var(--red); }
.hero.is-mine .hero__label,
.hero.is-mine .hero__meta { color: oklch(93% 0.03 30); }
.hero.is-mine .hero__turn {
  display: inline-flex; align-items: center; gap: var(--s2);
  font-weight: 700; font-size: 1.125rem; margin-top: var(--s2);
}

/* Thank-you state. Deliberately the calm deep ink, not red: red means
   "something is happening now", and this is the one screen where it is over. */
.hero.is-done { background: var(--panel); }
.hero.is-done .hero__label { color: oklch(80% 0.01 70); }
.hero.is-done .hero__meta  { color: oklch(74% 0.012 70); }
.hero.is-done .hero__number { font-size: clamp(2.5rem, 10vw, 3.75rem); }

.hero__idle {
  font-size: clamp(1.4rem, 5vw, 2rem);
  font-weight: 700; letter-spacing: -0.02em;
  display: block; margin: var(--s3) 0;
}

/* ------------------------------------------------- SIGNATURE: the ribbon -- */
/* One motif, three surfaces. Served numbers recede, current is marked in red,
   waiting numbers sit ahead. Distance to the marker IS the wait — no
   arithmetic. Scrolls horizontally on narrow screens; never wraps. */
.ribbon {
  list-style: none;
  display: flex; align-items: flex-end; gap: var(--s2);
  margin: 0; padding: var(--s4) var(--s4) var(--s3);
  overflow-x: auto;
  scroll-snap-type: x proximity;
  scrollbar-width: thin;
  -webkit-overflow-scrolling: touch;
  border-bottom: 1px solid var(--line);
}
.ribbon__item {
  position: relative;          /* the "ty" marker is absolute inside this */
  flex: none;
  min-width: 38px;
  padding-bottom: 30px;        /* room for the marker on every item, so the one
                                  that has it doesn't shunt the row out of line */
  text-align: center;
  scroll-snap-align: center;
  font-variant-numeric: tabular-nums;
  transition: color var(--t-base) var(--ease), transform var(--t-base) var(--ease);
}
.ribbon__n { display: block; font-weight: 600; font-size: 0.9375rem; }
.ribbon__dot {
  display: block; margin: var(--s2) auto 0;
  width: 7px; height: 7px; border-radius: var(--r-pill);
  background: var(--line-strong);
}
/* served — green, the same green the admin uses for a completed donation, so
   the two screens say "done" with one colour rather than two */
.ribbon__item.is-served { color: var(--ink-3); }
.ribbon__item.is-served .ribbon__dot { background: var(--success); }
/* waiting */
.ribbon__item.is-waiting { color: var(--ink-2); }
.ribbon__item.is-waiting .ribbon__dot {
  background: transparent; box-shadow: inset 0 0 0 1.5px var(--line-strong);
}
/* current — the only red in the ribbon */
.ribbon__item.is-current { color: var(--red); }
.ribbon__item.is-current .ribbon__n { font-size: 1.375rem; font-weight: 800; letter-spacing: -0.02em; }
.ribbon__item.is-current .ribbon__dot { width: 22px; background: var(--red); }
/* the viewer's own number */
.ribbon__item.is-mine { color: var(--ink); font-weight: 700; }
.ribbon__item.is-mine .ribbon__dot { background: var(--ink); }

/* The "you are here" marker: a triangle pointing up at your own number, with
   the label beneath. Absolutely positioned so adding it to one item cannot
   change the height or alignment of the whole strip. */
.ribbon__you {
  position: absolute; left: 0; right: 0; bottom: 0;
  font-size: 0.6875rem; font-weight: 700;
  letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--ink);
  line-height: 1;
}
.ribbon__you::before {
  content: ''; display: block;
  width: 0; height: 0; margin: 0 auto 4px;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-bottom: 6px solid var(--ink);
}
/* The dot sits directly above the arrow; give them a little air. */
.ribbon__item.is-mine .ribbon__dot { margin-bottom: 2px; }

.ribbon-legend {
  display: flex; flex-wrap: wrap;
  gap: var(--s2) var(--s5);
  font-size: 0.75rem; color: var(--ink-2);
  padding: var(--s3) var(--s4) var(--s4);
  margin: 0;
}
.ribbon-legend__item { display: inline-flex; align-items: center; gap: 6px; }

/* Each key is the mark it explains, at the same size it appears above — a
   legend whose swatches don't match the thing they describe explains nothing. */
.ribbon-legend__key {
  display: inline-block; width: 7px; height: 7px;
  border-radius: var(--r-pill); flex: none;
}
.ribbon-legend__key.is-served  { background: var(--success); }
.ribbon-legend__key.is-current { width: 18px; background: var(--red); }
.ribbon-legend__key.is-waiting {
  background: transparent; box-shadow: inset 0 0 0 1.5px var(--line-strong);
}

/* -------------------------------------------------------------- buttons -- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s2);
  min-height: 46px; padding: var(--s3) var(--s5);
  border: 1px solid transparent; border-radius: var(--r-input);
  font: inherit; font-weight: 600; font-size: 1rem;
  text-decoration: none; cursor: pointer;
  touch-action: manipulation;
  transition: background-color var(--t-fast) var(--ease),
              border-color var(--t-fast) var(--ease),
              color var(--t-fast) var(--ease),
              box-shadow var(--t-fast) var(--ease),
              transform var(--t-fast) var(--ease);
}
.btn--primary { background: var(--red); color: var(--on-red); box-shadow: var(--shadow-card); }
.btn--primary:hover { background: var(--red-hover); box-shadow: var(--shadow-lift); transform: translateY(-1px); }
.btn--secondary { background: var(--surface); color: var(--ink); border-color: var(--line-strong); }
.btn--secondary:hover { background: var(--sunken); border-color: var(--ink-3); }
/* A hairline, not nothing. Without a border this reads as a line of text and
   people do not realise it can be pressed — which matters most for "Nemôžem
   prísť, odhlás ma", the one action that frees a slot for somebody else. */
.btn--ghost {
  background: transparent;
  color: var(--ink-2);
  border-color: var(--line);
}
.btn--ghost:hover {
  background: var(--surface);
  color: var(--ink);
  border-color: var(--line-strong);
}
.btn--danger { background: var(--paper); color: var(--danger); border-color: var(--danger); }
.btn--danger:hover { background: var(--danger-tint); }
.btn--block { width: 100%; }
.btn--lg { min-height: 56px; font-size: 1.0625rem; padding-inline: var(--s6); }
/* Exit ~75% of entrance, and a press that actually feels pressed. */
.btn:active { transform: translateY(0) scale(0.985); transition-duration: 105ms; }
.btn[disabled] { opacity: 0.5; cursor: not-allowed; transform: none; }

/* ---------------------------------------------------------------- cards -- */
.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  padding: var(--s5);
}
.card--plain { background: var(--paper); }
.card--tint { background: var(--red-tint); border-color: transparent; }

.info-row { display: flex; justify-content: space-between; gap: var(--s4); padding: var(--s3) 0; }
.info-row + .info-row { border-top: 1px solid var(--line); }
.info-row dt { color: var(--ink-2); font-size: 0.9375rem; margin: 0; }
.info-row dd { margin: 0; font-weight: 600; text-align: right; }
.info-row dt svg { vertical-align: -3px; margin-right: 2px; color: var(--ink-3); }

/* Two short prep cards side by side above 640px, stacked below. Reading
   "what to bring" and "what to do the night before" as one block of prose is
   how people end up doing neither. */
.prep { display: grid; gap: var(--s4); margin-top: var(--s4); }
@media (min-width: 640px) { .prep { grid-template-columns: 1fr 1fr; } }
.prep h3 {
  display: flex; align-items: center; gap: var(--s2);
  margin: 0 0 var(--s3); font-size: 1rem;
}
.prep h3 svg { color: var(--red); flex: none; }

/* Ticked list. The marker is drawn rather than a bullet so it reads as a
   checklist you can work through. */
ul.tick { list-style: none; margin: 0; padding: 0; }
ul.tick li {
  position: relative; padding-left: 22px;
  font-size: 0.9375rem; color: var(--ink-2);
}
ul.tick li + li { margin-top: var(--s2); }
ul.tick li::before {
  content: ''; position: absolute; left: 2px; top: 0.52em;
  width: 9px; height: 5px;
  border-left: 2px solid var(--success);
  border-bottom: 2px solid var(--success);
  transform: rotate(-45deg);
}

/* Organiser's note, set apart from the facts above it. */
.note-block {
  margin: var(--s4) 0 0;
  padding: var(--s3) var(--s4);
  background: var(--surface);
  border-radius: var(--r-input);
  font-size: 0.9375rem;
  color: var(--ink-2);
}

/* ---------------------------------------------------------------- forms -- */
.field { margin-bottom: var(--s5); }
.field__label { display: block; font-weight: 600; font-size: 0.9375rem; margin-bottom: var(--s2); }
.field__hint { display: block; font-size: 0.8125rem; color: var(--ink-2); margin-bottom: var(--s2); }
.field__optional { font-weight: 400; color: var(--ink-2); }

.input, .select, .textarea {
  display: block; width: 100%;
  /* 16px floor: below this, iOS Safari zooms the page on focus. The
     viewport-meta "fix" for that breaks pinch-zoom — a real WCAG 1.4.4 fail. */
  font: inherit; font-size: 16px;
  min-height: 46px; padding: var(--s3) var(--s4);
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-input);
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.textarea { min-height: 96px; resize: vertical; }
.input:hover, .select:hover, .textarea:hover { border-color: var(--ink-3); }
.input:focus, .select:focus, .textarea:focus {
  outline: none;
  border-color: var(--red);
  box-shadow: 0 0 0 3px var(--red-tint);
}
.input[aria-invalid="true"] { border-color: var(--danger); }
.input[aria-invalid="true"]:focus { box-shadow: 0 0 0 3px var(--danger-tint); }

/* Errors sit BELOW the field (they appear after typing, so reading order puts
   them there). Hints sit ABOVE, where autofill menus and the mobile keyboard
   can't cover them. Never colour alone — icon + text always. */
.field__error {
  display: flex; align-items: flex-start; gap: 6px;
  margin-top: var(--s2);
  font-size: 0.875rem; font-weight: 500; color: var(--danger);
}
.field__error svg { flex: none; width: 16px; height: 16px; margin-top: 2px; }

.check { display: flex; align-items: flex-start; gap: var(--s3); cursor: pointer; }
.check input[type="checkbox"] {
  flex: none; width: 20px; height: 20px; margin-top: 2px;
  accent-color: var(--red); cursor: pointer;
}
.check span { font-size: 0.9375rem; }

/* Honeypot — must be reachable by nothing, including screen readers. */
.hp { position: absolute; left: -9999px; opacity: 0; height: 0; overflow: hidden; }

fieldset { border: 0; margin: 0; padding: 0; }
legend { font-weight: 600; font-size: 0.9375rem; padding: 0; margin-bottom: var(--s2); }

/* Volume presets — a segmented control, stacked-friendly. */
.presets { display: flex; flex-wrap: wrap; gap: var(--s2); }
.presets input { position: absolute; opacity: 0; pointer-events: none; }
.presets label {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 52px; min-width: 78px; padding: var(--s2) var(--s4);
  border: 1px solid var(--line-strong); border-radius: var(--r-input);
  background: var(--paper); font-weight: 600; cursor: pointer;
  font-variant-numeric: tabular-nums;
  transition: background-color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.presets label:hover { background: var(--surface); }
.presets input:checked + label { background: var(--red); color: var(--on-red); border-color: var(--red); }
.presets input:focus-visible + label { outline: 2px solid var(--red); outline-offset: 2px; }

/* --------------------------------------------------------------- alerts -- */
.alert {
  display: flex; gap: var(--s3);
  padding: var(--s4);
  border-radius: var(--r-card);
  font-size: 0.9375rem;
  border: 1px solid transparent;
}
.alert svg { flex: none; width: 20px; height: 20px; margin-top: 1px; }
.alert--error   { background: var(--danger-tint);  border-color: var(--danger);  color: var(--danger); }
.alert--success { background: var(--success-tint); border-color: var(--success); color: var(--success); }
.alert--note    { background: var(--surface); border-color: var(--line); color: var(--ink-2); }

/* --------------------------------------------------------------- tables -- */
.table-wrap { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--r-card); }
table.data { width: 100%; border-collapse: collapse; font-size: 0.9375rem; background: var(--paper); }
table.data th, table.data td { padding: var(--s3) var(--s4); text-align: left; }
table.data th {
  font-weight: 600; font-size: 0.8125rem; color: var(--ink-2);
  background: var(--surface); border-bottom: 1px solid var(--line);
  white-space: nowrap;
}
table.data td { border-bottom: 1px solid var(--line); }
table.data tr:last-child td { border-bottom: 0; }
table.data td.num, table.data th.num { text-align: right; font-variant-numeric: tabular-nums; }
table.data tbody tr { transition: background-color var(--t-fast) var(--ease); }
table.data tbody tr:hover { background: var(--surface); }

.status-dot {
  display: inline-block; width: 7px; height: 7px;
  border-radius: var(--r-pill); margin-right: 6px; vertical-align: 1px;
}
.status-dot--waiting { background: var(--line-strong); }
.status-dot--called  { background: var(--red); }
.status-dot--done    { background: var(--success); }
.status-dot--noshow  { background: var(--ink-3); }

/* ---------------------------------------------------------------- stats -- */
.stat-grid { display: grid; gap: var(--s4); grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
.stat {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-card); padding: var(--s4) var(--s5);
}
.stat--hero { background: var(--red-tint); border-color: transparent; grid-column: 1 / -1; }
.stat__label { font-size: 0.8125rem; color: var(--ink-2); font-weight: 500; }
.stat__value { font-size: 1.75rem; font-weight: 700; letter-spacing: -0.025em; line-height: 1.1; margin-top: 2px; }
.stat--hero .stat__value { font-size: clamp(2.25rem, 8vw, 3rem); }
.stat__unit { font-size: 0.9em; font-weight: 600; color: var(--ink-2); }
/* Comparisons are plain secondary text — never a coloured pill. */
.stat__note { font-size: 0.8125rem; color: var(--ink-2); margin-top: 2px; }

/* Horizontal bars for categorical data. No pie, no vertical bars on a
   time-series — single hue at varied opacity. */
.bars { display: grid; gap: var(--s3); }
.bar__row { display: grid; grid-template-columns: minmax(90px, 30%) 1fr auto; gap: var(--s3); align-items: center; font-size: 0.875rem; }
.bar__label { color: var(--ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bar__track { background: var(--sunken); border-radius: var(--r-pill); height: 10px; overflow: hidden; }
/* display:block is load-bearing. The track is a grid item so it gets blockified
   for free, but the fill inside it is a plain span in a non-flex parent — left
   inline, height has no effect and every bar renders empty. */
.bar__fill { display: block; height: 100%; background: var(--red); border-radius: var(--r-pill); }
.bar__value { font-variant-numeric: tabular-nums; font-weight: 600; white-space: nowrap; }

.spark { display: block; width: 100%; height: 48px; }

/* Chart. The SVG stretches to fill; everything that must stay the right shape
   and size lives in an HTML layer on top, positioned by percentage. That is why
   axis labels are crisp at any width and the dots are round rather than oval. */
.chart { position: relative; height: 190px; }
@media (max-width: 640px) { .chart { height: 160px; } }

.chart__plot { display: block; width: 100%; height: 100%; }
.chart__layer { position: absolute; inset: 0; pointer-events: none; }

.chart__dot {
  position: absolute; width: 7px; height: 7px;
  margin: -3.5px 0 0 -3.5px;
  border-radius: var(--r-pill); background: var(--red);
}

.chart__tick {
  position: absolute; bottom: 0; transform: translateX(-50%);
  font-size: 0.6875rem; color: var(--ink-2); white-space: nowrap;
}
.chart__tick.is-first { transform: none; }
.chart__tick.is-last  { transform: translateX(-100%); }

.chart__guide {
  position: absolute; top: 6%; bottom: 15%;
  border-left: 1px dashed var(--ink-3);
}
.chart__focus {
  position: absolute; width: 12px; height: 12px;
  margin: -6px 0 0 -6px;
  border-radius: var(--r-pill);
  background: var(--red); box-shadow: 0 0 0 2.5px var(--paper);
}

.chart__hit {
  position: absolute; top: 0; bottom: 14%;
  transform: translateX(-50%);
  padding: 0; border: 0; background: transparent;
  pointer-events: auto; cursor: crosshair;
}

.chart__tip {
  position: absolute; z-index: 3;
  transform: translate(-50%, -100%);
  background: var(--panel); color: var(--paper);
  padding: 7px 11px; border-radius: var(--r-input);
  font-size: 0.8125rem; line-height: 1.35;
  white-space: nowrap; pointer-events: none;
  box-shadow: var(--shadow-lift);
}
.chart__tip b { display: block; font-variant-numeric: tabular-nums; font-size: 0.9375rem; }
.chart__tip span { color: oklch(78% 0.012 70); }

/* ---------------------------------------------------------------- admin -- */
.admin-nav {
  display: flex; gap: var(--s1); align-items: center;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  padding: var(--s2) 0;
  overflow-x: auto;
}
.admin-nav a,
.admin-nav__form button {
  padding: var(--s2) var(--s4); border-radius: var(--r-input);
  color: var(--ink-2); text-decoration: none; font-weight: 600; font-size: 0.9375rem;
  white-space: nowrap;
  transition: background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.admin-nav a:hover,
.admin-nav__form button:hover { color: var(--ink); background: var(--paper); }
/* Sign-out is a POST, so it is a button. It must not read as one. */
.admin-nav__form { display: contents; }
.admin-nav__form button {
  font-family: inherit; border: 0; background: none; cursor: pointer;
}
.admin-nav a[aria-current="page"] { background: var(--red-tint); color: var(--red); }
.admin-nav__end { margin-left: auto; }

/* The operator's card. Big targets, one-handed, in a room. */
.now-serving {
  background: var(--panel); color: var(--paper);
  border-radius: var(--r-modal); padding: var(--s5);
}
.now-serving__num {
  font-size: clamp(3rem, 14vw, 4.5rem); font-weight: 800;
  letter-spacing: -0.04em; line-height: 1;
  font-variant-numeric: tabular-nums;
}
.now-serving__name { font-size: 1.25rem; font-weight: 600; margin-top: var(--s1); }
.now-serving__actions { display: grid; gap: var(--s3); margin-top: var(--s5); }
.now-serving__empty { color: oklch(78% 0.012 70); }

.queue-list { list-style: none; margin: 0; padding: 0; }
.queue-item {
  display: flex; align-items: center; gap: var(--s4);
  padding: var(--s3) var(--s4);
  border-bottom: 1px solid var(--line);
}
.queue-item:last-child { border-bottom: 0; }
.queue-item__n {
  font-weight: 700; font-variant-numeric: tabular-nums;
  min-width: 2.5ch; font-size: 1.0625rem;
}
.queue-item__body { flex: 1; min-width: 0; }
.queue-item__name { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.queue-item__meta { font-size: 0.8125rem; color: var(--ink-2); }
/* Already donated — a green row so the organiser can see at a glance who is
   finished without reading a word. The status dot and the "darované" label stay
   put: on a bright screen in a bright room the tint alone is easy to miss, and
   colour must never be the only thing carrying the state. */
/* Contact line. Deliberately below the status rather than beside it — a name,
   a state, a phone and an email on one line is unreadable on a phone. */
.queue-item__contact {
  display: flex; flex-wrap: wrap; gap: 2px 14px;
  font-size: 0.75rem; margin-top: 3px;
  color: var(--ink-3);
}
.queue-item__contact a {
  color: var(--ink-2);
  text-decoration: none;
  font-weight: 500;
  transition: color var(--t-fast) var(--ease);
}
.queue-item__contact a:hover { color: var(--ink); text-decoration: underline; }
.queue-item__tel {
  display: inline-flex; align-items: center; gap: 5px;
  font-variant-numeric: tabular-nums;
}
.queue-item__tel svg { color: var(--ink-3); }
.queue-item__mail {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 26ch;
}
.now-serving__contact {
  display: flex; flex-wrap: wrap; gap: 4px 14px; margin-top: 6px;
}
.now-serving__contact a { color: oklch(80% 0.012 70); text-decoration: none; display: inline-flex;
  align-items: center; gap: 5px; }
.now-serving__contact a:hover { color: var(--paper); text-decoration: underline; }

.queue-item.is-done { background: var(--success-row); }
.queue-item.is-done .queue-item__n { color: var(--success); }
.queue-item.is-done .queue-item__meta { color: var(--success); }

/* Skipped or removed — receded, not celebrated. */
.queue-item.is-skipped { color: var(--ink-2); }
.queue-item.is-skipped .queue-item__name { font-weight: 500; text-decoration: line-through; }

.queue-item.is-current { background: var(--red-tint); }

/* Reorder + remove controls. 38px is below the 44px target rule on purpose:
   these sit in a dense list, they are non-destructive-by-default (remove asks
   first), and making them full size would push the donor's name off a phone. */
/* Drag handle. touch-action:none is required, not cosmetic — without it the
   browser claims the gesture for scrolling and the drag never starts on a
   phone, which is the only device this screen is really used on. */
.drag-handle {
  flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 38px; padding: 0; margin-right: -4px;
  border: 0; background: transparent; color: var(--ink-3);
  cursor: grab; touch-action: none;
  border-radius: var(--r-input);
}
.drag-handle:hover { color: var(--ink-2); background: var(--surface); }
.drag-handle:active { cursor: grabbing; }

.queue-item.is-dragging {
  background: var(--paper);
  box-shadow: var(--shadow-lift);
  border-radius: var(--r-input);
  opacity: 0.92;
  position: relative; z-index: 2;
}
/* Where it will land. */
.queue-item.is-drop-target { box-shadow: inset 0 2px 0 0 var(--red); }
.queue-list.is-sorting { cursor: grabbing; user-select: none; }

.row-actions { display: flex; gap: 2px; flex: none; }
.icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; padding: 0;
  border: 1px solid transparent; border-radius: var(--r-input);
  background: transparent; color: var(--ink-2);
  cursor: pointer; touch-action: manipulation;
  transition: background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.icon-btn:hover { background: var(--surface); color: var(--ink); }
.icon-btn:active { transform: scale(0.94); }
.icon-btn--danger:hover { background: var(--danger-tint); color: var(--danger); }
.icon-btn[disabled] { opacity: 0.28; cursor: default; }
.icon-btn[disabled]:hover { background: transparent; color: var(--ink-2); }

/* -------------------------------------------------------------- dialogs -- */
dialog {
  border: 0; border-radius: var(--r-modal); padding: var(--s5);
  background: var(--paper); color: var(--ink);
  box-shadow: var(--shadow-overlay);
  width: min(440px, calc(100vw - 32px));
}
dialog::backdrop { background: oklch(20% 0.02 60 / 0.45); }
.dialog__actions { display: flex; gap: var(--s3); margin-top: var(--s5); }
.dialog__actions .btn { flex: 1; }

/* --------------------------------------------------------------- motion -- */
/* Transform only — no opacity. An entrance that fades in from 0 makes content
   invisible for as long as the animation has not run, and on an old Android
   WebView or any engine that stalls animations that is a permanently blank
   page. Half this town will open the site on a phone that is not new, so the
   motion is worth having only if it cannot hide anything. */
@keyframes rise-in {
  from { transform: translateY(6px); }
  to   { transform: none; }
}
@keyframes pop-in {
  from { transform: scale(0.97); }
  to   { transform: none; }
}
/* Queue advanced — communicates a state change, which is the only reason
   a number is allowed to animate. */
.is-advancing { animation: rise-in var(--t-base) var(--ease); }
/* One-time confirmation moment; may be expressive. */
.reveal { animation: pop-in var(--t-slow) var(--ease); }

/* No `both` fill mode, deliberately. With it, the element sits at opacity 0
   until the animation runs — so anything that stops the animation starting
   (an early paint, a snapshot renderer, an odd engine) leaves the page blank.
   Without it the element's resting state is visible and the entrance is pure
   enhancement, which is the only safe way round for content. */
.section-reveal { animation: rise-in var(--t-base) var(--ease); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .btn:hover, .btn:active { transform: none; }
}

/* ----------------------------------------------------------- responsive -- */
@media (min-width: 600px) {
  .now-serving__actions { grid-template-columns: 2fr 1fr; }
  .hero { padding: var(--s7) var(--s6) var(--s6); }
}
@media (min-width: 768px) {
  body { font-size: 16.5px; }
  .stat-grid { gap: var(--s5); }
  .brand__mark { width: 40px; height: 40px; }
  .brand__name { font-size: 1.0625rem; }
}

/* Below 380px (older/small phones) the ribbon and buttons need to give. */
@media (max-width: 380px) {
  .ribbon__item { min-width: 32px; }
  .btn { padding-inline: var(--s4); }
  .wrap { padding-inline: var(--s3); }
}

/* ---------------------------------------------------------------- print -- */
/* The organizer may want the queue on paper as a fallback if wifi dies. */
@media print {
  body { background: #fff; font-size: 11pt; }
  .site-header, .site-footer, .admin-nav, .btn, .ribbon, .now-serving__actions { display: none !important; }
  .card, .table-wrap { border-color: #999; box-shadow: none; }
  table.data { font-size: 10pt; }
  a[href]::after { content: ''; }
}
