:root {
  --ink: #14213D;
  --paper: #F5F6F2;
  --accent: #FF4B3E;
  --muted: #6B7280;
  --border: #E2E4DD;
  --font-display: 'Oswald', sans-serif;
  --font-body: 'Inter', sans-serif;
  --font-mono: 'JetBrains Mono', monospace;
}
html { overflow-y: scroll; scrollbar-gutter: stable; }
* { box-sizing: border-box; }
body { margin: 0; background: var(--paper); color: var(--ink); font-family: var(--font-body); line-height: 1.5; }
.site-nav { display: flex; align-items: center; gap: 2rem; padding: 1.25rem 2rem; border-bottom: 1px solid var(--border); }
.site-nav .brand { font-family: var(--font-display); font-weight: 700; font-size: 1.5rem; text-transform: uppercase; }
.site-nav a { color: var(--ink); text-decoration: none; font-weight: 500; }
.site-nav a:hover { color: var(--accent); }
/* The 11 Nov link in the header (in season): a small white-over-red flag before
   it, the same stripe as the 11 Nov page's hero board. The thin outline keeps
   the white half visible on the light navbar. */
.nav-link--holiday::before {
  content: ""; display: inline-block; width: 0.95rem; height: 0.62rem; margin-right: 0.4rem; vertical-align: 0.02em;
  background: linear-gradient(white 50%, var(--accent) 50%);
  border: 1px solid rgba(20, 33, 61, 0.2); border-radius: 2px;
}
.navbar .nav-link--holiday:hover { color: var(--accent); }  /* not on its own page: no other menu link marks the current page (Bart, 4 Nov) */
.container { max-width: 1100px; margin: 0 auto; padding: 2rem; }
h1, h2, h3 { font-family: var(--font-display); text-transform: uppercase; letter-spacing: 0.01em; }



.race-detail-distances__label {
  font-size: 0.7rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 700;
  margin: 0.9rem 0 0.4rem;
}
.race-detail-distances { display: flex; flex-wrap: wrap; gap: 0.4rem; }

/* Organizer facts ("Najważniejsze informacje", Race.page_facts), 28 Oct. A soft panel so it
   reads as one info box. Phones: label above value, so long values (the start
   place) get the full width. From 576px: label | value side by side.
   Type sits at the date line's level (.meta-line, 0.85rem): these are the same
   kind of detail, and must not outshout the date or the distance chips.
   The icon comes from data-icon via ::before: a <dl> may only hold dt/dd (and
   divs of them), and the '/ ""' alt text keeps screen readers from reading it. */
