/* Design tokens — look-and-feel-requirements.md §2–§4.
   Nothing here is Bosch IP: the deck's typeface, logo and supergraphic gradient
   are deliberately not shipped (L&F §0). */

:root {
  /* The four brand values, sampled from `images/KudeDaUcha — logo.pdf`. Nothing
     below invents a fifth: every grey is a tint of the ink, every green a tint
     of the mark's open cell. Change these and the whole site follows. */
  --brand-ink: #14191F;
  --brand-green: #0E7955;
  --brand-green-bright: #4ADE80; /* the mark's green on ink — unreadable on paper */
  --brand-paper: #F4F4F2;

  --bg-page: var(--brand-paper);
  --bg-surface: #FFFFFF;
  --bg-sunken: #ECEBE8;
  --bg-contrast: var(--brand-ink);
  /* A tint of the ink, not a new grey: the disclaimer band should read as an
     aside, not as the darkest thing on the page. */
  --bg-contrast-soft: #3A4149;

  --fg-major: var(--brand-ink);
  --fg-minor: #4A5158;
  /* 4.5:1 on --bg-page, not just on white: most muted text sits on the page,
     and the old value only cleared AA against a surface it rarely touches. */
  --fg-muted: #6A7077;
  --fg-on-contrast: #FFFFFF;

  --border-subtle: #E4E4E2; /* the outlined app-tile's border in the artwork */
  --border-strong: #C6C7C3;

  --accent: var(--brand-green);
  --accent-hover: #0A5C41;
  --accent-on-dark: var(--brand-green-bright);
  --accent-tint: #E3F1EA;

  /* Availability is the brand green by design: the logo is five closed cells
     and one open one, which is the same statement as „има свободно място".
     Deliberately one shade deeper than --accent so a places count and a link
     never read as the same kind of thing. */
  --avail-yes: #0A6647;
  --avail-yes-bg: #E3F1EA;
  --avail-none: #6A7077;
  /* Amber at 12px uppercase has to clear 4.5:1 — the bright signal orange is a
     fill colour, not a text colour. */
  --signal-warning: #9A5C00;

  /* Information → availability. The gradient is the product's semantic axis,
     not decoration (L&F §3.4) — now graphite → green, the two brand values. */
  --accent-rule: linear-gradient(90deg, #14191F 0%, var(--brand-green) 55%, var(--brand-green-bright) 100%);
  --accent-rule-h: 4px;

  --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px;
  --sp-5: 24px; --sp-6: 32px; --sp-7: 48px; --sp-8: 64px; --sp-9: 96px;

  --container: 1120px;
  --container-sm: 720px;
  --gutter: clamp(16px, 4vw, 32px);

  --radius: 8px;
  --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;

  --dur-fast: 140ms;
  --dur-base: 240ms;
  --ease-default: cubic-bezier(0.4, 0, 0.2, 1);
}

/* Inter's Bulgarian Cyrillic localised forms (де, ге, пе, бе…) only activate
   with lang="bg" AND the `locl` feature. Without both, Bulgarian text renders
   in Russian shapes and reads as foreign to a native eye. */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/fonts/inter-cyrillic.woff2') format('woff2');
  /* Exactly the range of Google's `cyrillic` subset — scripts/fonts.ts writes
     that file and fails if this line drifts from it. Declaring less than the
     file covers silently sends some characters to the fallback font. */
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/fonts/inter-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;
}

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

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

body {
  margin: 0;
  background: var(--bg-page);
  color: var(--fg-major);
  font-family: var(--font-sans);
  font-size: 15px;
  line-height: 1.55;
  font-feature-settings: 'locl' 1, 'cv05' 1;
  -webkit-font-smoothing: antialiased;
}

/*
 * Headings run about a third smaller than a marketing scale would. On this site
 * the largest thing on a page should be the number of свободни места, not the
 * name of the page a parent already knows they opened — `.places-count` at 24px
 * now outranks every heading but the h1, which is the intended order.
 *
 * h3 comes down less (20 → 17) only to stay under h2; shrinking card titles by
 * a third would push them below the 15px body text they head.
 */
h1, h2, h3, h4 { margin: 0; line-height: 1.25; letter-spacing: -0.004em; font-weight: 700; }
/* Only h1 still scales with the viewport; at 19px and 17px the other two fit any
   screen, and clamping them made h2 fall *below* h3 on a phone. */
