/*
 * The calendar's visual design, made real — design/calendar/ is the source of truth and
 * palette.py is where every colour below came from (derived in oklch, never picked).
 *
 * Two rules from that design worth keeping in mind before editing anything here:
 * every neutral sits at hue 60 with a trace of chroma, which is the entire reason the
 * screen reads soft rather than clinical; and there is exactly one accent, used only
 * where it means *now* or *primary action* (D1). Service colour is a separate dimension
 * carried by the block tint alone — no bars, no borders (a bar plus a border on a grid
 * this dense builds a cage).
 */

/* Self-hosted, not fetched from Google: a page in this app is served to a therapist
   whose practice is health data, and a font request would hand a third party her IP and
   the fact that she just opened her calendar. 38 KB of woff2 in the repo is cheaper than
   that conversation. Varta is SIL OFL — see public/assets/fonts/OFL.txt.

   **One file, no `unicode-range` split.** Google's own CSS ships Varta as separate
   `latin` and `latin-ext` subsets, and that is how this started — which quietly broke
   Czech. Every caron and kroužek (č ř š ž ě ů ď ť ň) lives in latin-ext while á é í ó ú ý
   sit in latin, so a Czech word is routinely spelled out of *both* files. Two files means
   two independent races, and under `font-display: optional` each one is decided on its
   own: on a phone the small latin file would win its window and the latin-ext file miss
   it, and the page rendered "Přehled" with the P, e, h, l, e, d in Varta and the ř in the
   system font. Different face, different weight, different width, inside one word.
   Subsetting both ranges into a single file makes that structurally impossible — the
   font is either used for the whole page or not at all. It is also *smaller* than the two
   subsets it replaces (38 KB against 47 KB) and one request instead of two.

   Rebuild it with (fonttools + brotli, from the upstream variable TTF at
   github.com/google/fonts/tree/main/ofl/varta):

     pyftsubset "Varta[wght].ttf" --output-file=public/assets/fonts/varta.woff2 \
       --flavor=woff2 --layout-features='*' --no-hinting --desubroutinize \
       --unicodes="U+0000-00FF,U+0100-017F,U+0180-024F,U+0259,U+02BB-02BC,U+02C6,U+02DA,\
                   U+02DC,U+0300-0304,U+0308,U+0329,U+1E00-1E9F,U+1EF2-1EFF,U+2000-206F,\
                   U+20A0-20C0,U+2113,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD"

   `font-display: optional`, not `swap`. Every navigation here is a full page load, and
   under `swap` the browser painted the fallback first and replaced it a moment later —
   Segoe UI is metrically much larger than Varta, so the whole page visibly jumped bigger
   and then snapped smaller, on every single click. `optional` gives the font a short
   block period and then commits for that page load: it never swaps mid-page, so the
   reflow is structurally impossible rather than merely rare. The trade is that a cold
   first load may render in the fallback; the preload in templates/layout.php is what
   keeps that to the first load only.

   No `size-adjust` fallback metric override is declared, deliberately: getting one right
   needs Varta's actual x-height and average advance measured out of the woff2, and an
   invented number would make the fallback wrong in a new way rather than a smaller way. */
@font-face {
  font-family: 'Varta';
  font-style: normal;
  font-weight: 300 700;
  font-display: optional;
  src: url('fonts/varta.woff2') format('woff2');
}

:root {
  --ink: #241E1A;
  --ink-2: #68625E;
  /* Was #9C9793, which measured 2.89:1 on white — a clear AA failure (4.5:1) on the
     smallest text in the app: field hints, empty states, calendar block times. Darkened
     along the same hue-60 neutral ramp to 4.84:1 on white and 4.63:1 on the today tint.
     It still reads as the quietest of the three inks; it is no longer unreadable. */
  --ink-3: #767169;
  --hairline: #E9E5E2;
  --hairline-soft: #F3EFED;
  --tint-today: #FDF9F6;
  /* Three accent values where there were two, because one colour cannot do all three
     jobs at AA. #AD674E is 4.35:1 on white: fine for a border, a focus ring or the today
     marker (which need 3:1), and a failure for text and for white-on-accent buttons
     (which need 4.5:1). Splitting them is cheaper than lightening the whole brand. */
  --accent: #AD674E;         /* non-text: rings, borders, the today marker */
  --accent-text: #A15C43;    /* accent-coloured *text* — 5.09:1 on white */
  --accent-strong: #9A553C;  /* filled buttons, white label on top — 5.62:1 */
  --accent-hover: #8E4E36;
  --accent-soft: #FFE7DE;
  /* Was #CE9581, which measured 2.55:1 on white — the focus ring, the one affordance a
     keyboard user has no alternative to, was below the 3:1 floor for a UI element. It was
     also the least visible thing on the palette against the accent-soft tint it most
     often appears over. #B37155 is 3.88:1 on white and 3.28:1 on that tint, so it clears
     the bar on both grounds it can appear on rather than only the easy one. */
  --accent-ring: #B37155;

  /* All six share one lightness and one chroma and differ only in hue, so no service
     shouts louder than another (F34). */
  --svc-modra: #DCEFFF;
  --svc-tyrkys: #D4F4F4;
  --svc-zelena: #DEF4E1;
  --svc-oliva: #F0EFD5;
  --svc-mauve: #F2E8FF;
  --svc-ruzova: #FFE4F2;
  --svc-neutral: #F3EFED;

  /* Type scale. Before this block every size in the file was a literal, and there were
     fifteen of them — 10.5, 11, 11.5, 12, 12.5, 13, 13.5, 14, 14.5, 15, 16, 19.5, 20, 22,
     23 — which is not a scale, it is an accumulation. Half-pixel sizes also round
     differently depending on the display's device-pixel-ratio, so the same screen was
     genuinely crisper on some machines than others.

     Named by role rather than by t-shirt size, because the roles are what the templates
     actually mean and a `--text-sm` that is larger than `--text-base` is how these get
     misused. Every size is a whole pixel. */
  --text-micro: 12px;    /* calendar block times, badges — the smallest thing we ship */
  --text-caption: 13px;  /* kickers, day names, meta under a heading */
  --text-small: 14px;    /* hints, secondary labels, table meta */
  --text-meta: 15px;     /* subnav, buttons, list meta */
  --text-body: 16px;     /* body copy and form inputs */
  --text-lead: 17px;     /* the one step above body, used sparingly */
  --text-title: 22px;    /* screen titles */
  --text-display: 25px;  /* the session panel's name, the largest text in the app */

  /* Varta is a light-ish humanist face; at 400 on white its secondary text reads thinner
     than the same weight in Segoe UI, which is most of why this looked washed out. The
     face is variable (300–700), so 450 is a real instance rather than a synthesised
     smear — a small, deliberate step, not a bolding. */
  --weight-body: 450;
  --weight-medium: 520;
  --weight-semibold: 620;
  --weight-bold: 700;

  /* D19: 30-minute rows. Raised with the type scale — a 50-minute session used to be 57px
     around 10.5/13/11.5px text, and the same block at 12/14.5/12.5px needs the room or
     the service line clips. */
  --row-h: 74px;
  --gutter-w: 76px;
  --grid-pad-l: 12px;
  --grid-pad-r: 24px;

  color-scheme: light;
}