.race-facts { background: var(--paper); border: 1px solid var(--border); border-radius: 8px; padding: 0.25rem 0.9rem; }
.race-facts__list { margin: 0; }
.race-facts__item { display: grid; grid-template-columns: 1.5rem 1fr; column-gap: 0.4rem; padding: 0.5rem 0; }
.race-facts__item + .race-facts__item { border-top: 1px solid var(--border); }
.race-facts__item::before { content: attr(data-icon); content: attr(data-icon) / ""; grid-row: 1 / span 2; font-size: 0.95rem; line-height: 1.4; }
.race-facts dt { font-size: 0.75rem; font-weight: 500; color: #4B5563; margin: 0; }
.race-facts dd { margin: 0; font-size: 0.85rem; font-weight: 500; color: var(--ink); overflow-wrap: anywhere; }
/* Quiet on purpose: ink, thin underline, a small ↗. The sign-up button below stays
   the one "do this next" on the page. */
.race-facts dd a { color: var(--ink); text-decoration: underline; text-decoration-color: rgba(20, 33, 61, 0.35); text-underline-offset: 3px; display: inline-block; padding: 0.15rem 0; }
.race-facts dd a:hover { color: var(--accent); text-decoration-color: currentColor; }
.race-facts__checked { margin: 0; padding: 0.5rem 0 0.4rem; border-top: 1px solid var(--border); font-size: 0.75rem; color: #4B5563; }
@media (min-width: 576px) {
  .race-facts__item { grid-template-columns: 1.5rem 9rem 1fr; align-items: baseline; }
  .race-facts__item::before { grid-row: auto; }
  .race-facts dt { font-size: 0.85rem; font-weight: 400; }
}


/* Breadcrumb: the only links above the fold on a phone, so they must look
   like links (blue, soft underline) and be easy to tap (padding). */
.breadcrumb-race { margin-bottom: 0.5rem; font-size: 0.9rem; }
.breadcrumb-race a {
  display: inline-block;
  padding: 0.3rem 0;
  color: #2563EB;
  text-decoration: underline;
  text-decoration-color: rgba(37, 99, 235, 0.35);
  text-underline-offset: 3px;
}
.breadcrumb-race a:hover { color: var(--accent); text-decoration-color: currentColor; }
.breadcrumb-race__sep { color: var(--muted); margin: 0 0.3rem; }

/* Race detail: card + related races on the left, "Zobacz więcej biegów" on the
   right. Stacks under 900px, so on mobile the links land below the related
   races. The links are the hubs' "Więcej" box (.choice-hub__more, .more-row
   with a count), the same rows on every screen: Bart picked them over pills
   on 2026-10-22 (full-width 56px rows are easier to tap and to scan). */
.race-layout { display: grid; grid-template-columns: minmax(0, 720px) 280px; gap: 1.5rem; justify-content: center; align-items: start; text-align: left; }
.race-layout__main { min-width: 0; }
/* Breadcrumb only when the sidebar has dropped to the bottom of the page. */
.race-layout .breadcrumb-race { display: none; }
@media (max-width: 900px) {
  .race-layout { grid-template-columns: minmax(0, 1fr); }
  .race-layout .breadcrumb-race { display: block; }
  /* Stacked: order stays card → related races → "Zobacz więcej". The
     breadcrumb above the H1 already links up to city/region, so real races
     come next. */
}

.race-card { background: white; border: 1px solid var(--border); border-top: 4px solid var(--accent); border-radius: 10px; padding: 2rem; max-width: 720px; width: 100%; }
/* Must come AFTER the base rule: same specificity, so the later one wins.
   It used to sit above it and never applied. */
@media (max-width: 480px) {
  .race-card { padding: 1.25rem; }
}


.related-races { max-width: 720px; width: 100%; text-align: left; }
.related-races h2 { font-size: 1.1rem; margin-bottom: 0.75rem; text-align: left; }
.related-races__note { color: var(--muted); font-size: 0.85rem; margin: 0 0 0.35rem; }

/* Homepage hero */
/* ~~Top is 1rem~~ Top is 0 (5 Nov): <main>'s own padding (48px desktop, 24px phones) is
   then the gap under the navbar, the same as on every list page. Bottom 2rem: the
   filter card sits 32px under the photo, as on the 11 Nov page (.home-section .fc). */
.hero { text-align: center; padding: 0 1rem 2rem; }
.hero h1 { font-size: 2.75rem; margin-bottom: 0.5rem; }
.hero-answer { color: var(--accent); white-space: nowrap; }
/* Results board under the description: three counts like a timing board,
   mono digits of equal width, small labels, a red "start line" on top. */
.hero-board { display: flex; max-width: 480px; margin: 1.25rem auto 0; padding: 0.7rem 0; list-style: none; border-top: 2px solid var(--accent); border-bottom: 1px solid var(--border); }
.hero-board > li { flex: 1; min-width: 0; }
.hero-board > li + li { border-left: 1px solid var(--border); }
.hero-board__item { display: flex; flex-direction: column; align-items: center; gap: 0.15rem; padding: 0 0.5rem; color: var(--ink); text-decoration: none; }
a.hero-board__item:hover .hero-board__label { color: var(--accent); }
.hero-board__num { font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: 1.6rem; line-height: 1.1; }
.hero-board__label { font-size: 0.7rem; font-weight: 600; letter-spacing: 0.06em; line-height: 1.25; text-transform: uppercase; color: var(--muted); }

/* Start-line photo panel (duotone): the photo in greyscale (::before) under a
   navy layer (::after), so any photo comes out in the site's own colours and
   white text stays readable. isolation keeps the two layers behind the text.
   Photo: Unsplash OpDIYfAb4WQ (free licence), saved as static/img/hero-start.jpg,
   1400x1100, greyscale, ~150 KB. */
.hero-photo { position: relative; isolation: isolate; overflow: hidden; max-width: 860px; margin: 0 auto; padding: 2.75rem 1.25rem 2.25rem; border-radius: 12px; background: var(--ink); color: white; }
.hero-photo::before { content: ""; position: absolute; inset: 0; z-index: -2; background: url("../img/hero-start.51a672b10e5f.jpg") center 50% / cover; filter: grayscale(1) contrast(1.15); }
.hero-photo::after { content: ""; position: absolute; inset: 0; z-index: -1; background: linear-gradient(180deg, rgba(20, 33, 61, 0.62), rgba(20, 33, 61, 0.88)); }
.hero-photo .hero-sub { color: rgba(255, 255, 255, 0.82); }
.hero-photo .hero-board { border-bottom-color: rgba(255, 255, 255, 0.2); }
.hero-photo .hero-board > li + li { border-left-color: rgba(255, 255, 255, 0.2); }
.hero-photo .hero-board__item { color: white; }
.hero-photo .hero-board__label { color: rgba(255, 255, 255, 0.7); }
/* On the dark panel the ink button would vanish: white with ink text. */
.hero .hero-photo .btn-primary { background: white; border-color: white; color: var(--ink); }  /* beats .hero .btn-primary further down */
/* 11 Nov page: a small label over the headline, and the board's start line as
   the flag, white over red. */
.hero-eyebrow { font-size: 0.75rem; font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; color: rgba(255, 255, 255, 0.75); margin: 0 0 0.5rem; }
.hero-board--flag { border-top-width: 3px; box-shadow: 0 -3px 0 white; }  /* white shadow over the red top line */
/* Phones: "MIEJSCOWOŚCI" and "WOJEWÓDZTW" are long for a third of the width. */
/* Phones: smaller labels on every board, not just the 11 Nov one. At 0.7rem
   "NADCHODZĄCYCH" (115px) overflowed its ~100px column on a 360px phone and
   ran into the dividers (Bart, 4 Nov). */
@media (max-width: 600px) {
  .hero-board__label { font-size: 0.62rem; letter-spacing: 0.02em; }
  .hero-board__item { padding: 0 0.3rem; }
}

/* Homepage sections: a hub-style label (.choice-hub__label) over each block,
   both blocks one width so the labels line up. */
.home-section { max-width: 860px; margin: 0 auto 2.5rem; text-align: left; }
/* The hub cards under the "Zobacz cały kalendarz" button (5 Nov): the same gap
   above them as between the other sections. */
.home-section--after { margin-top: 2.5rem; }
/* The homepage's filter card: straight under the hero, like .fc.holiday-filters. */
.home-section .fc { margin-top: 0; }

/* Short race lists outside the tables (_race_item.html): homepage "Nadchodzące
   biegi", the race page's "Inne biegi w…". The phone race row's look on every
   screen (see "Compact race cards on phones"), so a race looks the same
   everywhere (Bart, 4 Nov); replaces the homepage tiles and the race page's
   plain rows. Keep the two in step when one changes. */
.date-box__day { font-size: 1.35rem; font-weight: 700; color: var(--ink); font-variant-numeric: tabular-nums; }
.date-box__month { margin-top: 0.15rem; font-size: 0.7rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink); }
.date-box__year { margin-top: 0.1rem; font-size: 0.68rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.race-items { list-style: none; margin: 0; padding: 0; background: white; border: 1px solid var(--border); border-radius: 10px; overflow: hidden; text-align: left; }
.race-item {
  position: relative; display: flex; flex-direction: column; align-items: flex-start;
  padding: 0.9rem 0.85rem 0.9rem calc(0.85rem + 3rem + 0.75rem);  /* as the phone rows: the › sits on the chips line */
  min-height: calc(0.9rem * 2 + 3.7rem);
  border-bottom: 1px solid var(--border);
}
.race-item:last-child { border-bottom: none; }
.race-item:hover, .race-item:active { background: #FAFAF7; }
.race-item .date-box {
  position: absolute; left: 0.85rem; top: 0.9rem; width: 3rem;
  padding: 0.4rem 0; background: var(--paper); border: 1px solid var(--border); border-radius: 8px;
  text-align: center; line-height: 1; pointer-events: none;
}
.race-item .date-box > span { display: block; line-height: 1.05; }
.race-item__title { padding-bottom: 0.25rem; }
.race-item__title > a { color: var(--ink); font-size: 1rem; font-weight: 600; line-height: 1.3; text-decoration: none; }
.race-item__title > a::after { content: ""; position: absolute; inset: 0; }  /* the whole row opens the race */
.race-item:hover .race-item__title > a { color: var(--accent); }
.race-item__type { display: block; margin-top: 0.2rem; font-size: 0.85rem; color: var(--muted); }
/* Above the stretched link, so its hover text still shows on desktop. */
.race-item .pzla-badge { position: relative; z-index: 1; margin-left: 0.4rem; }
.race-item__place, .race-item__price { font-size: 0.9rem; line-height: 1.4; }
.race-item__place { color: var(--muted); }
.race-item__place::before, .race-item__price::before { font-size: 0.8rem; margin-right: 0.3rem; }
.race-item__place::before { content: "📍"; margin-right: 0.2rem; }
.race-item__price { margin-top: 0.25rem; color: var(--ink); }
.race-item__price::before { content: "💳"; }
.race-item__chips { margin-top: 0.6rem; }
.race-item::after {
  content: ""; position: absolute; right: 1rem; bottom: 1.45rem;
  width: 0.5rem; height: 0.5rem; pointer-events: none;
  border-right: 2px solid #A3A9B5; border-top: 2px solid #A3A9B5; transform: rotate(45deg);
}

/* Homepage nav cards: one per hub, same card look as the hubs' .choice-card
   (body font, not the uppercase display font). */
.home-nav-cards { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0.75rem; }
.nav-card { display: block; background: white; border: 1px solid var(--border); border-radius: 8px; padding: 1.1rem; text-decoration: none; color: var(--ink); text-align: left; transition: border-color 0.15s ease; }
.nav-card:hover { border-color: var(--accent); }
.nav-card h3 { font-family: var(--font-body); text-transform: none; letter-spacing: normal; font-weight: 600; font-size: 1.1rem; margin: 0 0 0.35rem; }
.nav-card p { margin: 0; color: var(--muted); font-size: 0.85rem; line-height: 1.4; }

/* Tablet and phone: 2 × 2, so four cards don't push the races off the first screen. */
@media (max-width: 860px) {
  .home-nav-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 600px) {
  .hero h1 { font-size: 2rem; }
}

.hero-sub { max-width: 480px; margin: 0.75rem auto 0; color: var(--muted); font-size: 0.95rem; text-wrap: balance; }  /* even lines, no lone last word */

.race-table { width: 100%; max-width: 1000px; margin: 0 auto; border-collapse: collapse; table-layout: fixed; background: white; border-radius: 10px; overflow: hidden; border: 1px solid var(--border); }
.race-table th { background: var(--ink); color: white; font-family: var(--font-display); text-transform: uppercase; font-size: 0.85rem; letter-spacing: 0.03em; padding: 0.85rem 1rem; text-align: left; }
.race-table td { padding: 0.75rem 1rem; border-top: 1px solid var(--border); font-size: 0.95rem; white-space: normal; overflow: visible; text-overflow: clip; text-align: left; }

/* DATE is the only column that should stay single-line — dates are a
   fixed, predictable length ("29 sierpnia 2026") and never need to wrap.
   Every other column (name, distance, city) wraps by default now; this is
   the one deliberate exception, not the other way around. */
.race-table td.date-cell { white-space: nowrap; }
.race-table .date-box { display: none; }  /* phones only, see "Compact race cards" */
.race-table tr:hover td { background: #FAFAF7; }
.race-table a { color: var(--ink); font-weight: 500; text-decoration: none; }
.race-table a:hover { color: var(--accent); }
.race-table td.past { color: var(--muted); }

/* --- Mobile: table becomes a stacked card list --------------------------- */
/* Below this width, 4 fixed-percentage columns don't leave room for
   unbreakable Polish words ("MIEJSCOWOŚĆ", "Warszawa") to render without
   overflowing sideways into the next column — browsers don't break a word
   mid-string by default, so a too-narrow column spills instead of wrapping.
   The fix isn't tighter columns, it's not having columns at all here: each
   row becomes its own card, each field stacks with a label pulled from
   data-label (set in _race_row.html) via ::before.

   Accessibility trade-off, noted rather than silently accepted: hiding
   <thead> removes it from the accessibility tree along with the visual
   removal. A fully accessible version would visually hide it instead
   (clip it off-screen rather than display:none) so screen readers still
   get the column context. Skipping that polish for now — flag if you want
   it done properly later. */
@media (max-width: 640px) {
  .race-table { max-width: 100%; }
  .race-table thead { display: none; }
  .race-table, .race-table tbody, .race-table tr, .race-table td {
    display: block;
    width: auto !important;
  }
  .race-table tr {
    border: 1px solid var(--border);
    border-radius: 8px;
    margin-bottom: 0.75rem;
    padding: 0.75rem 1rem;
  }
  .race-table tr:last-child { margin-bottom: 0; }

  .race-table td { border-top: none; padding: 0.3rem 0; }

  /* Race name reads as the card's title — bigger, bold, no label prefix
     (a card header doesn't need "Nazwa biegu:" in front of it). */
  .race-table td.name-cell { font-weight: 600; font-size: 1rem; padding-bottom: 0.5rem; }

  /* City and date: short single values, label + value side by side. */
  .race-table td.city-cell,
  .race-table td.date-cell {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.75rem;
  }
  .race-table td.city-cell::before,
  .race-table td.date-cell::before {
    content: attr(data-label);
    font-family: var(--font-display);
    text-transform: uppercase;
    font-size: 0.7rem;
    letter-spacing: 0.05em;
    color: var(--muted);
    font-weight: 700;
    flex-shrink: 0;
  }

  /* Distance chips can be several and wrap — label goes above, not beside. */
  .race-table td.dist-cell::before {
    content: attr(data-label);
    display: block;
    font-family: var(--font-display);
    text-transform: uppercase;
    font-size: 0.7rem;
    letter-spacing: 0.05em;
    color: var(--muted);
    font-weight: 700;
    margin-bottom: 0.3rem;
  }
}

/* Month hub grid — migrated off month_hub.html's old inline <style> block (Issues Backlog 5.3) */
.month-hub { max-width: 1000px; margin: 0 auto; padding: 2rem 1rem 4rem; }

.month-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 0.75rem; }

/* Shared hub tile base — used by both month and city hub grids so they can't drift apart again */
.hub-card {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding: 1.25rem 0.75rem;
  border: 1px solid var(--border);
  border-radius: 6px;
  text-align: center;
  text-decoration: none;
  color: var(--ink);
  font-weight: 600;
  background: white;
  transition: border-color 0.15s ease, transform 0.15s ease, opacity 0.15s ease;
}
.hub-card:hover { border-color: var(--accent); transform: translateY(-2px); }
.hub-card__count { font-size: 0.75rem; font-weight: 400; color: var(--muted); }

/* Choice hubs (/biegi/rodzaje/, /biegi/dystanse/): one card per thing people
   choose from, then a "Więcej" list of tap rows for the rest. Left-aligned
   (easier to scan than centred once a card holds several lines). */
.choice-hub__label, .choice-card, .more-row { text-align: left; }  /* .month-hub centres */
.choice-hub__label {
  font-family: var(--font-body); font-size: 0.75rem; font-weight: 600;
  letter-spacing: 0.08em; color: var(--muted); margin: 0 0 0.6rem;
}
.month-grid + .choice-hub__label { margin-top: 2rem; }  /* month hub: the boxes have no bottom margin */
.choice-hub__cards { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0.75rem; margin-bottom: 2rem; }
.choice-card {
  position: relative; display: flex; flex-direction: column; gap: 0.4rem;
  padding: 1.1rem 1.1rem 1rem; background: white; border: 1px solid var(--border); border-radius: 8px;
  transition: border-color 0.15s ease;
}
.choice-card:hover { border-color: var(--accent); }
.choice-card__head { display: flex; justify-content: space-between; align-items: center; gap: 0.5rem; }
.choice-card__name { font-weight: 600; font-size: 1.1rem; color: var(--ink); text-decoration: none; }
/* The name link covers the whole card, so a tap anywhere opens the type page. */
.choice-card__name::after { content: ""; position: absolute; inset: 0; }
/* Terrain icon (_type_icon.html): a duotone icon in a round badge tinted with
   its terrain colour (asphalt grey, rock brown, forest green; muted, so the
   red accent stays the only strong colour on the page). */
.choice-card__icon {
  flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
  width: 2.5rem; height: 2.5rem; border-radius: 50%; background: var(--paper);
}
.choice-card__icon--uliczne { background: #EEF1F5; }
.choice-card__icon--gorskie { background: #F6ECE3; }
.choice-card__icon--przelajowe { background: #E6F3EA; }
/* Distance hub: level bars (_distance_level.html) in the distance's chip
   colour (the .dist-* chips on every race list), on a light tint of it. */
.level-bars__on { fill: currentColor; }
.level-bars__off { fill: currentColor; opacity: 0.3; }
.choice-card__icon--dist-5km        { color: #15803D; background: #E3F4E8; }
.choice-card__icon--dist-10km       { color: #0369A1; background: #E0F0FA; }
.choice-card__icon--dist-polmaraton { color: #B45309; background: #FCEFDC; }
.choice-card__icon--dist-maraton    { color: #DC2626; background: #FDE6E6; }
.choice-card__icon--dist-ultra      { color: var(--ink); background: #E6E8EE; }
.choice-card__blurb { margin: 0; font-size: 0.85rem; color: var(--muted); line-height: 1.4; }
.choice-card__cta { margin-top: auto; padding-top: 0.5rem; font-weight: 600; font-size: 0.9rem; color: var(--accent); }

.choice-hub__more { background: white; border: 1px solid var(--border); border-radius: 8px; }
.more-row {
  display: flex; align-items: center; gap: 0.75rem; min-height: 3.5rem;
  padding: 0.65rem 1.1rem; border-bottom: 1px solid var(--border); color: var(--ink); text-decoration: none;
}
.more-row:last-child { border-bottom: none; }
.more-row:hover .more-row__name { color: var(--accent); }
.more-row__text { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.more-row__name { font-weight: 600; }
.more-row__desc { font-size: 0.85rem; color: var(--muted); }
.more-row__count { white-space: nowrap; color: var(--muted); font-size: 0.9rem; }

/* Tablet and phone: one card per row. */
@media (max-width: 860px) {
  .choice-hub__cards { grid-template-columns: minmax(0, 1fr); }
}

/* Dead months — requires month.is_past from the view (see races_month.html's is_past_month for the same pattern) */
.month-card--past { opacity: 0.55; }
.month-card--past:hover { opacity: 0.85; transform: none; }

/* City hub grid — migrated off city_hub.html's old inline <style> block, same twin pattern as month hub */
.city-hub { max-width: 1000px; margin: 0 auto; padding: 2rem 1rem 4rem; }

.top-cities { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 0.75rem; margin-bottom: 3rem; }

.az-heading {
  font-size: 0.8rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 700;
  margin: 0 0 1rem;
  border-top: 1px solid var(--border);
  padding-top: 1.5rem;
}

.az-list { columns: 3 160px; column-gap: 1.5rem; }
.az-list a {
  display: block;
  padding: 0.3rem 0;
  color: var(--ink);
  text-decoration: none;
  border-bottom: 1px solid var(--border);
  break-inside: avoid;
}
.az-list a:hover { color: var(--accent); text-decoration: underline; }

@media (max-width: 480px) {
  .az-list { columns: 2 140px; }
}

/* Past-month status badge (races_month.html) */
.month-status-badge {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  background: var(--muted);
  color: white;
  padding: 0.2rem 0.55rem;
  border-radius: 4px;
  vertical-align: middle;
  margin-left: 0.5rem;
}

/* ==========================================================================
   APPEND TO style.css
   Also DELETE the four existing .race-table nth-child width lines — they're
   restated below with the distance column widened. (If you forget, the ones
   below still win on source order, but you'd have dead duplicated rules.)
   ========================================================================== */

/* --- Table column widths, rebalanced for distance chips ------------------- */
/* Distance was 18% when it held "10 km". It now holds up to 4 chips, so it
   takes width from the name column. Name still gets the most room. */
/* Column widths. DATE is sized for its worst case, not its average case:
   "Pon, 30 października 2026" (25 chars) is the longest realistic string
   the |date:"D, j E Y" format can produce - needs ~245px at this font size.
   28% of a 1000px table = 280px, leaving real margin instead of the ~5px
   slack a tighter percentage would leave. Learned this the hard way once
   already: the previous 20% was sized for the pre-weekday format ("j E Y"),
   and nobody re-checked it when the format changed - the string just
   silently overflowed past its cell and got clipped by the table's own
   border-radius/overflow:hidden edge. Whenever DATE's format changes again,
   recompute the worst case, don't eyeball it. */
.race-table th:nth-child(1), .race-table td:nth-child(1) { width: 36%; }  /* name */
.race-table th:nth-child(2), .race-table td:nth-child(2) { width: 22%; }  /* distance */
.race-table th:nth-child(3), .race-table td:nth-child(3) { width: 20%; }  /* city */
.race-table th:nth-child(4), .race-table td:nth-child(4) { width: 22%; }  /* date */
/* Five columns with an "Opłata" column (show_price, 11 Nov page). The date
   there has no year (no_year): "11 listopada" is 82px + 32px padding, which
   fits 20% down to the 641px card breakpoint; "11 listopada 2026" (124px)
   didn't fit at tablet width. */
.race-table--price th:nth-child(1), .race-table--price td:nth-child(1) { width: 27%; }
.race-table--price th:nth-child(2), .race-table--price td:nth-child(2) { width: 17%; }
.race-table--price th:nth-child(3), .race-table--price td:nth-child(3) { width: 22%; }
.race-table--price th:nth-child(4), .race-table--price td:nth-child(4) { width: 19%; }
.race-table--price th:nth-child(5), .race-table--price td:nth-child(5) { width: 15%; }
/* Tablet widths: "zachodniopomorskie" (one word, can't wrap) and "135–160 zł"
   need a little more room than 1rem padding leaves. */
@media (min-width: 641px) and (max-width: 900px) {
  .race-table--price th, .race-table--price td { padding-left: 0.6rem; padding-right: 0.6rem; }
}
/* Just above the phone cards (small tablets, landscape phones), a slightly
   smaller font so the same two still fit. */
@media (min-width: 641px) and (max-width: 767px) {
  .race-table--price td { font-size: 0.85rem; }
}
@media (min-width: 641px) and (max-width: 720px) {
  .race-table--price td { font-size: 0.8rem; }
}
.race-table td.price-cell { white-space: nowrap; font-variant-numeric: tabular-nums; }
.race-table td.price-cell--none { color: var(--muted); }
.race-table td.price-cell--mobile-only { display: none; }  /* phones show it: see "Compact race cards" */
.race-table td.price-cell .free-badge { padding-left: 0.3rem; padding-right: 0.3rem; }

/* The distance cell is the one exception to the table's nowrap/ellipsis rule —
   chips need to wrap, not get cut off mid-chip. Rows holding several distances
   will be taller than single-distance rows; that's the accepted trade-off for
   showing them all. */
.race-table td.dist-cell {
  vertical-align: middle;
}

/* --- Distance chips ------------------------------------------------------- */
.dist-chips { display: flex; flex-wrap: wrap; gap: 0.25rem; }

.dist-chip {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  line-height: 1.4;
  font-weight: 500;
  padding: 0.15rem 0.45rem;
  border-radius: 4px;
  color: white;
  white-space: nowrap;
}

/* Ski-slope order, easy to experts only (Bart, 5 Nov): green → blue → amber →
   red → navy/black (czarna) for ultra. Chosen over a weather order (blue
   first) because it keeps 5 km and 10 km, the two most common distances,
   clearly different hues. Each is the brightest shade of its hue that still
   keeps small white text readable (contrast ≥ 4.5:1); pure orange or green
   would not. Maraton is no longer --accent: #FF4B3E only reached 3.3:1. */
.dist-5km        { background: #15803D; }   /* green */
.dist-10km       { background: #0369A1; }   /* blue  */
.dist-polmaraton { background: #B45309; }   /* amber */
.dist-maraton    { background: #DC2626; }   /* red   */
.dist-ultra      { background: var(--ink); }
/* Outline chips get a white fill, not transparent: on the beige page
   background (homepage list, related races) a transparent chip looked faded,
   as if disabled. Navy text and a mid-grey outline (Bart, 3 Nov): grey text
   read as "disabled" next to the filled chips; this stays neutral but reads
   as a real distance. */
/* 12 Nov (Bart): in-between distances are filled grey, so every distance chip
   is a filled block and colour only ever means a classic distance (5, 10, HM,
   M, ultra). White outline now means "not a distance" (type, +N, brak danych).
   The hairline keeps the grey from melting into --paper on the homepage and
   related races. ~~White fill, mid-grey outline~~ (3 Nov). */
.dist-inne { background: #E9ECF0; color: var(--ink); border: 1px solid #D1D5DB; }
.dist-typ { background: white; color: var(--ink); border: 1px solid #9CA3AF; }

/* "+3" overflow indicator — hover shows the rest via the title attribute */
.dist-more {
  background: white;
  color: var(--muted);
  border: 1px dashed var(--border);
  cursor: help;
}

/* Race has no distance data at all (~a handful of rows) */
.dist-none {
  background: white;
  color: var(--muted);
  border: 1px solid var(--border);
  font-style: italic;
}

/* Past races: chips desaturate along with the rest of the row */
.race-table td.past .dist-chip { opacity: 0.55; }

/* Shared by race-detail header and homepage upcoming list. Plain muted text,
   not chips — chips should carry filterable data (distance category), not
   display data. No emoji: the built-in 📅 glyph renders with a baked-in "17"
   on most platforms, which read as a UI bug next to a real date. */
.meta-line { display: flex; gap: 0.35rem; align-items: center; flex-wrap: wrap; font-size: 0.85rem; }
.meta-line .meta-sep { color: var(--border); }
.meta-line .meta-date { color: var(--ink); font-weight: 500; }
.meta-line .meta-city { color: var(--muted); }
.meta-line .meta-city::before { content: "📍"; margin-right: 0.25rem; }

.race-card .btn-primary, .hero .btn-primary {
  background: var(--ink);
  border-color: var(--ink);
  font-weight: 600;
}
.race-card .btn-primary:hover, .hero .btn-primary:hover {
  filter: brightness(1.15);
}

/* Phase 2 — footer */
.site-footer {
  /* A shade darker than --muted (4.45:1 on --paper, just under WCAG AA's
     4.5:1 for small text); this one is 5.3:1. Footer only, so the rest of
     the site keeps its grey. */
  --footer-muted: #5F6673;
  margin-top: 0;
  padding: 2rem 1rem;
  border-top: 1px solid var(--border);
  text-align: center;
}
/* Three columns: site links, types + distances, cities. Phones keep the site
   links on top, full width in two short columns, then types and cities side
   by side. The © sits in its own bar below all of them. */
.footer-columns {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.5rem;
  max-width: 46rem;
  margin: 0 auto;
  text-align: left;
}
.footer-bottom {
  max-width: 46rem;
  margin: 1.75rem auto 0;
  padding-top: 1rem;
  border-top: 1px solid var(--border);
  text-align: left;
}
.footer-col__label {
  display: block;
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--footer-muted);
  margin-bottom: 0.5rem;
}
.footer-col__links {
  list-style: none;
  padding: 0;
  margin: 0 0 1.25rem;
}
.footer-col__links:last-child { margin-bottom: 0; }
.footer-col__links li { margin-bottom: 0.15rem; }
.footer-col__links a {
  color: var(--ink);
  text-decoration: none;
  font-size: 0.82rem;
}
.footer-col__links a:hover { text-decoration: underline; }
/* Site links stay grey, as in the old bottom row: secondary to the lists. */
.footer-col--site .footer-col__links a { color: var(--footer-muted); }
.footer-col--site .footer-col__links a:hover { color: var(--ink); }
.footer-copy { color: var(--footer-muted); font-size: 0.75rem; margin: 0; }
/* Phones: 14px text and links ~38px tall (Apple asks 44, Google 48, WCAG's
   floor is 24), so a thumb hits the one it aims for. display: block makes the
   whole row tappable, not just the words. */
@media (max-width: 575.98px) {
  /* 1rem gaps (both the same, so the site links line up with the columns
     below): at 375px a column is 163px, and "Wszystkie miejscowości" needs 161. */
  .footer-columns { grid-template-columns: 1fr 1fr; column-gap: 1rem; }
  .footer-col--site { grid-column: 1 / -1; }
  .footer-col--site .footer-col__links { columns: 2; column-gap: 1rem; }
  .footer-col__links li { margin-bottom: 0; }
  .footer-col__links a { display: block; padding: 0.55rem 0; font-size: 0.875rem; }
  .footer-copy { font-size: 0.8rem; }
}

/* Voivodeships on /biegi/miejscowosci/: the map and the list side by side
   (desktop), stacked (phones). */
.region-explorer {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
  gap: 2.5rem;
  align-items: center;
  margin-bottom: 2.5rem;
}
@media (max-width: 760px) {
  .region-explorer { grid-template-columns: minmax(0, 1fr); gap: 1.25rem; }
}

.poland-map { display: block; width: 100%; height: auto; }
.poland-map__region path {
  fill: #fff;
  stroke: #A3ABBA;
  stroke-width: 1;
  vector-effect: non-scaling-stroke;  /* 1px borders at any map size */
  transition: fill 0.15s ease;
}
.poland-map__region:hover path,
.poland-map__region.is-highlighted path { fill: #FFE1DE; }
.poland-map__region:focus { outline: none; }
.poland-map__region:focus-visible path { fill: #FFE1DE; stroke: var(--accent); stroke-width: 2; }
.poland-map__label {
  font-family: var(--font-body);
  font-size: 12.5px;  /* viewBox units: ~11.5px on a desktop-sized map */
  font-weight: 600;
  fill: var(--ink);
  pointer-events: none;  /* clicks go to the region underneath */
}
/* On phones the names would be ~6px: the map is for tapping, the list for reading. */
@media (max-width: 560px) { .poland-map__label { display: none; } }

.region-index { list-style: none; margin: 0; padding: 0; }
.region-index a {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  min-height: 2.4rem;
  padding: 0.35rem 0.5rem;
  text-decoration: none;
  color: inherit;
  border-bottom: 1px solid rgba(20, 28, 51, 0.08);
}
.region-index a:hover,
.region-index a:focus-visible,
.region-index a.is-highlighted { background: rgba(20, 28, 51, 0.04); color: var(--accent); }
.region-index__name { font-weight: 600; text-align: left; line-height: 1.25; }
.region-index__count { font-variant-numeric: tabular-nums; color: var(--muted); font-size: 0.9rem; }
@media (max-width: 760px) { .region-index a { min-height: 2.75rem; } }  /* thumb-sized rows */

/* Town search (combobox, static/js/town_search.js) on /biegi/miejscowosci/. */
.town-search { max-width: 560px; margin: 0 auto 2.25rem; }
.town-search__field { position: relative; }
.town-search__icon {
  position: absolute; left: 0.95rem; top: 1.5rem; transform: translateY(-50%);
  color: var(--muted); pointer-events: none;
}
.town-search__input {
  width: 100%; height: 3rem; padding: 0 1rem 0 2.8rem;
  font: inherit; font-size: 1rem;  /* 16px: iOS doesn't zoom in on focus */
  color: var(--ink); background: #fff;
  border: 1px solid #CDD1C7; border-radius: 8px;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.town-search__input::placeholder { color: var(--muted); }
.town-search__input:focus { outline: none; border-color: var(--ink); box-shadow: 0 0 0 3px rgba(20, 33, 61, 0.12); }
.town-search__list,
.town-search__empty {
  position: absolute; z-index: 20; left: 0; right: 0; top: calc(100% + 6px);
  margin: 0; background: #fff; border: 1px solid var(--border); border-radius: 8px;
  box-shadow: 0 12px 32px rgba(20, 33, 61, 0.10), 0 2px 6px rgba(20, 33, 61, 0.06);
  text-align: left;
}
.town-search__list { list-style: none; padding: 0.35rem; max-height: 23rem; overflow-y: auto; }
.town-search__empty { padding: 0.9rem 1rem; color: var(--muted); font-size: 0.95rem; }
.town-search__empty a { color: var(--ink); font-weight: 600; }
.town-search__option {
  display: flex; justify-content: space-between; align-items: baseline; gap: 1rem;
  padding: 0.6rem 0.75rem; border-radius: 6px; cursor: pointer;
}
.town-search__option[aria-selected="true"] { background: var(--paper); }
.town-search__name { color: var(--ink); }
.town-search__name mark { background: none; color: inherit; padding: 0; font-weight: 700; }
.town-search__meta { color: var(--muted); font-size: 0.85rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }

.city-hub__all {
  margin-top: 2rem;
  text-align: center;
  font-size: 0.95rem;
}

.city-index-search {
  max-width: 480px;
  margin: 0 auto 2.5rem;
}

.city-index-search input {
  width: 100%;
  padding: 0.6rem 0.9rem;
  border: 1px solid rgba(20, 28, 51, 0.2);
  border-radius: 6px;
  font-size: 1rem;
}

.city-index__group {
  margin-bottom: 2rem;
}

.city-index__letter {
  font-size: 1.1rem;
  margin: 0 0 0.6rem;
  padding-bottom: 0.3rem;
  border-bottom: 2px solid rgba(20, 28, 51, 0.12);
}

.city-index__list {
  list-style: none;
  margin: 0;
  padding: 0;
  columns: 4;
  column-gap: 2rem;
}

.city-index__list li {
  break-inside: avoid;
  padding: 0.15rem 0;
}

.city-index__list a {
  text-decoration: none;
  color: inherit;
}

.city-index__list a:hover { text-decoration: underline; }

.city-index__list a span {
  opacity: 0.45;
  font-size: 0.85rem;
}

@media (max-width: 900px) { .city-index__list { columns: 2; } }
@media (max-width: 560px) { .city-index__list { columns: 1; } }

/* Nested .container (most list templates put one inside main.container):
   no top spacing at any width. Its 2rem padding + Bootstrap's mt-4 stacked on
   main's py-5 left 104px between navbar and H1; now it's main's own padding
   only (48px desktop, 24px on phones). margin-top needs !important because
   Bootstrap's mt-4 utility uses it. */
.container .container { padding-top: 0; margin-top: 0 !important; }

/* --- Phone layout (≤576px) ------------------------------------------------
   Everything here is phone-only; desktop is untouched.
   1. .container has 2rem padding (overriding Bootstrap's 12px), and most list
      templates nest a second .container inside main.container, so a 375px
      phone lost 128px to padding. Thinner outer padding, none on the inner one.
   2. Less empty space between the navbar and the page (main has py-5).
   3. Race page: date and place on separate lines, so the "·" separator can't
      dangle at the end of a wrapped line.
   4. "Inne biegi" on the race page: date under the name, not squeezed
      beside it (dates wrapped onto 2-3 lines of different widths). */
@media (max-width: 576px) {
  .container { padding-left: 1rem; padding-right: 1rem; }
  .container .container { padding-left: 0; padding-right: 0; }
  main.container { padding-top: 1.5rem !important; }

  .meta-line { flex-direction: column; align-items: flex-start; gap: 0.15rem; }
  .meta-line .meta-sep { display: none; }


  /* Homepage: less hero padding and slimmer nav cards, so the "Nadchodzące
     biegi" list starts on the first screen. 5 Nov: no top padding (main's 24px
     is the gap, as on list pages), 32px down to the filter card (11 Nov page). */
  .hero { padding: 0 0 2rem; }
  .home-nav-cards { gap: 0.5rem; }
  .home-section { margin-bottom: 1.5rem; }
  .nav-card { padding: 0.75rem; }
  .nav-card h3 { font-size: 1rem; margin-bottom: 0.15rem; }
  .nav-card p { font-size: 0.85rem; }

  /* City hub: the 12 top-city tiles were one tall column (two 150px columns
     need 312px, a 375px phone has 311), pushing the regions ~1,100px down.
     Two fixed columns + shorter tiles. */
  .top-cities { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.5rem; margin-bottom: 2rem; }
  .top-cities .hub-card { padding: 0.6rem 0.5rem; }
  .city-hub { padding-top: 0; }
  }

/* Mobile card rows (≤640px, see the race-table card layout above): the city
   cell is a flex row. Town + region used to be two separate flex items next
   to the label, so three things were spread across the row: the town floated
   mid-row and the region got clipped by the table's overflow:hidden. Wrapped
   in one .cell-value (_race_row.html), the value is a single right-aligned
   block: town on top, region under it. min-width:0 lets it shrink and wrap
   instead of overflowing. */
@media (max-width: 640px) {
  .race-table td.city-cell .cell-value { display: block; min-width: 0; text-align: right; }
}

/* --- Whole race row opens the race, on every screen ------------------------
   "Stretched link": the race-name link stays the only real link (Google,
   Ctrl/Cmd-click, "open in new tab" all keep working; no JavaScript), but its
   ::after covers the whole row, so a click on the date, town or chips opens
   the race too. Phones since October; desktop since 4 Nov (Bart: the row
   already lit up on hover but only the name was a link).
   ~~Desktop left out: "a table row can't reliably be a positioning box"~~
   Superseded 4 Nov: current Chrome, Firefox and Safari position ::after
   against a <tr>; checked in Chromium (a click on the date cell opens the
   race, the link covers its own row only).
   ~~Desktop by the same ::after~~ Superseded 4 Nov (Bart: "the whole 11 Nov
   page is one link" in Safari): Safari ignores position: relative on a real
   table row (display: table-row), so every row's ::after spread over the
   whole page and the last race won every click. Chromium only shows it with
   tr { position: static } forced. Now the ::after is phones only (≤640px,
   where the row is a flex box, which Safari does position against), and on
   wider screens js/row_links.js opens the race on a row click.
   Nothing else in a row is a link; the PZLA badge sits above the link so its
   hover text still shows. */
@media (max-width: 640px) {
  .race-table tr { position: relative; }
  .race-table td.name-cell a::after { content: ""; position: absolute; inset: 0; }
  .race-table .name-cell .pzla-badge { position: relative; z-index: 1; }
}
@media (min-width: 641px) {
  .race-table tbody tr:has(td.name-cell a) { cursor: pointer; }  /* js/row_links.js */
}
.race-table tr:hover td.name-cell a { color: var(--accent); }
/* Phones: the hover colour moves from the cells to the card: on cells it left
   an inner grey rectangle inside the card's padding after a tap. */
@media (max-width: 640px) {
  .race-table tr:hover td { background: transparent; }
  .race-table tr:hover, .race-table tr:active { background: #FAFAF7; }
  /* The short lists (.race-items, _race_item.html) do the same on every screen. */
}

/* --- Compact race cards on phones (≤640px) -----------------------------------
   Was ~220px per card (labels "DYSTANS / MIEJSCOWOŚĆ / DATA" + a row each).
   Now: name (+ type), date, 📍 place, then the chips.
   - The row becomes a wrapping flex box; `order` puts date/place before the
     chips without touching the HTML (desktop table unchanged).
   - Date and place each get a full line, always. "Beside if it fits" made
     the place jump between cards (next to a short date, under a long one).
     A long "Janowiec Wielkopolski, kujawsko-pomorskie" just wraps in its line.
   - The 📍 marks the place instead of a "·" separator.
   - Labels come from td::before (data-label); they're switched off here.
   - Text hierarchy (Bart, 4 Nov: "not sure about the look of the boxes"): the
     name is the title (bigger, 600), the type line is quiet (regular, grey),
     date / place / price sit close as one group, the chips a step lower.
   - ~~No box around the boxes~~ Superseded 4 Nov (Bart picked "B"): one white
     panel per list (the table itself), races separated by thin lines, not
     separate cards. Lists of items of one kind that people scan by date read
     better as a list (the usual list-vs-cards rule); the panel also groups a
     region's races under its heading on the 11 Nov page.
   - The date sits in a small box on the left (day / month / year), like other
     race calendars: the list scans by date. Absolutely positioned, so the
     rest keeps its flex order; the row's left padding makes room for it.
   Must stay below the earlier card-layout rules so it wins. */
@media (max-width: 640px) {
  .race-table { background: white; border: 1px solid var(--border); border-radius: 10px; overflow: hidden; }
  .race-table tr {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    column-gap: 0.75rem;
    row-gap: 0;  /* spacing set per line below, so it follows one rhythm */
    /* Side padding 0.85rem, box 3rem, gap 0.75rem (were 1 / 3.25 / 0.9rem):
       11px more for the name; with the name at 1rem, 3 of 20 typical 11 Nov
       names wrap on a 390px phone instead of 8 (Bart, 4 Nov: "so it doesn't
       wrap as much"). */
    padding: 0.9rem 0.85rem 0.9rem calc(0.85rem + 3rem + 0.75rem);  /* box + gap */
    min-height: calc(0.9rem * 2 + 3.7rem);  /* a short card still fits the box */
    margin: 0;
    border: none;
    border-radius: 0;
    border-bottom: 1px solid var(--border);
  }
  .race-table tbody tr:last-child { border-bottom: none; }
  /* A small › on the right, on the chips line (Bart picked mock-up 3, 4 Nov):
     says "this row opens the race" (DECISIONS → Arrows: › marks list rows).
     Low, not centred: the chips line has free space on the right, so the
     name keeps its full width (centred, 6 of 20 names wrapped instead of 3).
     Drawn with two borders, so it needs no icon font. */
  .race-table tr::after {
    content: ""; position: absolute; right: 1rem; bottom: 1.45rem;
    width: 0.5rem; height: 0.5rem; pointer-events: none;
    border-right: 2px solid #A3A9B5; border-top: 2px solid #A3A9B5; transform: rotate(45deg);
  }
  /* border: none — Bootstrap's .table (on /biegi/) draws a line under every
     cell, which inside a card showed up as a line under each row. */
  .race-table td { padding: 0; border: none; }
  /* One rhythm (Bart, 4 Nov: "doesn't seem balanced"; the gaps were 5, 10,
     2 and 11px): name, type, town and price evenly spaced (the big gap under
     the type line read as a hole, Bart 4 Nov), then a step to the chips. */
  .race-table td.name-cell { order: 1; flex-basis: 100%; padding-bottom: 0.25rem; }
  .race-table td.name-cell a { font-size: 1rem; font-weight: 600; line-height: 1.3; }
  /* The type ("Biegi uliczne") + PZLA badge line. Bootstrap's .text-muted is
     !important, hence the !important for the site's grey. */
  .race-table td.name-cell .small { font-weight: 400; font-size: 0.85rem; margin-top: 0.2rem; color: var(--muted) !important; }

  .race-table td.date-cell,
  .race-table td.city-cell { display: block; font-size: 0.9rem; line-height: 1.4; }
  .race-table td.date-cell::before,
  .race-table td.dist-cell::before { content: none; }

  /* The date box, top-aligned: level with the race name, so date + name read
     as a pair and the boxes keep one distance from each row's top, a straight
     column to scan (Material's rule for leading elements in 3+ line rows).
     ~~Centred on the row~~ Superseded 4 Nov: centring made up for the uneven
     gaps, which are fixed; centred boxes zigzag in rows of different height.
     pointer-events: none so a tap on it still reaches the race link's
     stretched ::after underneath. */
  .race-table td.date-cell {
    position: absolute; left: 0.85rem; top: 0.9rem;
    width: 3rem !important;  /* beats the card layout's td { width: auto !important } */
    padding: 0.4rem 0; background: var(--paper); border: 1px solid var(--border); border-radius: 8px;
    text-align: center; line-height: 1; pointer-events: none;
  }
  .race-table td.date-cell .date-full {
    position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
  }  /* visually hidden: screen readers read the full date */
  .race-table td.date-cell .date-box { display: block; }
  .race-table td.date-cell .date-box > span { display: block; line-height: 1.05; }
  .race-table td.date-cell.past .date-box { opacity: 0.55; }
  .race-table td.city-cell { order: 3; flex-basis: 100%; min-width: 0; color: var(--muted); }
  .race-table td.city-cell::before {
    content: "📍";
    font-family: inherit; font-size: 0.8rem; text-transform: none; letter-spacing: 0;
    margin-right: 0.2rem;
  }
  .race-table td.city-cell .cell-value { display: inline; text-align: left; }
  /* Region inline after the town: "Warszawa, mazowieckie" (Bootstrap's
     d-block is !important, hence the !important here). */
  .race-table td.city-cell .cell-value .d-block { display: inline !important; font-size: inherit; }
  .race-table td.city-cell .cell-value .d-block::before { content: ", "; white-space: normal; }
  /* The region never splits ("kujawsko-" / "pomorskie"); the line can still
     break after the comma (the ::before keeps normal wrapping). */
  .race-table td.city-cell .cell-value .d-block { white-space: nowrap; }

  .race-table td.dist-cell { order: 5; flex-basis: 100%; margin-top: 0.6rem; }
  /* Opłata (show_price): its own line under the place, 💳 like the race
     page's facts (back 4 Nov: without it the price looked bare); no line at
     all when there's no price. */
  .race-table td.price-cell { order: 4; flex-basis: 100%; display: block; font-size: 0.9rem; line-height: 1.4; margin-top: 0.25rem; }
  .race-table td.price-cell::before {
    content: "💳";
    font-family: inherit; font-size: 0.8rem; text-transform: none; letter-spacing: 0;
    margin-right: 0.3rem;
  }
  .race-table td.price-cell--none { display: none; }
}

/* --- Atest PZLA: badge and the list toggle -------------------------------
   Shown when this edition's course has a valid PZLA certificate
   (Race.has_current_pzla). Same shape and font as every other tag (.dist-chip),
   light green = "checked" (Bart picked version D, 2026-10-21). Kept light with a
   border so it never reads as the solid green 5 km chip. Hover text on desktop. */
.pzla-badge {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  line-height: 1.4;
  font-weight: 500;
  padding: 0.15rem 0.45rem;
  border-radius: 4px;
  white-space: nowrap;
  background: #E9F6EE;
  color: #17643A;
  border: 1px solid #B9E0C7;
  cursor: help;
}
.name-cell .pzla-badge { margin-left: 0.4rem; padding: 0.05rem 0.4rem; vertical-align: 0.05em; }
/* "Bezpłatny" in a race row (show_price, 11 Nov page): the PZLA badge's shape
   in a warm tint, so free reads as good news, not as another certificate. */
.free-badge { display: inline-block; font-family: var(--font-mono); font-size: 0.7rem; line-height: 1.4; font-weight: 500;
  padding: 0.05rem 0.4rem; border-radius: 4px; white-space: nowrap; vertical-align: 0.05em;
  background: #FEF3C7; color: #92400E; border: 1px solid #F5D78E; }

/* "Brak biegów…" under the 11 Nov page's filter card. */
.filter-empty { margin: 1.5rem 0; color: var(--muted); }

/* 11 Nov page: the breadcrumb sits right above the hero (city-hub's top
   padding and the hero's own 3rem stacked on main's py-5 left ~170px). */
.holiday-page { padding-top: 0; }
.holiday-page .hero { padding: 0.25rem 0 2rem; }
/* One column: hero, filter card and race tables share both edges (the
   homepage hero stops at 860px, this page's column is wider). */
.holiday-page .hero-photo { max-width: none; }
/* 11 Nov page (/biegi/niepodleglosci/): a "Filtry" card (region + distance
   dropdowns, Atest PZLA checkbox) over an open section per region. Same white
   card as the hubs' "Więcej" box. scroll-margin keeps the card and headings
   clear of the top edge after a jump. */
/* The card itself is the shared .fc component (search "The filter card: one
   component"). Here only what's this page's own: its jump target, and the
   town box's magnifier (a typed field, where the dropdowns have a chevron). */
.fc.holiday-filters { margin-top: 0; }  /* straight under the hero */
.holiday-filters__search { position: relative; }
.holiday-filters__search-icon { position: absolute; left: 0.75rem; top: 50%; transform: translateY(-50%);
  color: var(--muted); pointer-events: none; }
.holiday-filters__input { padding-left: 2.35rem; }
.holiday-region[hidden] { display: none; }
/* Phones: the same 16px side margin as the other list pages (town, region,
   month, /biegi/). The page sits in .city-hub, whose own 1rem padding on top
   of the container's doubled it to 32px (Bart, 4 Nov: "is the width OK?"). */
@media (max-width: 576px) {
  .holiday-page { padding-left: 0; padding-right: 0; }
}
/* Phones: no region after the town in the rows. Each section is a region
   with its name right above, so ", kujawsko-pomorskie" repeated it on every
   race and wrapped the place line (Bart, 4 Nov). Desktop keeps its column. */
@media (max-width: 640px) {
  .holiday-page .race-table td.city-cell .cell-value .d-block { display: none !important; }
}
.holiday-empty { text-align: center; }
.holiday-region { margin: 0 0 2.5rem; scroll-margin-top: 1rem; }
.holiday-region__head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 0.25rem 1rem;
  border-bottom: 2px solid var(--ink); padding-bottom: 0.4rem; margin-bottom: 0.75rem; text-align: left; }
.holiday-region__title { font-size: 1.35rem; margin: 0; }
.holiday-region__meta { color: var(--muted); font-size: 0.9rem; }
.holiday-region__more { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 0.25rem 1rem;
  text-align: left; font-size: 0.9rem; margin: 0.5rem 0 0; }
/* The site's link style (like race names in the tables): navy, no underline,
   accent on hover. Not Bootstrap's default blue underline (Bart, 4 Nov). */
/* 500 like the race names in the table (600 read heavy over two lines on a
   phone); padding makes a taller tap target without moving the text. */
.holiday-region__more a { color: var(--ink); font-weight: 500; text-decoration: none; padding: 0.3rem 0; }
.holiday-region__more a:hover { color: var(--accent); }
.holiday-region__more a.holiday-region__top { color: var(--muted); font-weight: 500; margin-left: auto; }
.holiday-region__more a.holiday-region__top:hover { color: var(--accent); }

/* --- List page header (4 Nov, it replaced the breadcrumb) --------------------
   _list_header.html: the season label ("Kalendarz biegów 2026/2027"), the H1,
   the tagline. The hub pages use the same header (.hub-header). */
.list-header { display: grid; gap: 0.35rem; max-width: 1000px; margin: 0 auto; }
.list-header__label { margin: 0; font-size: 0.8rem; font-weight: 700; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--accent); }
.list-header__title { margin: 0; text-wrap: balance; }
.list-header__tagline { margin: 0.2rem auto 0; max-width: 60ch; color: var(--muted); text-wrap: balance; }
/* Hub pages use the same header; the hub wrappers' own 2rem top padding is gone
   so the label sits where it does on list pages (main's padding only). */
.hub-header { margin-bottom: 2rem; }
.month-hub, .city-hub { padding-top: 0; }

/* Under the list (_race_list.html): "Pokaż więcej biegów", the switch to past
   races, and the grey note on a page with nothing upcoming. */
.load-more { display: grid; justify-items: center; gap: 0.4rem; margin: 1.25rem auto 0; }
/* .site-btn: the same outlined button anywhere else (homepage "Zobacz cały kalendarz",
   header "Dodaj swój bieg"; 5 Nov), so all buttons look like "Pokaż więcej biegów". */
.load-more__btn, .site-btn { display: inline-flex; align-items: center; justify-content: center; min-height: 2.75rem;
  padding: 0.5rem 1.5rem; border: 1px solid var(--ink); border-radius: 8px; background: white; color: var(--ink);
  font-weight: 600; text-decoration: none; transition: background-color 0.15s, color 0.15s; }
.load-more__btn:hover, .load-more__btn:focus-visible,
.site-btn:hover, .site-btn:focus-visible { background: var(--ink); color: white; outline: none; }
.site-btn--sm { min-height: 2.25rem; padding: 0.3rem 1rem; font-size: 0.9rem; }
.home-footer-link { text-align: center; margin: 1.5rem 0 0; }
/* Header: right of the menu on desktop; in the open phone menu, a full-width button under the links. */
.nav-add-race { white-space: nowrap; }
@media (max-width: 991.98px) { .nav-add-race { display: flex; margin: 0.25rem 0 0.75rem; } }
/* ~~992-1199px: smaller, tighter menu links so six links + the button fit at 1024px~~
   gone 5 Nov: two links left (the hubs moved to the footer), they fit at full size. */
.navbar .nav-link { white-space: nowrap; }
.load-more.is-loading .load-more__btn { opacity: 0.6; pointer-events: none; }
.load-more__count { margin: 0; color: var(--muted); font-size: 0.85rem; font-variant-numeric: tabular-nums; }
.list-switch { margin: 1.25rem auto 0; }
.list-switch a { color: var(--ink); font-weight: 500; text-decoration: underline; text-underline-offset: 3px;
  text-decoration-color: #B8BCB2; }
.list-switch a:hover { text-decoration-color: currentColor; }
.list-note { max-width: 1000px; margin: 0 auto 1rem; color: var(--muted); }

/* "↑ Filtry" (_filter_card.html, js/filters.js): bottom right, only once the
   card is out of sight above; under the filter sheets (z-index 1040+). */
.to-filters { position: fixed; z-index: 1000; display: inline-flex; align-items: center; min-height: 2.75rem;
  right: calc(1rem + env(safe-area-inset-right, 0px)); bottom: calc(1rem + env(safe-area-inset-bottom, 0px));
  padding: 0 1.1rem; border-radius: 999px; background: var(--ink); color: white; font-weight: 600; font-size: 0.95rem;
  text-decoration: none; box-shadow: 0 6px 20px rgba(20, 33, 61, 0.28);
  opacity: 0; transform: translateY(0.75rem); pointer-events: none; transition: opacity 0.2s, transform 0.2s; }
.to-filters.is-visible { opacity: 1; transform: none; pointer-events: auto; }
.to-filters:hover, .to-filters:focus-visible { color: white; background: #22325A; outline: none; }
.to-filters:focus-visible { box-shadow: 0 0 0 3px rgba(20, 33, 61, 0.3), 0 6px 20px rgba(20, 33, 61, 0.28); }
html.fc-sheet-open .to-filters { display: none; }
@media (prefers-reduced-motion: reduce) { .to-filters { transition: none; } }

/* "Nie ma tu Twojego biegu?" at the end of every list (_missing_race.html). */
.missing-race { max-width: 1000px; margin: 2rem auto 0; padding: 0.9rem 1.1rem; border: 1px dashed #C9CDC3;
  border-radius: 10px; color: var(--muted); font-size: 0.95rem; text-align: center; text-wrap: balance; }
.missing-race a { color: var(--ink); font-weight: 500; text-decoration: underline; text-underline-offset: 3px; white-space: nowrap; }
.missing-race a:hover { color: var(--accent); }

/* Text under a list page's races (_pzla_about.html, 9 Nov). Left-aligned
   reading width inside the centred container; below the list, so it never
   pushes the races down. */
.page-about { max-width: 720px; margin: 2.5rem auto 0; text-align: left; color: var(--ink); line-height: 1.6; }
.page-about__title { font-family: var(--font-display); font-size: 1.35rem; font-weight: 600;
  margin: 2rem 0 0.6rem; color: var(--ink); }
.page-about__title:first-child { margin-top: 0; }
.page-about p { margin: 0 0 0.9rem; }

/* --- The filter card: one component, used twice (B1, 2026-11-03) -----------
   The list pages' card (_filter_card.html: links, js/filters.js) and the 11 Nov
   page's card (independence_day.html: a select, a town box, its own script)
   are one block (Bart, 4 Nov: "made from the same block"): the box, the head,
   the labels, the field look, the panels (a drop-down on desktop, a sheet on
   phones), the checkbox, the line above it and the results line under the
   card all come from these .fc rules. What differs is what an option is: a
   link on the list pages, a button on the 11 Nov page (it filters in place);
   ~~the browser's own dropdown there~~ until 4 Nov (Bart: "the filters work
   differently on the 11 page"). Its typed Miejscowość box stays its own. One
   layout switch: .fc--stack (one column on phones, for long values). The
   11 Nov markup keeps its holiday-* classes as hooks for its script only. */
.fc { position: relative; max-width: 1000px; margin: 1.25rem auto 1.5rem; padding: 1.1rem 1.25rem;
  background: white; border: 1px solid var(--border); border-radius: 12px; text-align: left;
  scroll-margin-top: 1rem; }  /* 16px clear of the screen edge when a choice moves it up */
.fc__head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-bottom: 0.9rem; }
.fc__title { display: flex; align-items: center; gap: 0.5rem; font-weight: 600; color: var(--ink); }
.fc__icon { width: 1.75rem; height: 1.75rem; padding: 0.3rem; border-radius: 6px; background: var(--paper);
  fill: var(--paper); stroke: var(--ink); stroke-width: 1.6; stroke-linecap: round; }
/* "Wczytuję…" while the next list loads (js/filters.js sets .is-loading). */
.fc__loading { display: none; align-items: center; gap: 0.45rem; font-size: 0.85rem; color: var(--muted); }
.is-loading .fc__loading { display: inline-flex; }
.fc__spinner { width: 0.9rem; height: 0.9rem; border: 2px solid var(--border); border-top-color: var(--ink);
  border-radius: 50%; animation: fc-spin 0.7s linear infinite; }
@keyframes fc-spin { to { transform: rotate(360deg); } }

/* One row of fields on desktop (as many columns as fields, --fc-cols), two
   below 992px; .fc-field--wide takes a whole row there (the 11 Nov town box). */
.fc__fields { display: grid; grid-template-columns: repeat(var(--fc-cols, 4), minmax(0, 1fr)); gap: 0.9rem 1rem; }
@media (max-width: 991px) {
  .fc__fields { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .fc-field--wide { grid-column: 1 / -1; }
}

.fc-field { position: relative; min-width: 0; }
.fc-field__label { display: block; margin-bottom: 0.3rem; font-size: 0.85rem; font-weight: 600; color: var(--ink); }

/* The field box, on every control in the card: Bootstrap's .form-select /
   .form-control underneath, the site's border, radius and colour on top. */
.fc-control { border-color: var(--border); border-radius: 8px; color: var(--ink); }
.fc-control::placeholder { color: var(--muted); }
.fc-control:hover:not(:focus) { border-color: #9CA3AF; }
.fc-control:focus, .fc-select[open] > .fc-control {
  outline: none; border-color: var(--ink); box-shadow: 0 0 0 3px rgba(20, 33, 61, 0.15); }

/* The list pages' field: a <details> whose summary is the box. */
.fc-select { position: static; }
.fc-select > summary { list-style: none; cursor: pointer; -webkit-tap-highlight-color: transparent; user-select: none; }
.fc-select > summary::-webkit-details-marker { display: none; }
.fc-select__value { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* A field that's set: navy edge, the value in bold, and its own ✕ left of the
   chevron (a native select can't show one: the list pages' only extra). */
.fc-field.is-set .fc-control { border-color: var(--ink); font-weight: 600; padding-right: 4.1rem; }
.fc-field__clear { position: absolute; right: 2.1rem; bottom: 0.3rem; display: grid; place-items: center;
  width: 1.75rem; height: 1.75rem; border-radius: 50%; color: var(--muted); }
.fc-field__clear svg { width: 0.95rem; height: 0.95rem; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; }
.fc-field__clear:hover, .fc-field__clear:focus-visible { background: var(--paper); color: var(--ink); outline: none; }

/* The panel: a drop-down on desktop. */
.fc-panel { position: absolute; z-index: 30; top: calc(100% + 0.35rem); left: 0; min-width: 100%; width: max-content;
  max-width: min(24rem, calc(100vw - 2rem)); padding: 0.35rem; background: white; border: 1px solid var(--border);
  border-radius: 10px; box-shadow: 0 12px 32px rgba(20, 33, 61, 0.14); }
.fc-field--place .fc-panel { width: 24rem; }  /* the search placeholder fits (Bart, 4 Nov) */
/* When a script scrolls an open list onto the screen (filters.js fitOnScreen, the 11 Nov
   page's fitSuggestions), a little air under it. */
.fc-panel, .holiday-filters .town-search__list { scroll-margin-bottom: 1rem; }
.fc-field:last-child:not(:first-child) .fc-panel { left: auto; right: 0; }
.fc-panel__head, .fc-panel__grab { display: none; }
.fc-panel__search { margin: 0 0 0.35rem; }
.fc-panel__list { list-style: none; margin: 0; padding: 0; max-height: 20rem; overflow-y: auto; overscroll-behavior: contain; }
.fc-panel__list li[hidden] { display: none; }
.fc-panel__group { padding: 0.7rem 0.65rem 0.25rem; font-size: 0.72rem; font-weight: 700; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--muted); }
.fc-panel__empty { margin: 0; padding: 0.6rem 0.65rem; color: var(--muted); font-size: 0.9rem; }

/* One option: label left, count right; ✓ in a fixed slot on the chosen one. */
.fc-opt { display: flex; align-items: center; gap: 0.75rem; min-height: 2.5rem; padding: 0.4rem 0.65rem 0.4rem 1.85rem;
  position: relative; border-radius: 6px; color: var(--ink); text-decoration: none; font-size: 0.95rem; line-height: 1.3; }
a.fc-opt:hover, a.fc-opt:focus-visible,
button.fc-opt:not(:disabled):hover, button.fc-opt:focus-visible { background: var(--paper); color: var(--ink); outline: none; }
/* The 11 Nov page's options are buttons (it filters in place): same look as a link. */
button.fc-opt { width: 100%; margin: 0; border: 0; background: none; text-align: left; font-family: inherit; }
button.fc-opt:not(:disabled) { cursor: pointer; }
button.fc-field__clear { border: 0; background: none; padding: 0; cursor: pointer; }
.fc-field__clear[hidden] { display: none; }
.fc-opt.is-active { font-weight: 600; }
.fc-opt.is-active::before { content: ""; position: absolute; left: 0.7rem; top: 50%; width: 0.4rem; height: 0.7rem;
  margin-top: -0.45rem; border: solid var(--ink); border-width: 0 2px 2px 0; transform: rotate(45deg); }
.fc-opt__label { flex: 1 1 auto; min-width: 0; }
.fc-opt__count { flex-shrink: 0; color: var(--muted); font-size: 0.85rem; font-weight: 400; font-variant-numeric: tabular-nums; }
.fc-opt.is-disabled { color: #A3A8B0; cursor: default; }

/* The line and the Atest PZLA checkbox. On the list pages it's a link with a
   drawn box (.fc-check__box); on the 11 Nov page a real <input>. Same size,
   colours and hover. The row is 44px tall for a thumb but takes 24px of
   layout (the negative margin), so it sits where a plain line of text would. */
.fc__foot { margin-top: 1rem; padding-top: 0.9rem; border-top: 1px solid var(--border); }
.fc-check { display: flex; width: fit-content; align-items: center; gap: 0.6rem; min-height: 2.75rem; margin: -0.625rem 0;
  padding-right: 0.5rem; color: var(--ink); text-decoration: none; cursor: pointer; -webkit-tap-highlight-color: transparent; }
.fc-check:hover { color: var(--ink); }
.fc-check__box, .fc-check .form-check-input { flex-shrink: 0; width: 1.25rem; height: 1.25rem; margin: 0;
  border: 1px solid #B8BCB2; border-radius: 0.25em; cursor: pointer;
  transition: border-color 0.15s, background-color 0.15s, box-shadow 0.15s; }
.fc-check__box { background: white center / contain no-repeat; }
a.fc-check:not(.is-checked):hover .fc-check__box, .fc-check:hover .form-check-input:not(:checked) { border-color: #9CA3AF; }
.fc-check:focus-visible { outline: none; }
.fc-check:focus-visible .fc-check__box, .fc-check .form-check-input:focus {
  box-shadow: 0 0 0 3px rgba(20, 33, 61, 0.15); border-color: var(--ink); }
.fc-check.is-checked .fc-check__box, .fc-check .form-check-input:checked { background-color: var(--ink); border-color: var(--ink); }
.fc-check.is-checked .fc-check__box { background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e"); }
/* Greyed: ticking it would leave no upcoming race. */
.fc-check.is-disabled { color: #A3A8B0; cursor: default; }
.fc-check.is-disabled .fc-check__box { background-color: #F3F4F1; border-color: var(--border); cursor: default; }

/* Results line under the card: count left, links right, closer to the list
   than to the card. "Wyczyść filtry" is a link here, a button on the 11 Nov page. */
.fc-results { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 0.25rem 1rem;
  max-width: 1000px; margin: 0 auto 1.25rem; text-align: left; font-size: 0.95rem; color: var(--ink); }
.fc-results p { margin: 0; }
.fc-results__count { color: var(--muted); }
.fc-results__count strong { color: var(--ink); font-weight: 600; font-variant-numeric: tabular-nums; }
.fc-results__links { display: flex; gap: 1rem; }
.fc-results__links a { color: var(--ink); font-weight: 500; text-decoration: underline; text-underline-offset: 3px;
  text-decoration-color: #B8BCB2; }
.fc-results__links a:hover { text-decoration-color: currentColor; }
.fc-results .fc-results__clear { border: 0; background: none; padding: 0; font: inherit; font-weight: 500;
  color: var(--accent); text-decoration: none; cursor: pointer; }
.fc-results .fc-results__clear:hover { text-decoration: underline; }

/* While the next list loads: the list dims, so a tap feels answered. */
[data-fc-root] .race-table, [data-fc-root] .fc-results__count { transition: opacity 0.15s; }
[data-fc-root].is-loading .race-table, [data-fc-root].is-loading .fc-results__count { opacity: 0.45; }

/* Phones: two compact columns, and each panel becomes a sheet from the bottom. */
@media (max-width: 576px) {
  .fc { padding: 1rem; }
  .fc__fields { gap: 0.75rem 0.6rem; }
  /* .fc--stack: one field per row, for a card whose values are long
     ("Wszystkie województwa", the 11 Nov page). */
  .fc--stack .fc__fields { grid-template-columns: 1fr; }
  /* A set field on a phone: the ✕ takes the chevron's place, so the value has room. */
  .fc-field.is-set .fc-control { background-image: none; padding-right: 2.4rem; }
  /* 44px fields for a thumb (Apple's and Google's minimum; Bootstrap's are 38px),
     on both cards. The ✕ moves down to stay centred. */
  .fc-control { padding-top: 0.5625rem; padding-bottom: 0.5625rem; }
  .fc-field__clear { right: 0.35rem; bottom: 0.5rem; }
  /* The backdrop is the summary's own ::before: tapping it closes the panel, no script needed. */
  .fc-select[open] > summary::before { content: ""; position: fixed; inset: 0; z-index: 1040; background: rgba(20, 33, 61, 0.45); cursor: default; }
  /* The last field's selector too: on desktop its panel opens to the right edge
     (left: auto), which on a phone shrank the sheet to a strip (Bart, 4 Nov). */
  .fc-panel, .fc-field--place .fc-panel, .fc-field:last-child:not(:first-child) .fc-panel {
    position: fixed; z-index: 1050; left: 0; right: 0; top: auto; bottom: 0;
    width: auto; min-width: 0; max-width: none; max-height: 80vh; display: flex; flex-direction: column;
    padding: 0.4rem 0.75rem calc(0.75rem + env(safe-area-inset-bottom)); border: 0; border-radius: 16px 16px 0 0;
    box-shadow: 0 -10px 40px rgba(20, 33, 61, 0.25); animation: fc-sheet 0.18s ease-out;
    transition: transform 0.18s ease-out; }
  /* The handle: says "swipe down to close" (js/filters.js does it). */
  .fc-panel__grab { display: block; flex-shrink: 0; width: 2.25rem; height: 4px; margin: 0.2rem auto 0;
    border-radius: 2px; background: #C9CDC3; }
  .fc-panel__head { display: flex; align-items: center; justify-content: space-between; padding: 0.35rem 0.25rem 0.6rem;
    font-weight: 600; font-size: 1.05rem; color: var(--ink); touch-action: none; }
  .fc-panel__grab { touch-action: none; }
  .fc-panel__close { width: 2.5rem; height: 2.5rem; margin-right: -0.5rem; border: 0; border-radius: 50%; background: none;
    font-size: 1.6rem; line-height: 1; color: var(--muted); }
  .fc-panel__close:hover { background: var(--paper); color: var(--ink); }
  /* Above the phone's keyboard, never under it: --fc-kb is the keyboard's height,
     --fc-room the screen left above it (js/filters.js, fitSheet). Without the
     script (or a keyboard) they fall back to the old bottom: 0 and 80vh. */
  .fc-panel, .fc-field--place .fc-panel, .fc-field:last-child:not(:first-child) .fc-panel {
    bottom: var(--fc-kb, 0px); max-height: min(80vh, calc(var(--fc-room, 100vh) - 1rem)); }
  /* Gdzie keeps its full height while you type, so the box stays put and fewer
     towns just leave space at the bottom. ~~Shrinking to fit~~ (5 Nov): the
     sheet sank behind the keyboard as the list got shorter. */
  .fc-field--place .fc-panel { height: min(80vh, calc(var(--fc-room, 100vh) - 1rem)); }
  .fc-panel__head, .fc-panel__search { flex-shrink: 0; }
  .fc-panel__list { flex: 1 1 auto; min-height: 0; max-height: none; }
  .fc-opt { min-height: 3rem; font-size: 1rem; }
  .fc-results { font-size: 0.9rem; }
  html.fc-sheet-open { overflow: hidden; }
}
@keyframes fc-sheet { from { transform: translateY(1.5rem); opacity: 0; } to { transform: none; opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .fc__spinner, .fc-panel { animation: none; }
}