h1 { font-size: clamp(21px, 3.2vw, 27px); }
h2 { font-size: 19px; }
h3 { font-size: 17px; }
p { margin: 0; }

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

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

.skip-link {
  position: absolute; left: -9999px; top: var(--sp-2);
  background: var(--bg-surface); padding: var(--sp-3) var(--sp-4);
  border-radius: var(--radius); z-index: 100;
}
.skip-link:focus { left: var(--sp-4); }

/* Announced by a screen reader, not drawn: search labels, table captions. The
   class was already in the markup but had no rule, so the labels were visible. */
.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap; margin: -1px; padding: 0; border: 0;
}

/* ── Brand mark ──────────────────────────────────────────────────────────── */

/*
 * The mark is drawn inline (components/logo.tsx) rather than loaded as an
 * image, so it inherits colour from whatever it sits on: ink on paper, paper on
 * ink, and the bright green only where the background is dark enough for it.
 */
.mark { display: block; width: auto; }
.mark .mark-cell { fill: currentColor; }
.mark .mark-open { fill: var(--accent); }

/* Sized off the lockup's own font-size, so one `font-size` override rescales
   the mark and the wordmark together and keeps their proportion. */
.logo { display: inline-flex; align-items: center; gap: 0.55em; font-size: 17px; color: var(--fg-major); }
.logo:hover { text-decoration: none; }
.logo .mark { height: 0.86em; }
.logo-text { font-weight: 700; letter-spacing: -0.01em; white-space: nowrap; }
/* The „?" is part of the wordmark, not punctuation the page happens to end on. */
.logo-q { color: var(--accent); }

/* ── Structure ───────────────────────────────────────────────────────────── */

.accent-rule {
  height: var(--accent-rule-h);
  background: var(--accent-rule);
}

.container { max-width: var(--container); margin: 0 auto; padding-inline: var(--gutter); }
.container-sm { max-width: var(--container-sm); margin: 0 auto; padding-inline: var(--gutter); }

.site-header {
  background: var(--bg-surface);
  border-bottom: 1px solid var(--border-subtle);
  position: sticky; top: 0; z-index: 50;
}
.site-header .inner {
  display: flex; align-items: center; gap: var(--sp-5);
  min-height: 56px;
}
/* Text for screen readers only. */
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
/* Count of new feedback on the „Админ" link (routes/admin.tsx, U-20). */
.nav-badge {
  display: inline-block; min-width: 18px; padding: 0 5px; margin-left: 4px;
  border-radius: 9px; background: var(--accent); color: #fff;
  font-size: 11px; font-weight: 700; line-height: 18px; text-align: center; vertical-align: 1px;
}
.site-nav { margin-left: auto; display: flex; flex-wrap: wrap; justify-content: flex-end; gap: var(--sp-3) var(--sp-4); align-items: center; font-size: 14px; }

main { padding-block: var(--sp-6) var(--sp-8); min-height: 60vh; }

.site-footer {
  background: var(--bg-surface);
  border-top: 1px solid var(--border-subtle);
  padding-block: var(--sp-6);
  font-size: 13px; color: var(--fg-muted);
}
.site-footer nav { display: flex; flex-wrap: wrap; gap: var(--sp-4); margin-top: var(--sp-3); }
.site-footer .logo { font-size: 15px; margin-bottom: var(--sp-3); }
.site-footer .site-contact { margin-top: var(--sp-3); }
/* One click selects the whole address: it is meant to be copied. */
.contact-email { user-select: all; -webkit-user-select: all; font-weight: 500; color: var(--fg-major); }

/* ── Feedback ────────────────────────────────────────────────────────────── */

/* Honeypot (routes/feedback.tsx): off-canvas rather than display:none, since
   some bots skip fields the layout hides. */