* { box-sizing: border-box; }

/* Form controls do not inherit type from the page — a `<button>`, `<input>`, `<select>`
   or `<textarea>` with no explicit rule renders in the UA's own font at the UA's own
   size, which on a phone is a visibly different face from the rest of the screen. Every
   control this app ships today sets `font: inherit` itself; this makes that the default
   so the next one added does not have to remember. */
button, input, select, textarea { font: inherit; }

html, body {
  margin: 0;
  height: 100%;
  background: #fff;
  color: var(--ink);
  font-family: 'Varta', 'Segoe UI', system-ui, -apple-system, sans-serif;
  -webkit-font-smoothing: antialiased;
  font-size: var(--text-body);
  font-weight: var(--weight-body);
  line-height: 1.5;
}

a { color: var(--accent-text); text-decoration: none; }
a:hover { color: var(--accent-hover); }

:focus-visible { outline: 2px solid var(--accent-ring); outline-offset: 2px; border-radius: 6px; }

/*
 * 2.4.1 Bypass Blocks. The rail is six tab stops on every screen, and on the calendar the
 * content behind it is 140 more — one focusable slot per half hour of the week. A keyboard
 * user was crossing the whole navigation on every page load to reach anything.
 *
 * Off-screen rather than `display: none`, so it is in the tab order and appears where the
 * eye already is when it takes focus.
 */
.skip {
  position: absolute; left: 12px; top: -60px; z-index: 20;
  padding: 10px 16px; border-radius: 8px;
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--hairline); font-size: var(--text-body); text-decoration: none;
  transition: none;
}
.skip:focus { top: 12px; }

/* --- shell ------------------------------------------------------------- */

.app { display: flex; height: 100dvh; overflow: hidden; }

.rail {
  width: 232px;
  flex-shrink: 0;
  border-right: 1px solid var(--hairline);
  display: flex;
  flex-direction: column;
  padding: 24px 16px 18px;
}

.rail__brand {
  font-size: var(--text-body); font-weight: var(--weight-bold); letter-spacing: 0.02em;
  padding: 0 10px 26px;
}

.rail__nav { display: flex; flex-direction: column; gap: 3px; }

.rail__item {
  display: flex; align-items: center; gap: 12px;
  height: 42px; padding: 0 10px; border-radius: 10px;
  color: var(--ink-2); font-size: var(--text-body);
}
.rail__item--active { background: var(--accent-soft); color: var(--ink); font-weight: var(--weight-semibold); }
.rail__item--active svg { stroke: var(--accent); }
a.rail__item:hover { background: var(--hairline-soft); color: var(--ink); }

/* A rail item for a screen that does not exist yet is not a link. A dead link on the
   only navigation in the product is worse than an honestly inert one. */
.rail__item--unbuilt { color: var(--ink-3); cursor: default; }
/* One of these two is always hidden — see the note in layout.php. `display: none` and not
   a clip: this is not a label a screen reader should read out either, because on a phone
   the week grid genuinely is not there to go to. */
.rail__item--phone { display: none; }
.rail__item--unbuilt svg { stroke: var(--ink-3); }

.rail__label { flex-grow: 1; }

.rail__badge {
  min-width: 20px; height: 20px; padding: 0 6px; border-radius: 10px;
  background: var(--accent); color: #fff;
  font-size: var(--text-micro); font-weight: var(--weight-semibold);
  display: flex; align-items: center; justify-content: center;
}

.rail__spacer { flex-grow: 1; }

/* A form, not a label: signing out has to be a POST (a GET that ends a session is a GET
   any image tag on any page can fire), and the therapist's own name is deliberately not
   here — the rail is on screen when the laptop is turned around. */
.rail__user {
  display: flex; align-items: center; gap: 11px; width: 100%;
  padding: 9px 10px; border: 0; border-radius: 10px; background: none;
  font: inherit; font-size: var(--text-meta); color: var(--ink-2); cursor: pointer; text-align: left;
}
.rail__user:hover { background: var(--hairline-soft); color: var(--ink); }
.rail__avatar {
  width: 30px; height: 30px; border-radius: 15px;
  background: var(--accent-soft); color: var(--accent-strong);
  font-size: var(--text-caption); font-weight: var(--weight-semibold);
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}

.main { flex-grow: 1; display: flex; flex-direction: column; min-width: 0; }

.topbar {
  display: flex; align-items: center; gap: 14px;
  height: 76px; flex-shrink: 0; padding: 0 26px;
  border-bottom: 1px solid var(--hairline);
}
.topbar__title { font-size: var(--text-title); font-weight: var(--weight-semibold); letter-spacing: -0.005em; }
.topbar__spacer { flex-grow: 1; }
.topbar__nav { display: flex; gap: 7px; }
a.iconbtn { color: var(--ink-2); }

.iconbtn {
  width: 32px; height: 32px; border-radius: 9px;
  border: 1px solid var(--hairline); background: #fff;
  display: flex; align-items: center; justify-content: center;
  color: var(--ink-2); font-size: var(--text-body); cursor: pointer;
}
.iconbtn:hover { background: var(--hairline-soft); }

.pill {
  padding: 7px 15px; border: 1px solid var(--hairline); border-radius: 9px;
  color: var(--ink-2); font-size: var(--text-meta); background: #fff; cursor: pointer;
}
.pill:hover { background: var(--hairline-soft); }

.segmented { display: flex; background: var(--hairline-soft); border-radius: 10px; padding: 3px; gap: 2px; }
.segmented__item { padding: 6px 15px; border-radius: 8px; color: var(--ink-2); font-size: var(--text-meta); }
.segmented__item--active {
  background: #fff; color: var(--ink); font-weight: var(--weight-semibold);
  box-shadow: 0 1px 2px rgba(36, 30, 26, 0.07);
}
/* The switch became three links on 2026-09-03, when Den and Měsíc shipped, so the
   `--unbuilt` segment is gone rather than kept "in case". Links need the same hit area as
   the active span, and a hover that says they are pressable. */