.hp { position: absolute; left: -10000px; top: auto; width: 1px; height: 1px; overflow: hidden; }
.choice { display: flex; gap: var(--sp-3); align-items: flex-start; cursor: pointer; }
.choice input { width: auto; min-height: 0; margin-top: 4px; }
.choice .hint { display: block; font-size: 13px; color: var(--fg-muted); }
.feedback-list { list-style: none; margin: 0; padding: 0; background: var(--bg-surface); border-radius: var(--radius); }
.feedback-list li + li { border-top: 1px solid var(--border-subtle); }
.feedback-item summary {
  display: flex; gap: var(--sp-3); align-items: baseline; flex-wrap: wrap;
  padding: var(--sp-3) var(--sp-4); cursor: pointer; font-size: 14px; list-style: none;
}
.feedback-item summary::-webkit-details-marker { display: none; }
.feedback-item summary::before { content: '▸'; color: var(--fg-muted); flex: none; }
.feedback-item[open] summary::before { content: '▾'; }
.feedback-item summary:hover { background: var(--bg-sunken); }
.feedback-when { color: var(--fg-minor); flex: none; font-variant-numeric: tabular-nums; }
.feedback-preview { flex: 1 1 20ch; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.feedback-flags { display: inline-flex; gap: var(--sp-2); flex: none; }
.feedback-body { display: flex; flex-direction: column; gap: var(--sp-3); padding: 0 var(--sp-4) var(--sp-4) calc(var(--sp-4) + 1.2em); }
.feedback-meta { font-size: 13px; color: var(--fg-minor); display: flex; flex-wrap: wrap; gap: var(--sp-3); }
.feedback-msg { white-space: pre-wrap; overflow-wrap: anywhere; margin: 0; }
.rating { display: inline-flex; gap: var(--sp-1); align-items: center; }
.rating button { min-width: 36px; padding-inline: var(--sp-2); }
.rating button[aria-pressed="true"] { background: var(--accent); color: #fff; }

.stack { display: flex; flex-direction: column; gap: var(--sp-5); }
/* React island wrapper (components/island.tsx): a hydration root that must not
   become a flex/grid item, so the form inside it keeps its place in the stack. */
.island { display: contents; }
.stack-sm { display: flex; flex-direction: column; gap: var(--sp-3); }
.row { display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: center; }

.eyebrow {
  font-size: 12px; font-weight: 700; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--fg-muted);
}

/* ── Contrast band ───────────────────────────────────────────────────────── */

.band {
  background: var(--bg-contrast-soft);
  border-radius: var(--radius);
  padding: var(--sp-4) var(--sp-5);
  display: flex; gap: var(--sp-4); align-items: baseline; flex-wrap: wrap;
}
.band-label {
  font: 700 10px/1.2 var(--font-sans);
  letter-spacing: .08em; text-transform: uppercase;
  color: var(--accent-on-dark); white-space: nowrap;
}
.band-text { font: 700 13px/1.35 var(--font-sans); color: var(--fg-on-contrast); }
.band-text a { color: var(--accent-on-dark); }

/* ── Provenance ──────────────────────────────────────────────────────────── */

.provenance { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-3); align-items: baseline; font-size: 13px; color: var(--fg-muted); }
.provenance .eyebrow { color: var(--fg-muted); }
.provenance.is-stale .eyebrow { color: var(--signal-warning); }

/* ── School facts ────────────────────────────────────────────────────────── */

/*
 * One wrapping line of label+value pairs, not a stacked definition list. As a
 * two-column grid this was five rows and a 120px label gutter — roughly 140px
 * of contact details standing between the school's name and the places table,
 * which is the thing the page exists to show. Inline, it costs one or two lines.
 *
 * No separator character between pairs: the tiny uppercase label already reads
 * as the start of a new fact, and a „·" would collide with the ones inside
 * „средно · община · две смени".
 */
.school-facts {
  display: flex; flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-5);
  margin: 0; font-size: 14px;
}
.school-facts .fact { display: flex; align-items: baseline; gap: var(--sp-2); min-width: 0; }
.school-facts dt {
  font: 700 11px/1.5 var(--font-sans);
  letter-spacing: .08em; text-transform: uppercase; color: var(--fg-muted);
  white-space: nowrap;
}
.school-facts dd { margin: 0; color: var(--fg-minor); }

/* ── Cards ───────────────────────────────────────────────────────────────── */

.grid-schools {
  display: grid; gap: var(--sp-5);
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  list-style: none; margin: 0; padding: 0;
}

.card {
  background: var(--bg-surface);
  border-radius: var(--radius);
  padding: var(--sp-5);
  display: flex; flex-direction: column; gap: var(--sp-3);
  border: 1px solid transparent;
  /* Border-colour on hover rather than shadow: flat, and it avoids repainting
     200 shadows at once on a long list. */
  transition: border-color var(--dur-fast) var(--ease-default),
              transform var(--dur-fast) var(--ease-default);
}
.card:hover { border-color: var(--border-strong); transform: translateY(-2px); }
.card:focus-within { outline: 2px solid var(--accent); outline-offset: 2px; }
.card h3 a { color: inherit; }
.card h3 a:hover { text-decoration: none; }