.segmented__item { display: block; text-decoration: none; }
a.segmented__item:hover { background: rgba(255, 255, 255, 0.6); color: var(--ink); }

/* ── Kalendář — měsíc ─────────────────────────────────────────────────────────────────
   A month is a list per day, not a scaled-down week: no hour axis, no absolute
   positioning, so nothing here needs a computed style block the way `.daycol` does.
   Rows share the height available and scroll as one, which keeps a six-row month (a long
   month starting on a Saturday) from squeezing every cell below legibility. */
.monthscroll { flex-grow: 1; min-height: 0; overflow: auto; padding: 0 var(--grid-pad-r) 10px var(--grid-pad-l); }
.month { display: flex; flex-direction: column; min-height: 100%; }
.month__head {
  display: flex; position: sticky; top: 0; z-index: 2; background: #fff;
  border-bottom: 1px solid var(--hairline);
}
.month__weekday {
  flex: 1 1 0; min-width: 0; padding: 10px 0; text-align: center;
  font-size: var(--text-caption); color: var(--ink-3); letter-spacing: 0.04em;
}
.month__week { display: flex; flex: 1 1 0; min-height: 96px; }
.month__cell {
  flex: 1 1 0; min-width: 0; padding: 4px 5px 6px;
  border-left: 1px solid var(--hairline-soft); border-bottom: 1px solid var(--hairline-soft);
  display: flex; flex-direction: column; gap: 2px; overflow: hidden;
}
.month__week:last-child .month__cell { border-bottom: none; }
.month__cell:first-child { border-left: none; }
/* Dimmed, not hidden: a month grid with holes in its corners reads as a rendering fault
   rather than as a calendar. The sessions in them are real and still open. */
.month__cell--outside { background: var(--hairline-soft); }
.month__cell--outside .month__daynum { color: var(--ink-3); }
.month__cell--today { background-color: var(--tint-today); }

.month__daynum {
  align-self: flex-start; min-width: 24px; height: 24px; padding: 0 4px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 12px; font-size: var(--text-meta); color: var(--ink-2);
  font-variant-numeric: tabular-nums; text-decoration: none;
}
.month__daynum:hover { background: var(--hairline); color: var(--ink); }
.month__cell--today .month__daynum { background: var(--accent); color: #fff; font-weight: var(--weight-semibold); }

.month__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 1px; min-height: 0; }
.month__entry {
  display: flex; align-items: center; gap: 5px; min-height: 20px; padding: 1px 4px;
  border-radius: 5px; text-decoration: none; color: var(--ink);
  font-size: var(--text-caption); white-space: nowrap;
}
.month__entry:hover { background: var(--hairline-soft); }
.month__entry--past { opacity: 0.55; }
.month__entry--cancelled { text-decoration: line-through; color: var(--ink-3); }
/* A dot, not a filled bar: six saturated fills stacked in a 96px cell turn the month into
   a colour chart, and the service is a secondary fact at this density. */