/* Profile tiles on the home page: the school card, on a tighter grid so the
   nine categories fit as tiles rather than one scrolling line. They carry three
   short lines, so they are sized by their content — a forced square left the
   bottom half of every tile empty. */
.grid-tiles { grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: var(--sp-4); }
.card-tile { position: relative; padding: var(--sp-4); gap: var(--sp-2); }
/* The whole tile is the link — the heading's anchor is stretched over the card,
   which keeps one real link per tile for a keyboard and a crawler alike. */
.card-tile h3 a::after { content: ''; position: absolute; inset: 0; border-radius: var(--radius); }
/* Places sit on the bottom edge so the counts line up across a row whatever the
   profile name wraps to. The `.card` outranks `.card hr`'s own margin. */
.card.card-tile hr { margin-top: auto; }

.card-meta { font-size: 13px; color: var(--fg-minor); }
/* Where the school is — supporting detail, a step quieter than the paralelka. */
.card-where { color: var(--fg-muted); }
.card hr { border: none; border-top: 1px solid var(--border-subtle); margin: 0; }

.places { display: flex; align-items: baseline; gap: var(--sp-2); }
.places-count { font-size: 24px; font-weight: 700; color: var(--avail-yes); font-variant-numeric: tabular-nums; }
.places-label { font-size: 13px; color: var(--fg-minor); }
.places.is-empty .places-count { color: var(--avail-none); }

.badge {
  display: inline-block; font-size: 11px; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; padding: 2px var(--sp-2); border-radius: 4px;
  background: var(--avail-yes-bg); color: var(--avail-yes);
}
.badge-warn { background: #FFF1DB; color: #8A5200; }
/* Neutral: the default badge is the green of an available place, which would
   read as reassurance on a label like „непроверена". */
.badge-muted { background: var(--bg-sunken); color: var(--fg-minor); }

/* ── Chiclets ────────────────────────────────────────────────────────────── */

.chiclets {
  display: flex; gap: var(--sp-2); overflow-x: auto; padding-bottom: var(--sp-2);
  scroll-snap-type: x proximity; scrollbar-width: thin;
  list-style: none; margin: 0; padding-inline: 0;
}
.chiclets li { scroll-snap-align: start; }
.chiclet {
  display: inline-block;
  border-radius: 999px;
  padding: var(--sp-2) var(--sp-4);
  font-size: 14px; font-weight: 500;
  background: var(--bg-sunken);
  color: var(--fg-minor);
  border: 1px solid transparent;
  white-space: nowrap;
  min-height: 36px;
  transition: background var(--dur-fast) var(--ease-default);
}
.chiclet:hover { text-decoration: none; background: var(--border-subtle); }
.chiclet[aria-current="true"] {
  background: var(--accent-tint); color: var(--accent);
  border-color: var(--accent); font-weight: 700;
}

/* ── Forms and buttons ───────────────────────────────────────────────────── */

.btn {
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--radius); padding: var(--sp-3) var(--sp-5);
  font: 600 15px/1 var(--font-sans); min-height: 44px;
  border: 1px solid transparent; cursor: pointer; text-decoration: none;
}
.btn:hover { text-decoration: none; }
.btn-primary { background: var(--accent); color: #fff; }
.btn-primary:hover { background: var(--accent-hover); }
.btn-secondary { background: var(--bg-sunken); color: var(--fg-major); }
.btn-secondary:hover { background: var(--border-subtle); }
.btn-ghost { background: none; color: var(--accent); padding-inline: var(--sp-2); }

.field { display: flex; flex-direction: column; gap: var(--sp-2); }
.field label { font-size: 14px; font-weight: 600; }
.field .hint { font-size: 13px; color: var(--fg-muted); }
.field .error { font-size: 13px; color: #B3261E; }

input[type="text"], input[type="search"], input[type="email"], input[type="password"], select, input[type="file"] {
  font: 400 15px/1.4 var(--font-sans);
  padding: var(--sp-3) var(--sp-4);
  min-height: 44px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--bg-surface);
  color: var(--fg-major);
  width: 100%;
}
input:focus-visible, select:focus-visible { border-color: var(--accent); }

.searchbar { display: flex; gap: var(--sp-3); flex-wrap: wrap; }
.searchbar input[type="search"] { flex: 1 1 260px; }

.filters { display: grid; gap: var(--sp-3); grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }

/* ── Dense list ──────────────────────────────────────────────────────────── */

/*
 * The header sticks under the 56px site header while a long list scrolls, so
 * `top` has to clear it.
 *
 * No `overflow: hidden` here, however tempting it is for the rounded corners:
 * it makes the table its own scroll container, and a sticky cell then measures
 * `top` from the table's own edge instead of the viewport's. The header ends up
 * pinned 56px *down* from the top of the table — sitting on the first row,
 * swallowing its links. The corners are rounded on the corner cells instead,
 * which needs `separate` borders; the cells draw their own single lines, so
 * nothing doubles up.
 */
.results-table { width: 100%; border-collapse: separate; border-spacing: 0; background: var(--bg-surface); border-radius: var(--radius); }
.results-table th {
  text-align: left; font-size: 12px; font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: var(--fg-muted);
  padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--border-subtle);
  position: sticky; top: 56px; background: var(--bg-surface); z-index: 10;
}
.results-table thead tr:first-child th:first-child { border-top-left-radius: var(--radius); }
.results-table thead tr:first-child th:last-child { border-top-right-radius: var(--radius); }
.results-table tbody tr:last-child td:first-child { border-bottom-left-radius: var(--radius); }
.results-table tbody tr:last-child td:last-child { border-bottom-right-radius: var(--radius); }
.results-table td { padding: var(--sp-3) var(--sp-4); border-top: 1px solid var(--border-subtle); vertical-align: top; }
/* `collapse` used to merge this with the header's bottom border; `separate` draws both. */
.results-table tbody tr:first-child td { border-top: 0; }
.results-table .num { text-align: right; font-variant-numeric: tabular-nums; font-weight: 700; color: var(--avail-yes); }
/* Matches `.places.is-empty` on the cards: now that green is the brand colour a
   green „0" reads as reassurance, which is the opposite of what it says. */
.results-table .num.is-empty { color: var(--avail-none); }

/* Never horizontally scroll a table on a phone — collapse to cards. */
@media (max-width: 767px) {
  .results-table, .results-table thead, .results-table tbody,
  .results-table tr, .results-table th, .results-table td { display: block; }
  /* The rows become the cards here, so the table below them must not also be a
     surface — otherwise the gaps between rows disappear into one white slab. */
  .results-table { background: none; }
  .results-table thead { display: none; }
  .results-table tr { background: var(--bg-surface); border-radius: var(--radius); margin-bottom: var(--sp-3); padding: var(--sp-3); }
  .results-table td { border: none; padding: var(--sp-1) 0; }
  .results-table td::before { content: attr(data-label) ': '; font-weight: 600; color: var(--fg-muted); }
  .results-table .num { text-align: left; }
}

/* ── Empty state ─────────────────────────────────────────────────────────── */

.empty-state {
  background: var(--bg-surface); border-radius: var(--radius);
  padding: var(--sp-7) var(--sp-5); text-align: center;
  display: flex; flex-direction: column; gap: var(--sp-4); align-items: center;
}
.empty-state p { max-width: 46ch; color: var(--fg-minor); }
/* The mark says the thing the page says: the grid is full and the one open cell
   is still open. Greyed back so it reads as illustration, not as a control. */
.empty-state .mark { height: 40px; color: var(--border-strong); }
.empty-state .mark .mark-open { fill: var(--accent); }

/* ── Admin ───────────────────────────────────────────────────────────────── */

.panel { background: var(--bg-surface); border-radius: var(--radius); padding: var(--sp-5); }
.gate-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.gate {
  display: grid; grid-template-columns: 24px 1fr; gap: var(--sp-3);
  padding: var(--sp-3) 0; border-top: 1px solid var(--border-subtle); align-items: start;
}
.gate:first-child { border-top: none; }
.gate-mark { font-weight: 700; }
.gate.pass .gate-mark { color: var(--avail-yes); }
.gate.fail .gate-mark { color: #B3261E; }
.gate.warn .gate-mark { color: var(--signal-warning); }
/* Skipped, not passed — muted so it cannot be mistaken for a green tick. */
.gate.skip .gate-mark { color: var(--fg-muted); }
.gate-detail { font-size: 13px; color: var(--fg-minor); }

.notice { border-radius: var(--radius); padding: var(--sp-4); font-size: 14px; }
.notice-ok { background: var(--avail-yes-bg); color: #05603A; }
.notice-warn { background: #FFF1DB; color: #8A5200; }
.notice-error { background: #FCE8E6; color: #8C1D18; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
}