.month__dot { width: 7px; height: 7px; border-radius: 4px; flex-shrink: 0; background: var(--svc-neutral); }
.month__dot--modra { background: var(--svc-modra); }
.month__dot--tyrkys { background: var(--svc-tyrkys); }
.month__dot--zelena { background: var(--svc-zelena); }
.month__dot--oliva { background: var(--svc-oliva); }
.month__dot--mauve { background: var(--svc-mauve); }
.month__dot--ruzova { background: var(--svc-ruzova); }
.month__time { color: var(--ink-2); font-variant-numeric: tabular-nums; }
.month__name { overflow: hidden; text-overflow: ellipsis; }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 10px 17px; border-radius: 10px; border: 1px solid var(--hairline);
  background: #fff; color: var(--ink); font: inherit; font-size: var(--text-meta); cursor: pointer;
}
.btn:hover { background: var(--hairline-soft); }
.btn--primary { background: var(--accent-strong); border-color: var(--accent-strong); color: #fff; font-weight: var(--weight-semibold); }
.btn--primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
.btn--quiet { border-color: transparent; color: var(--ink-2); }
.btn[disabled] { color: var(--ink-3); cursor: default; }

/* Opravný doklad (doc05 §14). The screen is a subtraction, so the layout puts the two
   figures on the same visual rail and the difference last — it is the number she has to
   agree with before pressing a button that cannot be undone (F7). */
.corrects-summary { margin: 0; }
.corrects-summary dt { font-size: var(--text-small); color: var(--ink-2); margin-bottom: 4px; }
.corrects-summary dd { margin: 0; font-size: var(--text-body); }
.correction__original { margin: 4px 0 0; display: flex; align-items: baseline; gap: 10px; }
.correction__inputs { display: flex; align-items: center; gap: 10px; }
.correction__amount { margin-left: auto; font-weight: var(--weight-semibold); font-variant-numeric: tabular-nums; }
.correction__difference {
  display: flex; align-items: baseline; gap: 10px; margin: 0 0 6px;
  font-size: var(--text-lead);
}
.correction__difference .correction__amount { font-size: var(--text-title); }

/* --- the front door ----------------------------------------------------- */

/* The one screen a stranger can reach, so it is the one screen with no rail, no badge
   and no name on it. A single centred column: at 380px the form is the whole page on a
   phone and a calm object in the middle of a laptop, which is the same restraint the
   week view is built on (D1) rather than a second design. */

body.auth {
  min-height: 100dvh; margin: 0;
  display: flex; align-items: center; justify-content: center;
  padding: 24px; background: var(--tint-today);
}

.auth__card {
  width: 100%; max-width: 380px;
  background: #fff; border: 1px solid var(--hairline); border-radius: 16px;
  padding: 32px 30px 30px;
  box-shadow: 0 1px 3px rgba(36, 30, 26, 0.05);
}

.auth__brand {
  margin: 0 0 22px; font-size: var(--text-meta); font-weight: var(--weight-semibold); letter-spacing: 0.01em;
  color: var(--accent-text);
}
.auth__heading { font-size: var(--text-title); font-weight: var(--weight-semibold); letter-spacing: -0.005em; margin: 0 0 8px; }
.auth__lede { font-size: var(--text-meta); color: var(--ink-2); margin: 0 0 12px; line-height: 1.55; }

.auth__actions { margin-top: 22px; }
.btn--block { width: 100%; }

/* A quiet aside under a form — "you will still need your authenticator". Same size as the
   lede above the form and the same ink, because it is still something she has to read;
   what makes it an aside is its position, not a dimmer colour. */
.auth__note { font-size: var(--text-meta); color: var(--ink-2); margin: 18px 0 0; line-height: 1.55; }

/* The secondary links on an auth screen: sign-up, and "forgot password". Quiet by default
   and underlined only on hover, because they must not compete with the primary button
   above them. */
.auth__alt { margin: 18px 0 0; text-align: center; font-size: var(--text-meta); }
.auth__alt a { color: var(--ink-2); text-decoration: none; }
.auth__alt a:hover { color: var(--accent-text); text-decoration: underline; }
.auth__alt a:focus-visible { outline: 2px solid var(--accent-ring); outline-offset: 2px; border-radius: 2px; }

/* Six digits, spaced far enough apart to be read back off a phone held in the other
   hand. Tabular figures so the box does not twitch as it fills. */
.auth__code {
  font-size: var(--text-display); letter-spacing: 0.32em; text-align: center;
  font-variant-numeric: tabular-nums; padding: 12px;
}

.auth__qr {
  margin: 20px 0 16px; display: flex; justify-content: center;
  padding: 14px; border: 1px solid var(--hairline); border-radius: 12px;
}
.auth__qr svg { display: block; }

.auth__secret-label { font-size: var(--text-small); color: var(--ink-3); margin: 0 0 6px; }
.auth__secret {
  margin: 0; padding: 10px 12px; border-radius: 9px; background: var(--hairline-soft);
  font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  /* No `word-break: break-all` — the key is chunked into fours so the line can wrap
     at a space, and a break mid-group is exactly what makes it hard to type by hand. */
  font-size: var(--text-meta); letter-spacing: 0.06em; color: var(--ink); line-height: 1.7;
}

.auth__codes {
  list-style: none; margin: 18px 0; padding: 14px 16px;
  border: 1px solid var(--hairline); border-radius: 12px; background: var(--hairline-soft);
  display: grid; grid-template-columns: 1fr 1fr; gap: 7px 18px;
  font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  font-size: var(--text-meta); letter-spacing: 0.04em;
}

.auth__escape { margin-top: 16px; text-align: center; }

.auth .flash { margin: 0; max-width: none; }
.auth .field { margin-top: 18px; }

/* --- week grid --------------------------------------------------------- */

/* One scroller for the strip and the grid together. Two would drift apart the moment a
   phone scrolls the grid sideways, and a day strip whose columns no longer sit above the
   days they name is worse than no day strip. */
.weekscroll { flex-grow: 1; min-height: 0; display: flex; flex-direction: column; overflow: auto; }

.daystrip {
  flex-shrink: 0; border-bottom: 1px solid var(--hairline);
  position: sticky; top: 0; z-index: 2; background: #fff;
  width: max-content; min-width: 100%;
}
.daystrip__row {
  display: flex; height: 68px;
  padding-left: calc(var(--grid-pad-l) + var(--gutter-w));
  padding-right: var(--grid-pad-r);
}
/* The transparent 1px left border is not decoration: it makes each strip cell exactly as
   wide as the bordered day column beneath it. Without it the columns drift apart by a
   pixel a day across the week. */
.daystrip__cell {
  flex: 1 1 0; min-width: 0; border-left: 1px solid transparent;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
}
.daystrip__name { font-size: var(--text-caption); color: var(--ink-3); letter-spacing: 0.04em; }
.daystrip__num { height: 34px; display: flex; align-items: center; font-size: var(--text-lead); font-weight: var(--weight-medium); }
.daystrip__cell--today .daystrip__name { color: var(--accent-text); font-weight: var(--weight-semibold); }
.daystrip__cell--today .daystrip__num {
  width: 34px; border-radius: 17px; background: var(--accent); color: #fff;
  justify-content: center; font-weight: var(--weight-semibold);
}

.grid {
  display: flex; flex-grow: 1; min-height: 0;
  padding: 10px var(--grid-pad-r) 0 var(--grid-pad-l);
  width: max-content; min-width: 100%;
}

.gutter { width: var(--gutter-w); flex-shrink: 0; position: relative; }
.gutter__label {
  position: absolute; right: 14px;
  font-size: var(--text-micro); color: var(--ink-3); font-variant-numeric: tabular-nums;
  transform: translateY(-7px);
}

.daycol {
  flex: 1 1 0; min-width: 0; position: relative;
  border-left: 1px solid var(--hairline-soft);
  background-image: repeating-linear-gradient(
    to bottom,
    transparent 0 calc(var(--row-h) / 2 - 1px),
    var(--hairline-soft) calc(var(--row-h) / 2 - 1px) calc(var(--row-h) / 2),
    transparent calc(var(--row-h) / 2) calc(var(--row-h) - 1px),
    var(--hairline) calc(var(--row-h) - 1px) var(--row-h));
}
.daycol--today { background-color: var(--tint-today); }

/* C5's click target. Invisible until pointed at — the grid must read as a schedule, not
   as a hundred buttons — but a real link all the same, so a keyboard can reach every slot
   and nothing here needs JavaScript. */
.slot {
  position: absolute; left: 0; right: 0; display: block; z-index: 0;
  top: var(--top, 0px); height: var(--h, 0px);
}
.slot:hover { background: var(--accent-soft); opacity: 0.55; }
.slot:focus-visible { outline-offset: -2px; }

.block {
  position: absolute; left: 5px; right: 5px; z-index: 1;
  /* Set per block by the nonce'd rules the request generates — see
     src/Http/WeekGeometry.php for why the geometry is not an inline style attribute. */
  top: var(--top, 0px); height: var(--h, var(--row-h));
  border-radius: 9px; overflow: hidden; padding: 7px 11px;
  background: var(--svc-neutral); color: inherit; display: block;
}
.block:hover { box-shadow: 0 2px 8px rgba(36, 30, 26, 0.10); }
.block--modra { background: var(--svc-modra); }
.block--tyrkys { background: var(--svc-tyrkys); }
.block--zelena { background: var(--svc-zelena); }
.block--oliva { background: var(--svc-oliva); }
.block--mauve { background: var(--svc-mauve); }
.block--ruzova { background: var(--svc-ruzova); }
.block--past { opacity: 0.5; }
.block--cancelled { background: repeating-linear-gradient(135deg, var(--hairline-soft) 0 6px, #fff 6px 12px); opacity: 0.75; }
.block--cancelled .block__name { text-decoration: line-through; }

.block__time, .block__name, .block__service { display: block; }
.block__time { font-size: var(--text-micro); color: var(--ink-2); letter-spacing: 0.01em; line-height: 1.3; font-variant-numeric: tabular-nums; }
.block__name { font-size: var(--text-small); font-weight: var(--weight-semibold); color: var(--ink); line-height: 1.32; letter-spacing: -0.004em; margin-top: 1px; }
.block__service { font-size: var(--text-caption); color: var(--ink-2); line-height: 1.3; margin-top: 1px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.block__top { display: flex; align-items: center; gap: 5px; min-width: 0; }
.block__top .block__time { flex-shrink: 0; }
.block__top .chip { overflow: hidden; text-overflow: ellipsis; }

.chip {
  font-size: var(--text-micro); color: var(--ink-2);
  background: rgba(255, 255, 255, 0.66);
  border: 1px solid rgba(36, 30, 26, 0.07);
  border-radius: 5px; padding: 1.5px 6px; white-space: nowrap; line-height: 1.35;
}

.nowline { position: absolute; left: -4px; right: 0; top: var(--top, 0px); height: 0; z-index: 3; }
.nowline__dot { position: absolute; left: 0; top: -3.5px; width: 7px; height: 7px; border-radius: 4px; background: var(--accent); }
.nowline__rule { position: absolute; left: 5px; right: 0; top: 0; height: 1.5px; background: var(--accent); }

.grid__empty { padding: 40px 0 0 20px; color: var(--ink-3); font-size: var(--text-meta); }

/* --- session panel ----------------------------------------------------- */

.panel-page { flex-grow: 1; overflow-y: auto; padding: 34px 26px 60px; }

.panel {
  max-width: 520px; margin: 0 auto;
  border: 1px solid var(--hairline); border-radius: 14px; padding: 24px 26px;
}
.panel__kicker { font-size: var(--text-micro); font-weight: var(--weight-bold); letter-spacing: 0.09em; text-transform: uppercase; color: var(--ink-3); }
.panel__name { font-size: var(--text-display); font-weight: var(--weight-semibold); letter-spacing: -0.01em; margin: 10px 0 0; }
.panel__when { font-size: var(--text-body); color: var(--ink-2); margin: 6px 0 0; }
.panel__what { font-size: var(--text-body); color: var(--ink-2); margin: 3px 0 0; }
.panel__rule { border: 0; border-top: 1px solid var(--hairline); margin: 20px 0; }

.status { display: flex; align-items: center; gap: 9px; font-size: var(--text-body); }
.status__dot { width: 9px; height: 9px; border-radius: 5px; background: var(--ink-3); flex-shrink: 0; }
.status--attended .status__dot { background: var(--accent); }
.status--cancelled .status__dot { background: var(--hairline); border: 1px solid var(--ink-3); }

.panel__doc { font-size: var(--text-body); margin: 14px 0 0; }
.panel__doc-state { color: var(--ink-2); font-size: var(--text-meta); }
/* Whether the invoice reached the client (F37). Same weight as the paid/unpaid line
   beside it: it is a fact about the document, not an alert. */
.panel__doc-email { color: var(--ink-2); font-size: var(--text-meta); }

.panel__actions { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.panel__actions--secondary { margin-top: 14px; }
.panel__actions form { display: contents; }

/* `Nová faktura` and `Opravný doklad`. Both render as the whole of `.main` rather than
   inside a `.panel-page`, and `.panel__form` was never written — so they had no measure,
   no page padding, and (because `.app` is `height: 100dvh; overflow: hidden` and `.main`
   is not a scroller) no way to scroll to their own buttons. The templates now wrap in
   `.panel-page`, which supplies the padding and the scroll container; this supplies the
   measure. 720px rather than the 620px of `.match` and `.settings__body > *` because
   these two are the only forms carrying a four-column line editor — doc05 §12 draws the
   rules spanning a working surface, not a settings column. */
.panel__form { max-width: 720px; }
.panel__form .panel__actions { margin-top: 24px; }

/* Same omission, one screen over: `Příjem z platforem` (and `Zdroje příjmů`, which is
   wrapped in it) carried a class that no rule matched. That one is inside a
   `.panel-page`, so it scrolled — it was only ever the wrong width. */
.income { max-width: 620px; }
.income .panel__actions { margin-top: 24px; }

.panel__note { font-size: var(--text-small); color: var(--ink-2); margin: 14px 0 0; line-height: 1.5; }

.field { margin: 16px 0 0; padding: 0; border: 0; }
.field__label { display: block; font-size: var(--text-small); color: var(--ink-2); margin-bottom: 6px; padding: 0; }
.field__input {
  width: 100%; padding: 10px 12px; border: 1px solid var(--hairline); border-radius: 9px;
  font: inherit; font-size: var(--text-body); color: var(--ink); background: #fff;
}
.field__input:focus { border-color: var(--accent-ring); }
.field__input--short { width: 120px; }
.field__hint { font-size: var(--text-small); color: var(--ink-3); margin: 6px 0 0; }
.field__inline { display: flex; align-items: center; gap: 10px; margin-top: 10px; }
.field__inline .field__hint { margin: 0; }

.choice { display: flex; align-items: center; gap: 9px; padding: 6px 0; font-size: var(--text-body); }
.choice input { accent-color: var(--accent); width: 16px; height: 16px; }

/* The client combobox. Present in the markup whether or not the script runs: without it
   the list simply stays hidden and the typed name is resolved on the server. */
.results {
  list-style: none; margin: 6px 0 0; padding: 4px;
  border: 1px solid var(--hairline); border-radius: 9px;
  box-shadow: 0 4px 14px rgba(36, 30, 26, 0.10); background: #fff;
  max-height: 220px; overflow-y: auto;
}
.results[hidden] { display: none; }
.results li { padding: 9px 10px; border-radius: 7px; font-size: var(--text-body); cursor: pointer; }
.results li[aria-selected="true"], .results li:hover { background: var(--accent-soft); }

.changes { list-style: none; margin: 12px 0 0; padding: 0; }
.changes li { display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px; padding: 5px 0; font-size: var(--text-body); }
.changes__label { color: var(--ink-2); min-width: 92px; }
.changes__from { color: var(--ink-3); text-decoration: line-through; }
.changes__arrow { color: var(--ink-3); }
.changes__to { font-weight: var(--weight-semibold); }

.choice--scope { align-items: flex-start; padding: 9px 0; }
.choice--scope input { margin-top: 3px; }
.choice__body { display: flex; flex-direction: column; gap: 2px; }
.choice__meta { font-size: var(--text-small); color: var(--ink-3); }
/* U9's line. Accent, not red: nothing has gone wrong — she is being told what will not
   move, before she picks, rather than discovering it three months later. */
.choice__skipped { font-size: var(--text-small); color: var(--accent-text); }

.flash--error { border-color: var(--accent); }

.flash {
  max-width: 520px; margin: 0 auto 18px;
  border: 1px solid var(--accent-ring); background: var(--accent-soft);
  border-radius: 10px; padding: 11px 14px; font-size: var(--text-meta); color: var(--ink);
}

/* --- settings ---------------------------------------------------------- */

.settings { display: flex; flex-grow: 1; min-height: 0; overflow: hidden; }

.subnav {
  width: 210px; flex-shrink: 0; padding: 22px 12px;
  border-right: 1px solid var(--hairline);
  display: flex; flex-direction: column; gap: 2px;
}
.subnav__item { padding: 9px 12px; border-radius: 9px; color: var(--ink-2); font-size: var(--text-meta); }
a.subnav__item:hover { background: var(--hairline-soft); color: var(--ink); }
.subnav__item--active { background: var(--accent-soft); color: var(--ink); font-weight: var(--weight-semibold); }
.subnav__item--unbuilt { color: var(--ink-3); cursor: default; }

/* One column width for the whole tab, so the flash, the heading and the fields share a
   left edge. Capping the children instead let a centred flash drift right of the form. */
.settings__body { flex-grow: 1; overflow-y: auto; padding: 28px 30px 60px; }
.settings__body > * { max-width: 620px; }
.settings .flash { margin-left: 0; margin-right: 0; max-width: none; }
.settings__heading { font-size: var(--text-title); font-weight: var(--weight-semibold); letter-spacing: -0.005em; margin: 0 0 18px; }
.settings__subheading { font-size: var(--text-body); font-weight: var(--weight-semibold); margin: 22px 0 6px; }

.field__input--error { border-color: var(--accent); }
.field__error { font-size: var(--text-small); color: var(--accent-text); margin: 6px 0 0; }

.daypicker { display: flex; flex-wrap: wrap; gap: 14px; }
/* 2.5.8 (WCAG 2.2 AA): 24×24 is the floor for a pointer target, and these were 16×16. */
.daypicker__day, .swatchpick { display: flex; align-items: center; gap: 7px; font-size: var(--text-meta); min-height: 24px; }
.daypicker input, .swatchpick input { accent-color: var(--accent); width: 24px; height: 24px; }

.pricelist { list-style: none; margin: 0 0 4px; padding: 0; }
.pricelist__item {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 12px 0; border-bottom: 1px solid var(--hairline-soft);
}
/*
 * **Not `opacity`.** `opacity: 0.55` composited this row's 16px text down to 3.75:1 and its
 * 14px label to 2.14:1 against white — a 1.4.3 failure on four screens at once (a
 * deactivated service, an ended client, a voided document, a withdrawn consent), and every
 * one of them is a row the therapist still has to read. Opacity is the wrong tool for
 * "past": it dims the meaning and the contrast together, and only one of those was
 * intended. `--ink-2` is 6.0:1 and the line-through says the same thing without costing
 * legibility.
 */
.pricelist__item--retired .pricelist__name,
.pricelist__item--retired .pricelist__label,
.pricelist__item--retired .pricelist__meta { color: var(--ink-2); }
.pricelist__item--retired .pricelist__name { text-decoration: line-through; }
.pricelist__swatch { width: 22px; height: 22px; border-radius: 6px; background: var(--svc-neutral); flex-shrink: 0; }
.pricelist__swatch--modra { background: var(--svc-modra); }
.pricelist__swatch--tyrkys { background: var(--svc-tyrkys); }
.pricelist__swatch--zelena { background: var(--svc-zelena); }
.pricelist__swatch--oliva { background: var(--svc-oliva); }
.pricelist__swatch--mauve { background: var(--svc-mauve); }
.pricelist__swatch--ruzova { background: var(--svc-ruzova); }
.pricelist__body { display: flex; flex-direction: column; gap: 1px; flex-grow: 1; min-width: 160px; }
.pricelist__name { font-size: var(--text-body); font-weight: var(--weight-semibold); }
/* F11 lives on this line: what the client sees is not what she calls it. */
.pricelist__label { font-size: var(--text-small); color: var(--ink-3); }
.pricelist__meta { font-size: var(--text-small); color: var(--ink-2); font-variant-numeric: tabular-nums; }
.pricelist__actions { display: flex; gap: 2px; align-items: center; }
.pricelist__actions form { display: contents; }

.numbering { display: flex; align-items: center; gap: 12px; }
.numbering__preview { font-size: var(--text-body); color: var(--ink-2); font-variant-numeric: tabular-nums; }

/* --- narrow screens ---------------------------------------------------- */

/* PS4 revised: the phone is the design target for the *payment* screen. The week grid is
   a desktop screen that must not break on a phone, which is a different promise — the
   rail folds into a top bar and the grid scrolls sideways rather than crushing five
   columns into 390px. The phone's own agenda list (doc05 §6) is not built yet. */
/* --- Peníze (doc05 §10, §11) --------------------------------------------- */

/* M10: the two queues carry the same visual weight on purpose. They are one job done
   once a week, and making either secondary is how the other stops getting done. */
.money { padding: 24px 28px 44px; display: flex; flex-direction: column; gap: 26px; }
.money__queues { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; align-items: start; }

.queue { border: 1px solid var(--hairline); border-radius: 12px; padding: 16px 18px; background: #fff; }
.queue__title {
  display: flex; align-items: center; gap: 8px; margin: 0 0 10px;
  font-size: var(--text-caption); font-weight: var(--weight-semibold); letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--ink-2);
}
.queue__count {
  min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px;
  background: var(--hairline-soft); color: var(--ink-2);
  font-size: var(--text-micro); letter-spacing: 0; display: inline-flex; align-items: center; justify-content: center;
}
.queue__empty { margin: 0; color: var(--ink-3); font-size: var(--text-meta); }
.queue__list { list-style: none; margin: 0; padding: 0; }
.queue__item { padding: 11px 0; border-top: 1px solid var(--hairline-soft); }
.queue__item:first-child { border-top: 0; }
.queue__item--row { display: flex; align-items: baseline; gap: 12px; }
.queue__head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.queue__date, .queue__number { font-variant-numeric: tabular-nums; }
.queue__number { flex-grow: 1; }
.queue__amount { font-weight: var(--weight-semibold); font-variant-numeric: tabular-nums; }
.queue__meta { font-size: var(--text-small); color: var(--ink-2); margin: 2px 0 8px; }
/* Overdue is a fact, not an alarm — the accent, not red. A list of four normal invoices
   should not read as four problems (R8). */
.queue__overdue { font-size: var(--text-small); color: var(--accent-text); font-variant-numeric: tabular-nums; }

.documents__title {
  margin: 0 0 8px; font-size: var(--text-caption); font-weight: var(--weight-semibold);
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-2);
}
.documents__table { width: 100%; border-collapse: collapse; font-size: var(--text-meta); }
.documents__table th {
  text-align: left; padding: 0 10px 8px 0; font-weight: var(--weight-semibold); font-size: var(--text-caption);
  color: var(--ink-3); border-bottom: 1px solid var(--hairline);
}
.documents__table td { padding: 9px 10px 9px 0; border-bottom: 1px solid var(--hairline-soft); }
.documents__num { text-align: right; font-variant-numeric: tabular-nums; }
.documents__erased { color: var(--ink-3); font-style: italic; }

/* R8: a figure, not a gauge. No ring, no target, no trend arrow. */
.money__turnover { margin: 0; padding-top: 6px; color: var(--ink-2); font-variant-numeric: tabular-nums; }

.match { max-width: 620px; display: flex; flex-direction: column; gap: 18px; }
.match__facts { border: 1px solid var(--hairline); border-radius: 12px; padding: 16px 18px; }
.match__head { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; }
.match__amount { font-size: var(--text-title); font-variant-numeric: tabular-nums; }
.match__meta { font-size: var(--text-meta); color: var(--ink-2); margin-top: 3px; }
.match__choices { border: 0; margin: 0; padding: 0; }
.match__legend {
  padding: 0; margin-bottom: 8px; font-size: var(--text-caption); font-weight: var(--weight-semibold);
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-2);
}
.match__choice {
  display: flex; gap: 11px; align-items: flex-start;
  padding: 12px 14px; border: 1px solid var(--hairline); border-radius: 10px;
  margin-bottom: 8px; cursor: pointer;
}
.match__choice:hover { background: var(--hairline-soft); }
.match__choice:has(input:checked) { border-color: var(--accent); }
.match__choice-body { flex-grow: 1; display: flex; flex-direction: column; gap: 3px; }
.match__choice-head { display: flex; justify-content: space-between; gap: 12px; font-weight: var(--weight-semibold); font-variant-numeric: tabular-nums; }
/* The signals line is the content of this screen, not a caption. A score with no reasons
   is a number she can only trust blindly or ignore (M9). */
.match__signals { font-size: var(--text-small); color: var(--ink-2); }
.match__actions { display: flex; justify-content: flex-end; gap: 10px; }

/* --- Dnes, the phone agenda (doc05 §21) -------------------------------------
   Built mobile-first and then held back on a desktop, which is the opposite of the rest
   of this file and deliberate: D9 says this screen is "not a squeezed desktop", so the
   phone is the size it is designed at and the wide window is the adaptation. */
.agenda { padding: 18px 16px 28px; max-width: 640px; }
.agenda__date { font-size: var(--text-title); font-weight: var(--weight-semibold); letter-spacing: -0.005em; margin: 0 0 18px; }

.agenda__list { list-style: none; margin: 0; padding: 0; }
.agenda__row {
  display: flex; align-items: flex-start; gap: 14px; padding: 14px 0;
  border-bottom: 1px solid var(--hairline-soft);
}
.agenda__row:last-child { border-bottom: 0; }

/* 44px is the smallest thing a thumb hits reliably, and both of a row's two targets are
   sized for it rather than for a cursor (G13). */
.agenda__time {
  flex: 0 0 auto; min-width: 54px; min-height: 44px;
  display: flex; align-items: flex-start; padding-top: 1px;
  font-size: var(--text-lead); font-weight: var(--weight-medium);
  color: var(--ink); font-variant-numeric: tabular-nums;
}
.agenda__who { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex-grow: 1; }
.agenda__name {
  min-height: 24px; color: var(--ink);
  font-size: var(--text-body); font-weight: var(--weight-semibold);
}
.agenda__name:hover { color: var(--accent-text); }
.agenda__meta { font-size: var(--text-small); color: var(--ink-2); }

.agenda__row--past .agenda__time, .agenda__row--past .agenda__name { color: var(--ink-2); }
.agenda__row--cancelled .agenda__name { text-decoration: line-through; }
.agenda__row--cancelled { color: var(--ink-3); }

/* The row's own money, stated before the button so the tap is never blind. */
.agenda__pay { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 6px; }
.agenda__owed { font-size: var(--text-small); color: var(--accent-text); font-variant-numeric: tabular-nums; }
.agenda__paid-btn { min-height: 40px; border-color: var(--hairline); color: var(--ink-2); }

.agenda__free {
  margin: 18px 0 0; padding-top: 14px; border-top: 1px solid var(--hairline);
  font-size: var(--text-small); color: var(--ink-3); text-align: center;
}
.agenda__empty { margin: 0; color: var(--ink-2); }

.agenda__nav {
  display: flex; justify-content: space-between; gap: 12px;
  margin-top: 26px; padding-top: 14px; border-top: 1px solid var(--hairline);
  font-size: var(--text-meta);
}
.agenda__nav a { color: var(--ink-2); min-height: 44px; display: flex; align-items: center; }
.agenda__nav a:hover { color: var(--accent-text); }

@media (max-width: 900px) {
  .app { flex-direction: column; height: auto; min-height: 100dvh; overflow: visible; }

  /* **A bottom tab bar, not a scrolling strip of icons** (doc05 §21). It was a horizontal
     rail across the top, which put the product's whole navigation where a thumb cannot
     reach it on a phone held one-handed — the position every mobile OS reserves for
     chrome, and the one this app's own wireframe draws it in. `env(safe-area-inset-bottom)`
     keeps it clear of the home indicator; the padding on `.main` keeps the last row of a
     list from hiding underneath it. */
  .rail {
    position: fixed; bottom: 0; left: 0; right: 0; z-index: 10;
    width: auto; flex-direction: row; align-items: center; justify-content: space-around;
    gap: 2px; padding: 6px 8px calc(6px + env(safe-area-inset-bottom));
    border-right: 0; border-top: 1px solid var(--hairline); background: #fff;
  }
  .main { padding-bottom: 72px; }
  .rail__item--desk { display: none; }
  .rail__item--phone { display: flex; }
  /* The brand is chrome, and chrome is what a phone has least room for. */
  .rail__brand { display: none; }
  .rail__nav { flex-direction: row; gap: 2px; flex-grow: 1; justify-content: space-around; }
  /* Icon over label, and at least 48px tall: the tab bar is the one place in this app
     where every target is a thumb's rather than a cursor's. */
  .rail__item {
    height: auto; min-height: 48px; min-width: 48px; padding: 5px 8px;
    flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  }
  /* **Labels are visible in the tab bar**, which is what doc05 §21 draws — `Dnes` and
     `Klienti` are words on that wireframe, not icons. They were clipped back when the rail
     was a cramped horizontal strip across the top; a bottom bar has the room, and an icon
     nobody can name is a worse accessibility outcome than a small word (G13). Sign-out
     stays clipped: it is the one control here that is not a destination, and labelling it
     would give the bar a fifth word competing with four navigational ones. */
  .rail__label {
    flex-grow: 0; font-size: var(--text-micro); line-height: 1.1;
    max-width: 72px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .rail__signout {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip-path: inset(50%); white-space: nowrap;
  }
  .rail__item, .rail__user { position: relative; }
  /* With the label under the icon there is no line to sit on the end of, so the badge
     becomes a corner marker on the icon itself — where every phone puts one. */
  .rail__badge { position: absolute; top: 2px; right: 4px; }
  .rail__user { width: auto; padding: 4px; }
  .rail__spacer { flex-grow: 1; }
  .topbar { height: auto; flex-wrap: wrap; gap: 10px; padding: 12px 14px; }
  /* The agenda states its own date as the page heading; the bar would say it twice. */
  .topbar__title--phone-hidden {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip-path: inset(50%); white-space: nowrap;
  }
  .agenda { padding: 16px 14px 24px; }
  .daycol, .daystrip__cell { min-width: 132px; }
  .panel-page { padding: 20px 14px 40px; }
  .settings { flex-direction: column; overflow: visible; }
  .subnav {
    width: auto; flex-direction: row; overflow-x: auto; padding: 10px 12px;
    border-right: 0; border-bottom: 1px solid var(--hairline);
  }
  .subnav__item { white-space: nowrap; }
  .settings__body { padding: 20px 14px 40px; }
  .money { padding: 20px 14px 40px; }
  /* The two queues stack rather than shrink: a 160px-wide amount column is not a queue. */
  .money__queues { grid-template-columns: 1fr; }
  .documents__table { display: block; overflow-x: auto; }
  .panel { padding: 20px 18px; }
}

/* The correction link under a document number in the ledger. Quiet on purpose: issuing one
   is rare and irreversible, so it should be findable rather than prominent (doc05 §14). */
/*
 * 2.5.8, the other half. A document number inside a row is an inline link whose height is
 * the line-height around it — 22-23px, one pixel short, and covered by the standard's
 * inline exception either way. Vertical padding on an inline element grows the hit box
 * without touching the line box, so the target clears 24px and no row moves.
 */
.pricelist__name a[href$=".pdf"],
.documents__table a[href$=".pdf"] { padding: 3px 0; }

/*
 * 2.5.8: a row action is not an inline link in a sentence, so the exception does not cover
 * it — this was 20px tall. The padding grows the target without moving the text, which is
 * what the row's rhythm depends on.
 */
.documents__correct {
  display: inline-block; font-size: var(--text-caption); color: var(--ink-3);
  margin-top: 2px; padding: 2px 0; min-height: 24px; line-height: 20px;
}
.documents__correct:hover { color: var(--accent-text); }

/* Peníze — the `+ Nový doklad` pair (doc05 §10) beside the documents heading. */
.documents__head { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.documents__actions { display: flex; gap: 8px; }

/* Nová faktura's line editor (doc05 §12). A real table because the columns have to line up
   across rows, and the header is what says which number goes where. */
.lines-editor { width: 100%; border-collapse: collapse; margin-top: 4px; }
.lines-editor th {
  text-align: left; padding: 0 8px 6px 0; font-size: var(--text-caption);
  font-weight: var(--weight-semibold); color: var(--ink-3);
}
.lines-editor .lines-editor__num { width: 120px; }
.lines-editor td { padding: 0 8px 8px 0; vertical-align: top; }
.lines-editor td:last-child, .lines-editor th:last-child { padding-right: 0; }

/* --- remember-this-browser, and the device list it obliges ---------------
 *
 * The checkbox sits on the login screen and the list behind Nastavení →
 * Zabezpečení; they are one feature (SEC2) and share the 48px touch target the
 * phone tab bar established. */

.field--check { display: flex; align-items: flex-start; gap: 10px; margin: 18px 0 4px; }
.field__check { width: 24px; height: 24px; margin: 0; accent-color: var(--accent-strong); flex-shrink: 0; } /* 2.5.8 */
.field__check-label { font-size: var(--text-body); color: var(--ink); cursor: pointer; }
.field__check-label .field__hint { margin: 2px 0 0; }

.devices { list-style: none; margin: 18px 0 0; padding: 0; }

.devices__row {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 14px 0; border-bottom: 1px solid var(--hairline-soft);
}
.devices__row:last-child { border-bottom: 0; }

.devices__what { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px; min-width: 0; }
.devices__name { font-size: var(--text-body); color: var(--ink); }
.devices__when { flex-basis: 100%; font-size: var(--text-small); color: var(--ink-3); }

/* The current device is marked by a chip, not by colour: "which line is this
 * browser" has to survive being read on a phone in a hurry, and a tint that
 * means something is a tint somebody has to have been told about. */
.devices__row .btn { flex-shrink: 0; min-height: 44px; }

/* --- Data a export (doc05 §20) ------------------------------------------ */

.period { display: flex; align-items: center; gap: 10px; margin: 18px 0 10px; }
.period .field__label { margin: 0; }

.settings__subheading {
  font-size: var(--text-lead); font-weight: var(--weight-semibold);
  color: var(--ink); margin: 0 0 6px;
}

.panel__actions--left { justify-content: flex-start; gap: 10px; }

/* An honestly disabled button, the same idea as the rail's unbuilt rows: it says the
 * feature is named and not yet here, rather than leaving a gap the reader has to
 * interpret. Not a <button disabled>, because a disabled control is skipped by the
 * keyboard and its title never gets read. */
/*
 * A real `<button disabled>`, not a `<span aria-disabled>` — the accessibility tree used to
 * report these as `role=text`, so a screen reader read "XLSX" as a word in a sentence with
 * nothing to say it was a control, let alone an unavailable one, and the `title` explaining
 * why sat on a non-interactive element that is not reliably announced. Being genuinely
 * disabled also settles the contrast question: 1.4.3 exempts an inactive control, which the
 * 4.24:1 this used to render at did not qualify for while it was a span.
 */
.btn--unbuilt[disabled] {
  color: var(--ink-3); border-color: var(--hairline);
  background: var(--hairline-soft); cursor: default;
}

.field__hint--list { margin-top: 14px; }

/* A caveat the reader must not skim past, without shouting: the accent, not red — R8
 * keeps red for things that are wrong, and this figure is not wrong, it is incomplete. */
.field__hint--caution { color: var(--accent-text); }
