/* =====================================================================
   PACIVITAL v0.1 - design system + portal
   Light and dark are both first-class: every colour is a token, and the
   <html data-theme> attribute (set before paint by app.js) decides which
   set is live. Nothing below hard-codes a themed colour.
   ===================================================================== */

@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@400;500;600;700;800&family=Inter:wght@400;500;600;700&display=swap');

/* ---------------------------------------------------------------------
   1. Tokens
   --------------------------------------------------------------------- */
:root {
    --font-heading: 'Outfit', 'Segoe UI', system-ui, -apple-system, sans-serif;
    --font-body: 'Inter', 'Segoe UI', system-ui, -apple-system, sans-serif;

    --radius-sm: 10px;
    --radius: 16px;
    --radius-lg: 24px;
    --radius-pill: 999px;

    --header-h: 64px;
    /* Reading measure for the provider detail panel. */
    --detail-w: 820px;
    /* v2: the picker/results pane is the main event, the map is a small
       locator preview - see section 6 for the min-width safety valve. */
    --sidebar-w: 80%;
    --picker-w: 380px;

    --ease: cubic-bezier(0.4, 0, 0.2, 1);
    --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
    --t: 0.25s var(--ease);

    /* Terracotta. --brand/--brand-2 seed the primary button gradient and the
       ambient glow, so they live outside the theme blocks. */
    --brand: #b04a2f;
    --brand-2: #c9573a;
    --amber: #e0973a;
    /* Nudged cooler and brighter than the rust primary: a destructive action
       has to read as clearly different from a normal one, and the old red sat
       too close to #a8412a to do that. */
    --danger: #cc2936;
    --info: #3d8bfd;
}

/* --- light (default) --- */
:root,
:root[data-theme='light'] {
    color-scheme: light;

    --bg: #fbf6f1;
    --bg-2: #f3e9e1;
    --surface: rgba(255, 255, 255, 0.86);
    --surface-solid: #ffffff;
    --surface-2: #f7efe9;
    --surface-hover: #f1e5dc;

    --text: #2e1f18;
    --text-strong: #1c120d;
    --muted: #6e574b;
    --faint: #9a8375;

    --border: rgba(58, 34, 22, 0.10);
    --border-strong: rgba(58, 34, 22, 0.20);

    --primary: #a8412a;
    --primary-soft: rgba(168, 65, 42, 0.10);
    --primary-glow: rgba(168, 65, 42, 0.22);
    --on-primary: #ffffff;

    --accent: #b5762a;
    --accent-soft: rgba(181, 118, 42, 0.14);

    /* Shadows carry the warmth too - a neutral grey shadow over a warm ivory
       page reads as dirt rather than depth. */
    --shadow-sm: 0 1px 2px rgba(60, 34, 22, 0.06), 0 2px 8px rgba(60, 34, 22, 0.05);
    --shadow: 0 4px 12px rgba(60, 34, 22, 0.08), 0 12px 28px rgba(60, 34, 22, 0.07);
    --shadow-lg: 0 8px 20px rgba(60, 34, 22, 0.10), 0 24px 48px rgba(60, 34, 22, 0.12);

    --blur: blur(18px) saturate(1.4);
    --scrim: rgba(45, 26, 17, 0.45);
    --map-scrim: rgba(70, 42, 28, 0.10);
}

/* --- dark --- */
:root[data-theme='dark'] {
    color-scheme: dark;

    /* NOT TUNED YET. Carried over to the terracotta family so a visitor whose
       OS is in dark mode gets the same brand rather than the old teal, but the
       balance has not been worked through - that is a separate pass. */
    --bg: #120d0a;
    --bg-2: #1a120e;
    --surface: rgba(30, 22, 18, 0.78);
    --surface-solid: #1e1612;
    --surface-2: #241a15;
    --surface-hover: #2d211a;

    --text: #f2e9e3;
    --text-strong: #ffffff;
    --muted: #b09c8f;
    --faint: #86746a;

    --border: rgba(255, 255, 255, 0.09);
    --border-strong: rgba(255, 255, 255, 0.16);

    --primary: #e0795c;
    --primary-soft: rgba(224, 121, 92, 0.14);
    --primary-glow: rgba(224, 121, 92, 0.26);
    --on-primary: #2a0f07;

    --accent: #e0a44a;
    --accent-soft: rgba(224, 164, 74, 0.16);

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
    --shadow: 0 6px 18px rgba(0, 0, 0, 0.45);
    --shadow-lg: 0 16px 44px rgba(0, 0, 0, 0.6);

    --blur: blur(18px) saturate(1.2);
    --scrim: rgba(0, 0, 0, 0.6);
    --map-scrim: rgba(0, 0, 0, 0.26);
}

/* ---------------------------------------------------------------------
   2. Base
   --------------------------------------------------------------------- */
/* The UA stylesheet's [hidden] { display: none } loses to any author rule that
   sets display - which is how the admin ended up rendering both of its views
   side by side. Make the attribute win everywhere so `hidden` always means
   hidden. */
[hidden] { display: none !important; }

*, *::before, *::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
    -webkit-tap-highlight-color: transparent;
}

html, body {
    height: 100%;
}

body {
    background: var(--bg);
    color: var(--text);
    font-family: var(--font-body);
    font-size: 15px;
    line-height: 1.55;
    -webkit-font-smoothing: antialiased;
    overflow: hidden;
    transition: background-color 0.3s var(--ease), color 0.3s var(--ease);
}

h1, h2, h3, h4 {
    font-family: var(--font-heading);
    font-weight: 700;
    letter-spacing: -0.015em;
    color: var(--text-strong);
    line-height: 1.25;
}

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

button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; background: none; border: none; }

svg { flex: none; }

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

::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
    background: var(--border-strong);
    border-radius: var(--radius-pill);
}
::-webkit-scrollbar-thumb:hover { background: var(--faint); }

.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;
}

/* ---------------------------------------------------------------------
   3. Ambient background glow (kept subtle in light mode)
   --------------------------------------------------------------------- */
.ambient {
    position: fixed;
    inset: 0;
    z-index: 0;
    overflow: hidden;
    pointer-events: none;
}
.ambient span {
    position: absolute;
    border-radius: 50%;
    filter: blur(90px);
    opacity: 0.35;
}
.ambient span:nth-child(1) {
    top: -12%; left: -8%;
    width: 42vw; height: 42vw;
    background: var(--brand);
}
.ambient span:nth-child(2) {
    bottom: -18%; right: -10%;
    width: 46vw; height: 46vw;
    background: var(--amber);
    opacity: 0.22;
}
:root[data-theme='dark'] .ambient span { opacity: 0.16; }
:root[data-theme='dark'] .ambient span:nth-child(2) { opacity: 0.12; }

/* ---------------------------------------------------------------------
   4. Shared atoms
   --------------------------------------------------------------------- */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 11px 18px;
    border-radius: var(--radius-pill);
    border: 1px solid transparent;
    font-family: var(--font-heading);
    font-weight: 600;
    font-size: 0.92rem;
    white-space: nowrap;
    transition: var(--t);
}
.btn svg { width: 18px; height: 18px; fill: currentColor; }

.btn-primary {
    background: linear-gradient(135deg, var(--brand-2), var(--primary));
    color: var(--on-primary);
    box-shadow: 0 4px 14px var(--primary-glow);
}
.btn-primary:hover { transform: translateY(-1px); box-shadow: 0 8px 22px var(--primary-glow); }
.btn-primary:active { transform: translateY(0); }

.btn-ghost {
    background: var(--surface-2);
    border-color: var(--border);
    color: var(--text);
}
.btn-ghost:hover { background: var(--surface-hover); border-color: var(--border-strong); }

.btn-danger {
    background: transparent;
    border-color: rgba(226, 87, 76, 0.4);
    color: var(--danger);
}
.btn-danger:hover { background: var(--danger); color: #fff; border-color: var(--danger); }

.btn-block { width: 100%; }
.btn:disabled { opacity: 0.55; pointer-events: none; }

/* ---------- "More" menu ----------
   Collapsed it is one circle in the header row. Opened it drops a vertical
   pill holding a circle per destination. Same <details> pattern as the
   language switcher: the entries are links, so no JavaScript is involved. */
.menu-pill { position: relative; }

.menu-pill > summary {
    list-style: none;
    cursor: pointer;
    user-select: none;
}
.menu-pill > summary::-webkit-details-marker { display: none; }
.menu-pill > summary::marker { content: ''; }
.menu-pill[open] > summary {
    background: var(--primary);
    border-color: var(--primary);
    color: var(--on-primary);
}

.menu-stack {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    z-index: 80;
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 8px;
    /* The container itself is the pill; the entries are the circles in it. */
    border-radius: var(--radius-pill);
    background: var(--surface-solid);
    border: 1px solid var(--border-strong);
    box-shadow: var(--shadow-lg);
}

.menu-item {
    /* Inherits .icon-btn sizing; only the hover treatment differs. */
    transition: background 0.18s var(--ease), color 0.18s var(--ease), transform 0.18s var(--ease);
}
.menu-item:hover,
.menu-item:focus-visible {
    background: var(--primary);
    border-color: var(--primary);
    color: var(--on-primary);
    transform: scale(1.06);
    text-decoration: none;
}

/* The circle carries the meaning; the text is there for screen readers and as
   the native tooltip via title=. */
.menu-label {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

/* An animal whose service list has not been written yet. Still pickable - it
   just says so rather than pretending to be empty by accident. */
.cat-card.is-thin .cat-tagline {
    color: var(--accent);
    font-style: italic;
}

/* ---------- Language switcher ----------
   <details>/<summary> rather than a scripted dropdown: switching language is a
   link that reloads the page anyway, so this needs no JS and stays keyboard
   accessible. Shared by the portal and the admin console. */
.lang-switch { position: relative; }

.lang-switch > summary {
    list-style: none;
    cursor: pointer;
    user-select: none;
}
.lang-switch > summary::-webkit-details-marker { display: none; }
.lang-switch > summary::marker { content: ''; }

.lang-code {
    font-family: var(--font-heading);
    font-size: 0.76rem;
    font-weight: 800;
    letter-spacing: 0.04em;
}
.lang-switch[open] > summary {
    background: var(--primary);
    border-color: var(--primary);
    color: var(--on-primary);
}

.lang-menu {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    z-index: 80;
    min-width: 176px;
    margin: 0;
    padding: 6px;
    list-style: none;
    background: var(--surface-solid);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    box-shadow: var(--shadow-lg);
}
.lang-menu a {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 10px;
    border-radius: 8px;
    color: var(--text);
    font-size: 0.88rem;
    text-decoration: none;
}
.lang-menu a:hover { background: var(--surface-hover); text-decoration: none; }
.lang-menu a.is-active { background: var(--primary-soft); color: var(--primary); font-weight: 700; }
.lang-abbr {
    flex: none;
    width: 26px;
    font-size: 0.7rem;
    font-weight: 800;
    letter-spacing: 0.04em;
    color: var(--faint);
}
.lang-menu a.is-active .lang-abbr { color: var(--primary); }

.icon-btn {
    width: 40px; height: 40px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-pill);
    border: 1px solid var(--border);
    background: var(--surface-2);
    color: var(--muted);
    transition: var(--t);
}
.icon-btn svg { width: 19px; height: 19px; fill: currentColor; }
.icon-btn:hover { color: var(--primary); border-color: var(--primary); background: var(--primary-soft); }

/* The blog button spells it out. A page-with-lines glyph reads as
   "document" more than "blog", and at 19px the lines barely register. */
.menu-word {
    font-family: var(--font-heading);
    font-size: 0.58rem;
    font-weight: 800;
    letter-spacing: 0.04em;
    line-height: 1;
    color: currentColor;
    pointer-events: none;
}

.chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 7px 13px;
    border-radius: var(--radius-pill);
    border: 1px solid var(--border);
    background: var(--surface-2);
    color: var(--muted);
    font-size: 0.82rem;
    font-weight: 600;
    white-space: nowrap;
    transition: var(--t);
}
.chip:hover { border-color: var(--border-strong); color: var(--text); }
.chip.is-active {
    background: var(--primary);
    border-color: var(--primary);
    color: var(--on-primary);
    box-shadow: 0 3px 10px var(--primary-glow);
}
.chip .chip-emoji { font-size: 0.95rem; line-height: 1; }

.badge {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 9px;
    border-radius: var(--radius-pill);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    background: var(--surface-2);
    color: var(--muted);
    border: 1px solid var(--border);
}
.badge svg { width: 12px; height: 12px; fill: currentColor; }
.badge-primary { background: var(--primary-soft); color: var(--primary); border-color: transparent; }
.badge-accent  { background: var(--accent-soft);  color: var(--accent);  border-color: transparent; }

.field { margin-bottom: 16px; }
.field label {
    display: block;
    font-size: 0.78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--muted);
    margin-bottom: 7px;
}
.input, .select, .textarea {
    width: 100%;
    padding: 11px 14px;
    background: var(--surface-solid);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    color: var(--text);
    font-size: 0.93rem;
    transition: var(--t);
}
.textarea { min-height: 96px; resize: vertical; line-height: 1.6; }
.input:focus, .select:focus, .textarea:focus {
    outline: none;
    border-color: var(--primary);
    box-shadow: 0 0 0 3px var(--primary-soft);
}
.input.has-error, .select.has-error { border-color: var(--danger); }
.field-error { color: var(--danger); font-size: 0.78rem; margin-top: 5px; display: none; }
.field-error.is-visible { display: block; }
.field-hint { color: var(--faint); font-size: 0.78rem; margin-top: 5px; }

.switch {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    cursor: pointer;
    user-select: none;
}
.switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.switch .track {
    width: 42px; height: 24px;
    border-radius: var(--radius-pill);
    background: var(--border-strong);
    position: relative;
    transition: var(--t);
    flex: none;
}
.switch .track::after {
    content: '';
    position: absolute;
    top: 3px; left: 3px;
    width: 18px; height: 18px;
    border-radius: 50%;
    background: #fff;
    box-shadow: var(--shadow-sm);
    transition: var(--t);
}
.switch input:checked + .track { background: var(--primary); }
.switch input:checked + .track::after { transform: translateX(18px); }
.switch input:focus-visible + .track { outline: 2px solid var(--primary); outline-offset: 2px; }

/* ---------------------------------------------------------------------
   5. Header
   --------------------------------------------------------------------- */
.app {
    position: relative;
    z-index: 1;
    height: 100%;
    display: flex;
    flex-direction: column;
}

.app-header {
    height: var(--header-h);
    flex: none;
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 0 18px;
    background: var(--surface);
    backdrop-filter: var(--blur);
    -webkit-backdrop-filter: var(--blur);
    border-bottom: 1px solid var(--border);
    /* Above .detail (70). The header creates a stacking context, so the
       z-index on .menu-stack / .lang-menu only orders them *within* it - at 40
       the whole header, dropdowns included, painted under an open profile
       panel and the menu became invisible. The header never overlaps the
       detail geometrically (the panel starts below it), so sitting on top
       costs nothing. */
    z-index: 90;
}

.brand {
    display: flex;
    align-items: center;
    gap: 10px;
    color: var(--primary);
    text-decoration: none;
    flex: none;
}
.brand:hover { text-decoration: none; }
.brand img { width: 30px; height: 30px; }
.brand-text { display: flex; flex-direction: column; line-height: 1.05; }
.brand-name {
    font-family: var(--font-heading);
    font-weight: 800;
    font-size: 1.2rem;
    letter-spacing: -0.02em;
    color: var(--text-strong);
}
.brand-sub {
    font-size: 0.66rem;
    font-weight: 600;
    letter-spacing: 0.13em;
    text-transform: uppercase;
    color: var(--faint);
}

.header-search {
    position: relative;
    flex: 1;
    max-width: 460px;
}

/* Only ever shown while the mobile search is expanded - there is room for the
   field itself but not for the button that opened it, which the overlay covers. */
.search-close {
    display: none;
    position: absolute;
    right: 5px;
    top: 50%;
    transform: translateY(-50%);
    width: 34px;
    height: 34px;
    align-items: center;
    justify-content: center;
    border: 0;
    border-radius: 50%;
    background: var(--surface-hover);
    color: var(--muted);
    cursor: pointer;
    transition: background 0.18s var(--ease), color 0.18s var(--ease), transform 0.18s var(--ease);
}
/* Has to out-rank the magnifier rule below, which absolutely positions any
   svg inside .header-search. That rule is later in the file at the same
   specificity (0,1,1), so the plain `.search-close svg` this replaces never
   won: the X was being placed at left:14px inside a 34px button, sitting
   5.5px right of centre, and kept the magnifier's faint fill so it stayed
   brown on the hover background. One extra class settles both. */
.header-search .search-close svg {
    position: static;
    transform: none;
    width: 19px;
    height: 19px;
    fill: currentColor;
    pointer-events: none;
}
.search-close:hover,
.search-close:focus-visible {
    background: var(--primary);
    color: var(--on-primary);
}
.search-close:active { transform: translateY(-50%) scale(0.92); }
.header-search svg {
    position: absolute;
    left: 14px; top: 50%;
    transform: translateY(-50%);
    width: 17px; height: 17px;
    fill: var(--faint);
    pointer-events: none;
}
.header-search input {
    width: 100%;
    padding: 10px 14px 10px 40px;
    border-radius: var(--radius-pill);
    border: 1px solid var(--border);
    background: var(--surface-2);
    color: var(--text);
    font-size: 0.9rem;
    transition: var(--t);
}
.header-search input::placeholder { color: var(--faint); }
.header-search input:focus {
    outline: none;
    border-color: var(--primary);
    background: var(--surface-solid);
    box-shadow: 0 0 0 3px var(--primary-soft);
}

.header-actions {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-left: auto;
}

.theme-toggle svg { transition: transform 0.4s var(--ease-out); }
.theme-toggle .icon-sun { display: none; }
:root[data-theme='dark'] .theme-toggle .icon-sun { display: block; }
:root[data-theme='dark'] .theme-toggle .icon-moon { display: none; }
.theme-toggle:hover svg { transform: rotate(25deg); }

/* ---------------------------------------------------------------------
   6. Layout: list + map
   --------------------------------------------------------------------- */
.app-body {
    flex: 1;
    min-height: 0;
    position: relative;
    overflow-y: auto;
}

/* v3 is one scrolling column at every width. The funnel is answered top to
   bottom, so source order is already the chronological order the mobile
   layout needs - there is nothing left for a media query to re-stack. */
.flow {
    max-width: 1080px;
    margin: 0 auto;
    padding: 24px 20px 64px;
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.flow-head { margin-bottom: 2px; }
.flow-head h1 {
    font-family: var(--font-heading);
    font-size: 1.6rem;
    font-weight: 800;
    letter-spacing: -0.02em;
    margin-bottom: 6px;
}
.flow-head p {
    font-size: 0.9rem;
    color: var(--muted);
    line-height: 1.55;
}

/* ---------- A step in the funnel ---------- */
.step {
    background: var(--surface);
    backdrop-filter: var(--blur);
    -webkit-backdrop-filter: var(--blur);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 16px 18px;
    transition: opacity 0.25s ease, border-color 0.25s ease;
}

/* Locked steps stay visible so the shape of the journey is legible, but
   their controls are gone rather than merely dimmed - a disabled-looking
   control that still responds is worse than one that is not there. */
.step.is-locked {
    opacity: 0.6;
    border-style: dashed;
}
.step.is-locked .step-body { display: none; }
.step.is-locked .step-locked-note { display: block; }

.step-locked-note {
    display: none;
    margin-top: 10px;
    font-size: 0.82rem;
    color: var(--faint);
    font-style: italic;
}

.step-head {
    display: flex;
    align-items: flex-start;
    gap: 12px;
}

.step-index {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    background: var(--primary-soft);
    color: var(--primary);
    font-size: 0.8rem;
    font-weight: 800;
    margin-top: 1px;
}
.step.is-locked .step-index {
    background: var(--border);
    color: var(--faint);
}

.step-titles { flex: 1; min-width: 0; }
.step-titles h2 {
    font-family: var(--font-heading);
    font-size: 1rem;
    font-weight: 700;
    letter-spacing: -0.01em;
}
.step-hint {
    font-size: 0.8rem;
    color: var(--muted);
    margin-top: 2px;
    line-height: 1.45;
}

.step-chosen {
    flex: none;
    padding: 4px 10px;
    border-radius: var(--radius-pill);
    background: var(--primary-soft);
    color: var(--primary);
    font-size: 0.78rem;
    font-weight: 700;
}

.step-count {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    height: 20px;
    padding: 0 6px;
    border-radius: var(--radius-pill);
    background: var(--primary);
    color: var(--on-primary);
    font-size: 0.7rem;
    font-weight: 700;
}

.step-body { margin-top: 14px; }

.tag-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

/* ---------- Step 0: location ---------- */

/* Every .step sets backdrop-filter, which makes it a stacking context — so the
   dropdown's own z-index only orders it *inside* this card, and the step cards
   below it painted straight over the open list. Lifting the whole card is what
   actually puts the list on top. Kept under the header (40) so it can never
   cover the brand bar; the list only ever opens downward anyway. */
.step-location {
    position: relative;
    z-index: 20;
}
/* `align-items: end` used to bottom-align three cells whose insides differ —
   the combo grows a "chosen town" line, the button had no label at all — so
   the controls sat at three different heights and shifted as you interacted.
   Every cell is now label + control and starts at the same top, which keeps
   the controls on one line no matter what appears underneath them. */
.location-grid {
    /* Two cells since the "use my location" button went: the postal field and
       the radius slider. */
    display: grid;
    grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
    gap: 16px;
    align-items: start;
}

/* Deliberately not `.field` — that class already belongs to the admin form
   system, whose `.field label` rule (0,1,1) outranks `.field-label` (0,1,0)
   and was quietly resizing this label out of alignment. */
.loc-field, .combo { min-width: 0; }

.field-label {
    display: block;
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--faint);
    margin-bottom: 6px;
}

.combo { position: relative; }

.combo-input {
    display: flex;
    align-items: center;
    gap: 8px;
    height: 42px;
    padding: 0 10px;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    background: var(--surface-2);
}
.combo-input:focus-within { border-color: var(--primary); }
.combo-input svg { width: 17px; height: 17px; fill: var(--faint); flex: none; }
.combo-input input {
    flex: 1;
    min-width: 0;
    border: 0;
    background: none;
    color: var(--text);
    font: inherit;
    font-size: 0.9rem;
    outline: none;
}
.combo-clear {
    flex: none;
    border: 0;
    background: none;
    color: var(--faint);
    cursor: pointer;
    font-size: 0.85rem;
    padding: 2px 4px;
    border-radius: 6px;
}
.combo-clear:hover { color: var(--text); background: var(--surface-3); }

.combo-list {
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    right: 0;
    z-index: 60;
    max-height: 264px;
    overflow-y: auto;
    padding: 6px;
    margin: 0;
    list-style: none;
    background: var(--surface-solid, var(--surface-2));
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    box-shadow: var(--shadow-lg);
}

.combo-option {
    display: grid;
    grid-template-columns: auto 1fr;
    grid-template-areas: "code place" "code sub";
    column-gap: 10px;
    padding: 7px 9px;
    border-radius: 8px;
    cursor: pointer;
}
.combo-option:hover, .combo-option.is-active { background: var(--primary-soft); }
.combo-code {
    grid-area: code;
    align-self: center;
    font-variant-numeric: tabular-nums;
    font-weight: 700;
    font-size: 0.85rem;
    color: var(--primary);
}
.combo-place { grid-area: place; font-size: 0.88rem; font-weight: 600; }
.combo-sub   { grid-area: sub; font-size: 0.75rem; color: var(--faint); }

.combo-chosen {
    margin-top: 6px;
    font-size: 0.8rem;
    color: var(--primary);
    font-weight: 600;
}

/* ---------- Search radius slider ----------
   Replaces the dropdown: the value is a distance, and a distance reads better
   as a position on a track than as a list. 0 sits at the far left and means
   "whole country", so "no limit" is a place on the same control rather than a
   separate mode. */
.range-pill {
    -webkit-appearance: none;
    appearance: none;
    display: block;
    width: 100%;
    height: 42px;              /* matches the postal field beside it */
    margin: 0;
    padding: 0 14px;
    background: var(--surface-2);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-pill);
    cursor: pointer;
}
.range-pill:disabled { opacity: 0.5; cursor: not-allowed; }
.range-pill:focus-visible { outline: none; border-color: var(--primary); }

/* The track and thumb need vendor-specific rules; they cannot be combined into
   one selector list because an unknown pseudo-element invalidates the whole
   rule in every browser that does not know it. */
.range-pill::-webkit-slider-runnable-track {
    height: 6px;
    border-radius: var(--radius-pill);
    background: var(--border-strong);
}
.range-pill::-moz-range-track {
    height: 6px;
    border-radius: var(--radius-pill);
    background: var(--border-strong);
}
.range-pill::-moz-range-progress {
    height: 6px;
    border-radius: var(--radius-pill);
    background: var(--primary);
}
.range-pill::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 22px;
    height: 22px;
    margin-top: -8px;          /* centres a 22px thumb on a 6px track */
    border: 0;
    border-radius: 50%;
    background: var(--primary);
    box-shadow: 0 0 0 4px var(--primary-soft);
}
.range-pill::-moz-range-thumb {
    width: 22px;
    height: 22px;
    border: 0;
    border-radius: 50%;
    background: var(--primary);
    box-shadow: 0 0 0 4px var(--primary-soft);
}

.range-readout {
    float: right;
    text-transform: none;
    letter-spacing: 0;
    font-size: 0.76rem;
    font-weight: 700;
    color: var(--primary);
}
.range-pill:disabled + .range-ticks,
.range-pill:disabled ~ .range-ticks { opacity: 0.5; }

.range-ticks {
    display: flex;
    justify-content: space-between;
    margin-top: 5px;
    padding: 0 4px;
    font-size: 0.68rem;
    color: var(--faint);
}

/* The chosen postal code on the map. Not "you" - it is the place that was
   picked, which is the whole point of dropping GPS. */
.origin-dot {
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: var(--primary);
    border: 3px solid var(--surface-solid);
    box-shadow: 0 0 0 3px var(--primary-glow), var(--shadow-sm);
}

.select {
    /* Block, not inline-block: a baseline-aligned control picks up the line
       box's descender space and sits a couple of pixels below its neighbours. */
    display: block;
    width: 100%;
    height: 42px;
    padding: 0 10px;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    background: var(--surface-2);
    color: var(--text);
    font: inherit;
    font-size: 0.88rem;
    cursor: pointer;
}
.select:disabled { opacity: 0.5; cursor: not-allowed; }
.select:focus { outline: none; border-color: var(--primary); }

/* ---------- Step 1: category cards ---------- */
.card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
    gap: 10px;
}

.cat-card {
    display: flex;
    align-items: flex-start;
    gap: 11px;
    padding: 13px;
    text-align: left;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    background: var(--surface-2);
    color: var(--text);
    font: inherit;
    cursor: pointer;
    transition: border-color 0.18s ease, background 0.18s ease, transform 0.18s ease;
}
.cat-card:hover { border-color: var(--primary); transform: translateY(-1px); }
.cat-card.is-active {
    border-color: var(--primary);
    background: var(--primary-soft);
}
.cat-emoji { font-size: 1.4rem; line-height: 1.1; flex: none; }
.cat-text { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.cat-name { font-size: 0.93rem; font-weight: 700; }
.cat-tagline { font-size: 0.78rem; color: var(--muted); line-height: 1.4; }

.match-toggle { align-items: flex-start; gap: 12px; margin-top: 14px; }
.match-toggle .track { margin-top: 2px; }
.match-toggle-text { display: flex; flex-direction: column; gap: 2px; }
.match-toggle-text strong { font-size: 0.85rem; }
.match-toggle-text small { font-size: 0.76rem; color: var(--muted); line-height: 1.4; }

.result-pane {
    min-width: 0;
    display: flex;
    flex-direction: column;
    scroll-margin-top: 12px;
}

.active-filters {
    flex: none;
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    padding: 12px 16px 0;
}
.active-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 6px 4px 11px;
    border-radius: var(--radius-pill);
    background: var(--primary-soft);
    color: var(--primary);
    font-size: 0.78rem;
    font-weight: 600;
}
.active-pill button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 16px; height: 16px;
    border-radius: 50%;
    background: var(--primary);
    color: var(--on-primary);
    line-height: 1;
    font-size: 0.7rem;
}
.active-pill button:hover { filter: brightness(1.1); }

.filter-summary {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 12px 16px 8px;
    font-size: 0.82rem;
    color: var(--muted);
}
.filter-summary strong { color: var(--text-strong); font-weight: 700; }
.link-btn {
    color: var(--primary);
    font-size: 0.82rem;
    font-weight: 600;
    padding: 2px;
}
.link-btn:hover { text-decoration: underline; }

.results {
    /* Not a scroll container: .app-body scrolls the whole page in v3. This
       kept `overflow-y: auto` + `overscroll-behavior: contain` from v2, when
       it was a pane inside a fixed-height sidebar. `contain` blocks scroll
       chaining to the parent, so a touch that began on a card was trapped in
       a box with nothing to scroll - the list only moved when you dragged the
       margins beside it. */
    padding: 4px 16px 16px;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
    align-content: start;
    gap: 10px;
}

/* ---------------------------------------------------------------------
   7. Doctor card
   --------------------------------------------------------------------- */
.doc-card {
    display: flex;
    flex: none;          /* the results column scrolls; cards must not shrink */
    gap: 12px;
    padding: 13px;
    border-radius: var(--radius);
    border: 1px solid var(--border);
    background: var(--surface-solid);
    box-shadow: var(--shadow-sm);
    cursor: pointer;
    text-align: left;
    width: 100%;
    transition: var(--t);
    position: relative;
    overflow: hidden;
}
.doc-card::before {
    content: '';
    position: absolute;
    left: 0; top: 0; bottom: 0;
    width: 3px;
    background: var(--primary);
    transform: scaleY(0);
    transform-origin: center;
    transition: transform 0.3s var(--ease-out);
}
.doc-card:hover {
    border-color: var(--border-strong);
    box-shadow: var(--shadow);
    transform: translateY(-1px);
}
.doc-card.is-active { border-color: var(--primary); background: var(--primary-soft); }
.doc-card.is-active::before { transform: scaleY(1); }

.doc-avatar {
    width: 52px; height: 52px;
    border-radius: 50%;
    flex: none;
    border: 2px solid var(--border);
    background: var(--surface-2);
}
.doc-card.is-active .doc-avatar { border-color: var(--primary); }

/* The card is a <button>, so its inner spans need blockifying by hand. */
.doc-main { display: block; flex: 1; min-width: 0; }
/* Both of these wrap onto a second line rather than being cut with an
   ellipsis. "Veterinárna nemocnica Dúbrava" needed 239px in a 153px box and
   arrived as "Veterinárna nemocn…", which is not a name anybody can act on;
   four of the twelve listings were losing their names, and two vets were
   losing their surnames.

   The card cannot get wider as a result, and that is not left to chance:
   .results sizes its columns as minmax(230px, 1fr) - a share of the container,
   never of the content - .doc-card is width:100% of that track, and .doc-main
   carries min-width:0 so a long line can shrink instead of pushing. The card
   grows downwards only. overflow-wrap is the last resort for a single word
   longer than the box, which would otherwise be the one thing that could
   still overflow; ordinary names break at the space, as they should. */
.doc-name {
    display: block;
    font-family: var(--font-heading);
    font-weight: 700;
    font-size: 1rem;
    color: var(--text-strong);
    overflow-wrap: break-word;
}
.doc-clinic {
    display: block;
    font-size: 0.82rem;
    color: var(--muted);
    overflow-wrap: break-word;
}
.doc-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    margin-top: 8px;
}
.doc-animals {
    display: block;
    font-size: 0.95rem;
    letter-spacing: 1px;
    margin-top: 7px;
}
.doc-range {
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: 0.76rem;
    font-weight: 700;
    color: var(--primary);
}
.doc-range svg { width: 13px; height: 13px; fill: currentColor; }

/* ---------------------------------------------------------------------
   8. Empty / loading states
   --------------------------------------------------------------------- */
.state {
    text-align: center;
    padding: 48px 22px;
    color: var(--muted);
}
.state svg { width: 46px; height: 46px; fill: var(--border-strong); margin-bottom: 12px; }
.state h3 { font-size: 1.02rem; margin-bottom: 5px; }
.state p { font-size: 0.87rem; }

.skeleton {
    flex: none;
    height: 80px;
    border-radius: var(--radius);
    background: linear-gradient(100deg, var(--surface-2) 30%, var(--surface-hover) 50%, var(--surface-2) 70%);
    background-size: 220% 100%;
    animation: shimmer 1.3s infinite linear;
}
@keyframes shimmer {
    from { background-position: 180% 0; }
    to   { background-position: -20% 0; }
}

/* ---------------------------------------------------------------------
   9. Map
   --------------------------------------------------------------------- */
/* v3: the map stopped being the stage. It is a supporting strip at the end
   of the flow - useful for orienting yourself once the list has narrowed,
   but never competing with the picker for attention. */
.map-strip {
    background: var(--surface);
    backdrop-filter: var(--blur);
    -webkit-backdrop-filter: var(--blur);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 14px 16px 16px;
    scroll-margin-top: 12px;
}

.map-strip-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 12px;
}
.map-strip-head h2 {
    font-family: var(--font-heading);
    font-size: 0.95rem;
    font-weight: 700;
}
.map-strip-tools { display: flex; gap: 6px; }
.map-strip-tools .icon-btn { width: 34px; height: 34px; }
.map-strip-tools .icon-btn svg { width: 16px; height: 16px; }

#map {
    height: 300px;
    border-radius: var(--radius);
    overflow: hidden;
    border: 1px solid var(--border);
    z-index: 1;
}
.leaflet-container {
    background: var(--bg-2);
    font-family: var(--font-body);
}

.map-overlay {
    position: absolute;
    z-index: 500;
    pointer-events: none;
}
.map-overlay > * { pointer-events: auto; }

.map-tools {
    top: 14px; right: 14px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.map-tools .icon-btn {
    width: 42px; height: 42px;
    background: var(--surface);
    backdrop-filter: var(--blur);
    -webkit-backdrop-filter: var(--blur);
    box-shadow: var(--shadow-sm);
    color: var(--text);
}
.map-tools .icon-btn.is-active {
    background: var(--primary);
    border-color: var(--primary);
    color: var(--on-primary);
}

/* Sits under the map now rather than floating on top of it — there is no
   longer a full-bleed map surface to overlay. */
.map-legend {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-top: 10px;
    font-size: 0.76rem;
    color: var(--muted);
    font-weight: 600;
}
.legend-item { display: flex; align-items: center; gap: 7px; }
.legend-dot {
    width: 12px; height: 12px;
    border-radius: 50%;
    flex: none;
}
.legend-dot.base { background: var(--primary); box-shadow: 0 0 0 3px var(--primary-soft); }
.legend-dot.range { background: var(--primary-soft); border: 1.5px dashed var(--primary); }
.legend-dot.you { background: var(--info); box-shadow: 0 0 0 3px rgba(61, 139, 253, 0.25); }

/* Leaflet control restyle */
.leaflet-control-zoom {
    border: 1px solid var(--border) !important;
    border-radius: var(--radius-sm) !important;
    overflow: hidden;
    box-shadow: var(--shadow-sm) !important;
}
.leaflet-control-zoom a {
    background: var(--surface-solid) !important;
    color: var(--text) !important;
    border-bottom: 1px solid var(--border) !important;
    width: 34px !important;
    height: 34px !important;
    line-height: 34px !important;
    font-size: 18px !important;
}
.leaflet-control-zoom a:hover { background: var(--primary-soft) !important; color: var(--primary) !important; }
.leaflet-control-attribution {
    background: var(--surface) !important;
    color: var(--faint) !important;
    font-size: 10px !important;
    border-radius: var(--radius-pill) 0 0 0;
    padding: 2px 8px !important;
}
.leaflet-control-attribution a { color: var(--muted) !important; }

/* Map markers */
.pin { background: none; border: none; }
.pin-inner {
    width: 40px; height: 40px;
    border-radius: 50%;
    background: var(--surface-solid);
    border: 2.5px solid var(--primary);
    box-shadow: var(--shadow);
    overflow: hidden;
    transition: transform 0.25s var(--ease-out), border-color var(--t);
    position: relative;
}
.pin-inner img { width: 100%; height: 100%; display: block; }
.pin:hover .pin-inner { transform: scale(1.12); }
.pin.is-active .pin-inner {
    transform: scale(1.2);
    border-color: var(--accent);
    box-shadow: 0 0 0 4px var(--accent-soft), var(--shadow);
}
.pin-emergency {
    position: absolute;
    right: -2px; bottom: -2px;
    width: 15px; height: 15px;
    border-radius: 50%;
    background: var(--danger);
    border: 2px solid var(--surface-solid);
}
.pin-ring {
    position: absolute;
    inset: -3px;
    border-radius: 50%;
    border: 2px solid var(--primary);
    animation: ping 2s infinite ease-out;
    pointer-events: none;
}
@keyframes ping {
    0%   { transform: scale(0.92); opacity: 0.75; }
    100% { transform: scale(1.55); opacity: 0; }
}

.me-dot {
    width: 18px; height: 18px;
    border-radius: 50%;
    background: var(--info);
    border: 3px solid #fff;
    box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.15), 0 2px 8px rgba(0, 0, 0, 0.3);
    position: relative;
}
.me-dot::after {
    content: '';
    position: absolute;
    inset: -9px;
    border-radius: 50%;
    border: 2px solid var(--info);
    animation: ping 2.2s infinite ease-out;
}

/* Leaflet popup */
.leaflet-popup-content-wrapper {
    background: var(--surface-solid);
    color: var(--text);
    border-radius: var(--radius);
    border: 1px solid var(--border);
    box-shadow: var(--shadow-lg);
    padding: 0;
}
.leaflet-popup-content { margin: 0; width: 230px !important; }
.leaflet-popup-tip { background: var(--surface-solid); border: 1px solid var(--border); }
.leaflet-popup-close-button { color: var(--faint) !important; padding: 8px 8px 0 0 !important; }
.popup-card { padding: 13px 14px; }
.popup-name {
    font-family: var(--font-heading);
    font-weight: 700;
    font-size: 0.95rem;
    color: var(--text-strong);
    padding-right: 14px;
}
.popup-sub { font-size: 0.8rem; color: var(--muted); margin-top: 1px; }
.popup-range {
    margin-top: 8px;
    font-size: 0.76rem;
    font-weight: 700;
    color: var(--primary);
}
.popup-btn {
    margin-top: 10px;
    width: 100%;
    padding: 8px;
    border-radius: var(--radius-sm);
    background: var(--primary);
    color: var(--on-primary);
    font-weight: 700;
    font-size: 0.82rem;
    font-family: var(--font-heading);
}

/* ---------------------------------------------------------------------
   10. Detail panel
   --------------------------------------------------------------------- */
/* Anchored to the viewport, not to the flow.
   It used to be `position: absolute; inset: 0` inside the scroll container —
   which pinned it to the top of the *content*, so opening a provider after
   scrolling down to the results put the panel off-screen above. Fixed
   positioning below the header makes it immune to scroll position. */
.detail {
    position: fixed;
    top: var(--header-h);
    left: 0;
    right: 0;
    bottom: 0;
    /* Above the postal dropdown (60); it never overlaps the header. */
    z-index: 70;
    display: flex;
    flex-direction: column;
    background: var(--surface-solid);
    transform: translateX(-102%);
    transition: transform 0.4s var(--ease-out);
    visibility: hidden;
}
.detail.is-open { transform: translateX(0); visibility: visible; }

/* The panel is full-bleed, but a profile read across 1200px is not a profile.
   Both rows share one centred measure, so the bar's controls line up with the
   body beneath them. */
.detail-bar,
.detail-body {
    padding-left: max(16px, calc((100% - var(--detail-w)) / 2));
    padding-right: max(16px, calc((100% - var(--detail-w)) / 2));
}

.detail-bar {
    flex: none;
    display: flex;
    align-items: center;
    gap: 10px;
    padding-top: 12px;
    padding-bottom: 12px;
    border-bottom: 1px solid var(--border);
    background: var(--surface);
    backdrop-filter: var(--blur);
    -webkit-backdrop-filter: var(--blur);
}
.detail-bar h2 { font-size: 0.98rem; flex: 1; }
.detail-body {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding-top: 18px;
    padding-bottom: 28px;
}

.detail-hero {
    display: flex;
    gap: 14px;
    align-items: center;
    margin-bottom: 16px;
}
.detail-hero img {
    width: 74px; height: 74px;
    border-radius: 50%;
    border: 3px solid var(--primary);
    box-shadow: 0 0 0 5px var(--primary-soft);
    flex: none;
}
.detail-hero h3 { font-size: 1.22rem; }
.detail-hero .clinic { color: var(--muted); font-size: 0.88rem; }
.detail-hero .place { color: var(--faint); font-size: 0.8rem; margin-top: 3px; }

.detail-badges { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 16px; }

.range-card {
    border-radius: var(--radius);
    border: 1px solid var(--border);
    background: linear-gradient(135deg, var(--primary-soft), transparent);
    padding: 14px;
    margin-bottom: 18px;
}
.range-head {
    display: flex;
    align-items: center;
    gap: 8px;
    font-family: var(--font-heading);
    font-weight: 700;
    font-size: 0.9rem;
    color: var(--text-strong);
    margin-bottom: 10px;
}
.range-head svg { width: 17px; height: 17px; fill: var(--primary); }
.range-stats { display: flex; gap: 10px; }
.range-stat {
    flex: 1 1 0;
    /* Capped so the row does not stretch one number across the whole panel.
       There used to be two figures here and the second was dropped; without
       a ceiling the survivor inherits the full width and the card reads as
       though something failed to load. Still shrinks to fit on a phone. */
    max-width: 240px;
    background: var(--surface-solid);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: 10px 12px;
}
.range-stat .val {
    font-family: var(--font-heading);
    font-size: 1.3rem;
    font-weight: 800;
    color: var(--primary);
    line-height: 1.1;
}
.range-stat .lbl {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--faint);
    font-weight: 700;
    margin-top: 3px;
}
.range-note { font-size: 0.78rem; color: var(--muted); margin-top: 10px; }
.range-note.is-covered { color: var(--primary); font-weight: 600; }
.range-note.is-outside { color: var(--accent); font-weight: 600; }

/* Every listing gets this card, and the address is the largest thing in it -
   it is what a visitor wants whether or not the provider travels. A provider
   who stays put is tinted differently, so the two are still distinguishable
   at a glance without the layout changing under you. */
.range-card.is-fixed {
    background: linear-gradient(135deg, var(--accent-soft, var(--primary-soft)), transparent);
}
.range-card.is-fixed .range-head svg { fill: var(--accent); }

/* Address on the left, travel figures on the right. They swap to stacked on a
   narrow screen rather than squeezing a street name into a column. */
.place-row {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 14px;
    flex-wrap: wrap;
}
.place-row .fixed-address { flex: 1 1 200px; margin-bottom: 0; }
.place-row .range-stats { flex: 0 0 auto; }
.fixed-address {
    font-family: var(--font-heading);
    font-size: 1.05rem;
    font-weight: 700;
    line-height: 1.35;
    color: var(--text-strong);
    margin: 0 0 10px;
}
.range-card.is-fixed .range-stats { margin-top: 2px; }

.detail-section { margin-bottom: 20px; }
.detail-section h4 {
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.09em;
    color: var(--faint);
    margin-bottom: 9px;
}
.detail-section p { font-size: 0.9rem; color: var(--muted); line-height: 1.65; }
.detail-bio { white-space: pre-line; }
/* How current the listing is, under the opening hours it mostly describes.
   Quiet: it qualifies what is above it rather than competing with it. */
.detail-freshness {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 10px 0 0;
    font-size: 0.78rem;
    color: var(--faint);
}
.detail-freshness svg { width: 14px; height: 14px; fill: currentColor; flex: none; }
/* The long description reuses the blog's typography - it is the same
   markup, written in the same editor. */
.detail-longtext { font-size: 0.95rem; }
.detail-longtext > :last-child { margin-bottom: 0; }
.tag-row { display: flex; flex-wrap: wrap; gap: 7px; }

.contact-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-bottom: 20px; }
.contact-actions .btn { padding: 12px 14px; }
.contact-actions .btn:only-child { grid-column: 1 / -1; }

.hours-table { width: 100%; border-collapse: collapse; font-size: 0.86rem; }
.hours-table td { padding: 7px 0; border-bottom: 1px solid var(--border); }
.hours-table td:first-child { color: var(--muted); text-transform: capitalize; }
.hours-table td:last-child { text-align: right; font-weight: 600; font-variant-numeric: tabular-nums; }
.hours-table tr.is-today td { color: var(--primary); font-weight: 700; }
.hours-table td.closed { color: var(--faint); font-weight: 500; }

/* ---------------------------------------------------------------------
   11. Toasts
   --------------------------------------------------------------------- */
.toasts {
    position: fixed;
    top: calc(var(--header-h) + 12px);
    left: 50%;
    transform: translateX(-50%);
    z-index: 3000;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    width: max-content;
    max-width: min(92vw, 420px);
    pointer-events: none;
}
.toast {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 11px 17px;
    border-radius: var(--radius-pill);
    background: var(--surface-solid);
    border: 1px solid var(--border);
    box-shadow: var(--shadow-lg);
    font-size: 0.87rem;
    font-weight: 500;
    animation: toast-in 0.35s var(--ease-out);
    transition: opacity 0.3s, transform 0.3s;
}
.toast-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; background: var(--primary); }
.toast.error .toast-dot { background: var(--danger); }
.toast.info .toast-dot { background: var(--info); }
.toast.is-leaving { opacity: 0; transform: translateY(-10px); }
@keyframes toast-in {
    from { opacity: 0; transform: translateY(-14px) scale(0.96); }
    to   { opacity: 1; transform: translateY(0) scale(1); }
}

/* ---------------------------------------------------------------------
   12. Mobile: the same single column, just tighter
   ---------------------------------------------------------------------
   v3 needs no re-ordering here. The funnel is one column at every width and
   the markup is already in the order it is answered, so the phone layout is
   the desktop layout with smaller padding. The draggable map-first sheet
   that v2 used is gone with it.
   --------------------------------------------------------------------- */
.mobile-only { display: none; }

@media (max-width: 899px) {
    :root { --header-h: 56px; }

    .app-header { padding: 0 12px; gap: 10px; }
    .brand-sub { display: none; }
    .mobile-only { display: flex; }

    /* Collapsed by default; the toggle adds .is-open, which floats the field
       across the whole header. That covers the toggle itself, so the close
       button inside it is the only way back out. */
    .header-search { display: none; }
    .header-search.is-open {
        display: block;
        position: absolute;
        left: 12px;
        right: 12px;
        top: 8px;
        max-width: none;
        z-index: 60;
    }
    .header-search.is-open .search-close { display: inline-flex; }
    /* Keep the typed text clear of the button. */
    .header-search.is-open input { padding-right: 46px; }

    .flow { padding: 16px 12px 48px; gap: 12px; }
    .flow-head h1 { font-size: 1.3rem; }
    .flow-head p { font-size: 0.85rem; }

    .step { padding: 14px; border-radius: var(--radius); }
    .step-titles h2 { font-size: 0.95rem; }

    /* Stack the three location controls; a 3-up grid is unreadable at this
       width and the postal field deserves the full line. */
    .location-grid { grid-template-columns: 1fr; }

    .card-grid { grid-template-columns: 1fr; }

    .results { display: flex; flex-direction: column; }

    .detail { border-radius: 0; }

    #map { height: 240px; }
    .map-legend {
        flex-wrap: wrap;
        justify-content: center;
        font-size: 0.7rem;
        padding: 7px 10px;
        gap: 10px;
    }

    .contact-actions { grid-template-columns: 1fr; }
    .toasts { top: calc(var(--header-h) + 8px); }
}

/* Respect reduced-motion preferences everywhere. */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
}

/* ---------------------------------------------------------------------
   ACCOUNT PAGES - sign in, register, my account
   These reuse the portal shell, so there is very little here: a card, a
   role pill, and the bits the funnel has no equivalent for.
   --------------------------------------------------------------------- */

/* Narrower than the funnel. A form of three fields laid out 1080px wide
   reads as a mistake; ~460px keeps the eye on one column. */
.flow-narrow { max-width: 480px; }

.auth-card {
    background: var(--surface);
    backdrop-filter: var(--blur);
    -webkit-backdrop-filter: var(--blur);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow);
    padding: 28px 24px 24px;
    position: relative;
    overflow: hidden;
}

/* The same warm wash the login card in the console uses, so the two doors
   look like the same building. */
.auth-card::before {
    content: '';
    position: absolute;
    inset: 0 0 auto 0;
    height: 3px;
    background: linear-gradient(90deg, var(--brand), var(--brand-2), var(--amber));
}

.auth-head { text-align: center; margin-bottom: 22px; }
.auth-head img { color: var(--primary); margin-bottom: 10px; }
.auth-head h1 {
    font-family: var(--font-heading);
    font-size: 1.4rem;
    font-weight: 800;
    letter-spacing: -0.02em;
    margin-bottom: 4px;
}
.auth-head p { font-size: 0.88rem; color: var(--muted); }

.auth-card .field { margin-bottom: 14px; }
.auth-card .btn-block { margin-top: 6px; }

.auth-alt {
    margin-top: 16px;
    text-align: center;
    font-size: 0.86rem;
    color: var(--muted);
}
.auth-alt a { color: var(--primary); font-weight: 700; }

.auth-back {
    margin-top: 14px;
    text-align: center;
    font-size: 0.84rem;
}
.auth-back a { color: var(--muted); }
.auth-back a:hover { color: var(--primary); }

/* ---------- My account ---------- */
.account-meta {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: 14px;
}
.account-meta > div { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.account-meta strong {
    font-size: 0.92rem;
    color: var(--text-strong);
    overflow-wrap: anywhere;
}

.account-nothing {
    margin-top: 16px;
    padding: 14px 16px;
    border: 1px dashed var(--border-strong);
    border-radius: var(--radius);
    color: var(--muted);
    font-size: 0.88rem;
    line-height: 1.55;
}

.account-form { display: flex; flex-direction: column; gap: 4px; }
.account-form .btn { align-self: flex-start; margin-top: 6px; }

/* ---------- Role pill ----------
   Shared by the account page and both admin headers, so it lives here
   rather than in admin.css. */
.role-pill {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 10px;
    border-radius: var(--radius-pill);
    font-size: 0.72rem;
    font-weight: 800;
    letter-spacing: 0.02em;
    white-space: nowrap;
    background: var(--surface-2);
    color: var(--muted);
    border: 1px solid var(--border);
}
.role-pill.role-admin {
    background: var(--accent-soft);
    color: var(--accent);
    border-color: transparent;
}
.role-pill.role-superadmin {
    background: var(--primary-soft);
    color: var(--primary);
    border-color: transparent;
}

/* ---------------------------------------------------------------------
   PROVIDER DETAIL - hours states (v6)
   --------------------------------------------------------------------- */

/* A provider seen by arrangement, where a grid of closed days would say
   the opposite of what they mean. */
.by-arrangement {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px 14px;
    border: 1px dashed var(--border-strong);
    border-radius: var(--radius);
    font-size: 0.9rem;
    line-height: 1.5;
    color: var(--muted);
}
.by-arrangement-mark {
    flex: none;
    width: 26px;
    height: 26px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: var(--primary-soft);
    color: var(--primary);
    font-size: 0.9rem;
}

.hours-table td.holiday { color: var(--accent); font-weight: 600; }

/* Shut for the holiday, but somebody still answers. Green because it is
   the one piece of good news in a column of closures - and it carries a
   label as well as a colour, so it does not depend on seeing the hue. */
.emergency-mark {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    margin-left: 8px;
    padding: 1px 8px 1px 6px;
    border-radius: var(--radius-pill);
    background: rgba(23, 138, 77, 0.14);
    color: #126b3d;
    font-size: 0.72rem;
    font-weight: 800;
    letter-spacing: 0.02em;
    vertical-align: middle;
}
.emergency-mark svg { width: 11px; height: 11px; fill: currentColor; }

[data-theme="dark"] .emergency-mark {
    background: rgba(52, 199, 123, 0.18);
    color: #5fd99b;
}

/* ---------------------------------------------------------------------
   BLOG - the index and one post
   --------------------------------------------------------------------- */
.blog-lede { color: var(--muted); font-size: 0.95rem; margin-bottom: 18px; }

.post-list { display: flex; flex-direction: column; gap: 14px; }

.post-card {
    display: flex;
    gap: 16px;
    padding: 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface-2);
    color: inherit;
    text-decoration: none;
    transition: var(--t);
}
.post-card:hover {
    border-color: var(--border-strong);
    transform: translateY(-1px);
    box-shadow: var(--shadow-sm);
}
.post-card-cover {
    flex: none;
    width: 132px;
    height: 92px;
    border-radius: var(--radius-sm);
    overflow: hidden;
    background: var(--bg-2);
}
.post-card-cover img { width: 100%; height: 100%; object-fit: cover; }

.post-card-body { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.post-card-title {
    font-family: var(--font-heading);
    font-size: 1.02rem;
    font-weight: 800;
    letter-spacing: -0.01em;
    color: var(--text-strong);
}
.post-card-excerpt {
    font-size: 0.88rem;
    color: var(--muted);
    line-height: 1.5;
    /* Two lines, then stop - a card is a promise of a post, not the post. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.post-card-meta {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: auto;
    font-size: 0.78rem;
    color: var(--faint);
}

/* ---------- One post ---------- */
.post-cover {
    margin: -4px 0 18px;
    border-radius: var(--radius);
    overflow: hidden;
    max-height: 340px;
}
.post-cover img { width: 100%; height: 100%; object-fit: cover; display: block; }

.post-meta {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 0.82rem;
    color: var(--faint);
    margin-bottom: 10px;
}
.post-author { color: var(--muted); font-weight: 600; }

.post-lede {
    font-size: 1.02rem;
    line-height: 1.6;
    color: var(--muted);
    padding-bottom: 14px;
    margin-bottom: 4px;
    border-bottom: 1px solid var(--border);
}

/* The body is the one place on the site with long-form prose, so it gets
   a reading measure rather than the full column width.
   The measure sits on the body rather than on the paragraphs, so that a
   full-width picture is full width *of the prose* - put it on the
   paragraphs instead and the pictures overshoot the text by 300px. */
.post-body {
    font-size: 1rem;
    line-height: 1.75;
    max-width: 72ch;
}
.post-body h2 {
    font-family: var(--font-heading);
    font-size: 1.45rem;
    font-weight: 800;
    letter-spacing: -0.02em;
    line-height: 1.25;
    margin: 26px 0 10px;
    color: var(--text-strong);
}
.post-body h3 {
    font-family: var(--font-heading);
    font-size: 1.12rem;
    font-weight: 700;
    line-height: 1.35;
    margin: 20px 0 8px;
    color: var(--text-strong);
}
.post-body h2:first-child, .post-body h3:first-child { margin-top: 0; }
.post-body p { margin: 0 0 14px; }
.post-body a { color: var(--primary); text-decoration: underline; text-underline-offset: 2px; }

/* ---------- Pictures inside a post ---------- */
.post-figure { margin: 20px 0; }
.post-figure img { width: 100%; border-radius: var(--radius); display: block; }
.post-figure figcaption {
    margin-top: 7px;
    font-size: 0.82rem;
    color: var(--faint);
    line-height: 1.5;
}

.post-figure.is-center { text-align: center; }
.post-figure.is-center img { max-width: min(100%, 560px); margin: 0 auto; }

/* Floats, so the text wraps round them - which is the point of putting a
   picture on one side rather than across the column. */
.post-figure.is-left,
.post-figure.is-right { max-width: 46%; margin-top: 6px; }
.post-figure.is-left  { float: left;  margin-right: 22px; }
.post-figure.is-right { float: right; margin-left: 22px; }

/* A narrower picture. The width comes after the alignment rules on
   purpose: both are two classes deep, so source order is what decides, and
   an explicit width has to beat the float's default 46%. */
.post-figure.is-w-25  { max-width: 25%; }
.post-figure.is-w-50  { max-width: 50%; }
.post-figure.is-w-75  { max-width: 75%; }
.post-figure.is-w-100 { max-width: 100%; }
/* is-center centres with text-align plus a margin on the image, which stops
   working once the figure itself is the narrow thing. */
.post-figure.is-center[class*="is-w-"] { margin-inline: auto; }

/* Lists inside a body. */
.post-body ul, .post-body ol { margin: 0 0 14px; padding-left: 24px; }
.post-body li { margin: 0 0 6px; }

/* In the provider panel there is no column for text to wrap round - it is
   already a narrow one - so every picture spans it, whatever it was set to
   for the wide page. After the width rules, which it has to outrank. */
.detail-longtext .post-figure {
    float: none;
    max-width: 100%;
    margin-left: 0;
    margin-right: 0;
}

/* Headings start a new thought, so they never wrap round a float. */
.post-body h2, .post-body h3 { clear: both; }
.post-body::after { content: ''; display: block; clear: both; }

.post-back { margin-top: 24px; }

/* On a phone there is no room to wrap text round anything - every picture
   goes full width, which is what the portal does with everything else. */
@media (max-width: 640px) {
    .post-figure.is-left,
    .post-figure.is-right,
    .post-figure[class*="is-w-"] {
        float: none;
        max-width: 100%;
        margin-left: 0;
        margin-right: 0;
    }
    .post-card { flex-direction: column; }
    .post-card-cover { width: 100%; height: 150px; }
}

/* The confirmation that replaces a form once it has done its job. Replacing
   rather than adding, so it is obvious the step is finished. */
.auth-sent { text-align: center; padding: 8px 0 4px; }
.auth-sent-mark {
    width: 44px;
    height: 44px;
    margin: 0 auto 14px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: var(--primary-soft);
    color: var(--primary);
    font-size: 1.3rem;
    font-weight: 800;
}
.auth-sent p { font-size: 0.92rem; line-height: 1.6; color: var(--text); }
.auth-sent-note { margin-top: 8px; font-size: 0.85rem; color: var(--faint); }
.auth-sent-note a { color: var(--primary); font-weight: 700; }

.auth-forgot { margin-top: 12px; text-align: center; font-size: 0.84rem; }
.auth-forgot a { color: var(--muted); }
.auth-forgot a:hover { color: var(--primary); }

/* ---------------------------------------------------------------------
   BOOKING - the public page
   --------------------------------------------------------------------- */
.bk-hero { display: flex; align-items: center; gap: 16px; margin-bottom: 14px; }
.bk-hero img { width: 62px; height: 62px; border-radius: 50%; background: var(--surface-2); }
.bk-hero h2 {
    font-family: var(--font-heading);
    font-size: 1.3rem;
    font-weight: 800;
    letter-spacing: -0.02em;
    color: var(--text-strong);
}
.bk-hero-place { font-size: 0.86rem; color: var(--muted); margin-top: 2px; }

.bk-intro {
    font-size: 0.94rem;
    line-height: 1.6;
    color: var(--muted);
    margin-bottom: 6px;
    white-space: pre-line;
}
.bk-empty, .bk-none { color: var(--faint); font-size: 0.9rem; padding: 8px 0; }

.bk-signin {
    padding: 22px;
    border: 1px dashed var(--border-strong);
    border-radius: var(--radius);
    background: var(--surface-2);
    text-align: center;
}
.bk-signin h3 { font-family: var(--font-heading); font-size: 1.05rem; margin-bottom: 6px; }
.bk-signin p { font-size: 0.9rem; color: var(--muted); line-height: 1.55; }

/* ---------- Picking a service ---------- */
.bk-services-pick { display: flex; flex-direction: column; gap: 8px; }
.bk-service-opt {
    display: grid;
    grid-template-columns: 1fr auto;
    grid-template-areas: "name len" "note len";
    gap: 2px 14px;
    text-align: left;
    padding: 13px 16px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface-2);
    transition: var(--t);
}
.bk-service-opt:hover { border-color: var(--border-strong); transform: translateX(2px); }
.bk-service-opt.is-active { border-color: var(--primary); background: var(--primary-soft); }
.bk-opt-name { grid-area: name; font-weight: 700; color: var(--text-strong); font-size: 0.95rem; }
.bk-opt-note { grid-area: note; font-size: 0.83rem; color: var(--muted); }
.bk-opt-len {
    grid-area: len;
    align-self: center;
    padding: 4px 11px;
    border-radius: var(--radius-pill);
    background: var(--surface-solid);
    color: var(--muted);
    font-size: 0.76rem;
    font-weight: 700;
    white-space: nowrap;
}
.bk-service-opt.is-active .bk-opt-len { background: var(--primary); color: var(--on-primary); }

/* ---------- Picking a day ----------
   A scrolling strip, not a month grid: most of a calendar is days with
   nothing free on them, and this only shows days that have something. */
.bk-days {
    display: flex;
    gap: 8px;
    overflow-x: auto;
    padding-bottom: 6px;
    scroll-snap-type: x proximity;
    -webkit-overflow-scrolling: touch;
}
.bk-day {
    flex: none;
    width: 62px;
    padding: 10px 0 8px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface-2);
    scroll-snap-align: start;
    transition: var(--t);
}
.bk-day:hover { border-color: var(--border-strong); }
.bk-day.is-active { border-color: var(--primary); background: var(--primary-soft); }
.bk-day-name {
    display: block;
    font-size: 0.68rem;
    font-weight: 700;
    color: var(--faint);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    /* Belt and braces behind the three-letter trim in the JS. */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.bk-day-num {
    display: block;
    font-family: var(--font-heading);
    font-size: 1.25rem;
    font-weight: 800;
    color: var(--text-strong);
    line-height: 1.2;
}
.bk-day-mon { display: block; font-size: 0.72rem; color: var(--muted); }
.bk-day-free {
    display: inline-block;
    margin-top: 5px;
    padding: 1px 7px;
    border-radius: var(--radius-pill);
    background: var(--surface-solid);
    font-size: 0.68rem;
    font-weight: 800;
    color: var(--primary);
}
.bk-day.is-active .bk-day-free { background: var(--primary); color: var(--on-primary); }

.bk-times { margin-top: 16px; }
.bk-times-head {
    font-size: 0.8rem;
    font-weight: 700;
    color: var(--faint);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    margin-bottom: 8px;
}
.bk-time-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(76px, 1fr)); gap: 7px; }
.bk-time {
    padding: 10px 4px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
    font-size: 0.88rem;
    font-weight: 700;
    color: var(--text);
    font-variant-numeric: tabular-nums;
    transition: var(--t);
}
.bk-time:hover { border-color: var(--primary); color: var(--primary); }
.bk-time.is-active { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }

/* ---------- Confirming ---------- */
.bk-summary, .bk-receipt {
    padding: 14px 16px;
    margin-bottom: 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface-2);
}
.bk-receipt { margin-top: 14px; text-align: left; }
.bk-sum-row { display: flex; justify-content: space-between; gap: 14px; padding: 4px 0; font-size: 0.9rem; }
.bk-sum-row span { color: var(--muted); }
.bk-sum-row strong { color: var(--text-strong); text-align: right; }

/* ---------- On the account page ---------- */
.bk-mine { display: flex; flex-direction: column; gap: 8px; }
.bk-mine-row {
    display: grid;
    grid-template-columns: 58px minmax(0, 1fr) auto;
    align-items: center;
    gap: 14px;
    padding: 11px 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface-2);
}
.bk-mine-row.is-past { opacity: 0.55; }
.bk-mine-row.is-cancelled { opacity: 0.55; }
.bk-mine-row.is-cancelled .bk-mine-what strong { text-decoration: line-through; }
.bk-mine-when { text-align: center; }
.bk-mine-when strong {
    display: block;
    font-family: var(--font-heading);
    font-size: 1rem;
    font-weight: 800;
    color: var(--primary);
}
.bk-mine-when span { font-size: 0.8rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.bk-mine-what { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.bk-mine-what strong { font-size: 0.92rem; color: var(--text-strong); }
.bk-mine-what span { font-size: 0.82rem; color: var(--muted); }
.bk-mine-where { color: var(--faint) !important; font-size: 0.78rem !important; }
.bk-mine-ref code { font-size: 0.74rem; color: var(--faint); letter-spacing: 0.06em; }

@media (max-width: 560px) {
    .bk-mine-row { grid-template-columns: 52px minmax(0, 1fr); }
    .bk-mine-ref { grid-column: 2; }
}

/* ---------------------------------------------------------------------
   MAP SCROLL LOCK

   The map sits in the middle of a page people scroll straight past, and a
   wheel over it used to zoom instead of scroll - so the page snagged every
   time somebody passed over it. Its controls stay locked until a click asks
   for them, and hand back the moment the pointer leaves.
   --------------------------------------------------------------------- */
.map-lock {
    position: absolute;
    inset: 0;
    z-index: 900;
    display: grid;
    place-items: center;
    background: var(--map-scrim);
    /* Never takes the event. The click still lands on whatever the visitor
       aimed at underneath, and on a phone a swipe across the map still
       scrolls the page rather than being swallowed by an invisible sheet. */
    pointer-events: none;
    transition: opacity 0.28s var(--ease), visibility 0.28s var(--ease);
}
.map-lock.is-open { opacity: 0; visibility: hidden; }

.map-lock-badge {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 9px 15px 9px 12px;
    border-radius: var(--radius-pill);
    background: var(--surface-solid);
    border: 1px solid var(--border-strong);
    box-shadow: var(--shadow);
    font-size: 0.83rem;
    font-weight: 700;
    color: var(--text-strong);
    white-space: nowrap;
    animation: map-lock-pulse 2.6s var(--ease) infinite;
}
.map-lock-badge svg { width: 17px; height: 17px; fill: var(--primary); flex: none; }

/* Breathes rather than blinks - enough to read as "not dead yet", not
   enough to nag while somebody reads the map through it. */
@keyframes map-lock-pulse {
    0%, 100% { transform: scale(1);     opacity: 0.88; }
    50%      { transform: scale(1.045); opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .map-lock-badge { animation: none; opacity: 1; }
    .map-lock { transition: none; }
}

@media (max-width: 560px) {
    .map-lock-badge { font-size: 0.78rem; padding: 8px 13px 8px 10px; }
}


/* ---------- Closures and public holidays ----------
   Shown above the opening-hours table, because a week of times means the
   wrong thing if the door is shut for a fortnight. */
.closure-now {
    font-size: 0.9rem;
    font-weight: 700;
    color: var(--accent);
    background: var(--accent-soft);
    border-radius: var(--radius-sm);
    padding: 9px 12px;
    margin-bottom: 8px;
}
.closure-next {
    font-size: 0.85rem;
    color: var(--muted);
    margin-bottom: 8px;
}
/* A statement about the calendar, not about this practice - so it is quieter
   than a closure, which is this practice telling you it is shut. */
.holiday-note {
    font-size: 0.82rem;
    color: var(--faint);
    margin-bottom: 14px;
}
.badge-closed {
    background: var(--accent-soft);
    color: var(--accent);
    border-color: transparent;
}


/* ---------- Contact details as text ----------
   Under the call/email buttons, not instead of them. The buttons act; these
   can be selected, copied and pasted somewhere else, which a button cannot. */
.contact-lines {
    margin: 0 0 18px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
    overflow: hidden;
}
.contact-line {
    display: flex;
    align-items: baseline;
    gap: 10px;
    padding: 9px 12px;
}
.contact-line + .contact-line { border-top: 1px solid var(--border); }
.contact-label {
    flex: none;
    min-width: 74px;
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    font-weight: 700;
    color: var(--faint);
}
.contact-value {
    /* Selectable on a phone: a long-press should offer copy, and the row is
       narrow enough that a long address has to be allowed to break. */
    user-select: text;
    -webkit-user-select: text;
    word-break: break-word;
    font-size: 0.92rem;
    color: var(--text-strong);
    text-decoration: none;
}
.contact-value:hover { text-decoration: underline; }

/* ---------- Map tiles ----------
   OpenStreetMap's own tiles, because CARTO now paints "API KEY REQUIRED"
   across every tile it serves without one.

   OSM's cartography is louder than the CARTO light basemap it replaces - full
   colour roads, green landuse, brown contours - and the pins have to read on
   top of it. Muting it here rather than paying for a quieter tile server
   keeps the map keyless.

   The filter is on the tile pane only, so markers, the coverage circle and
   the controls above it are untouched. */
.leaflet-tile-pane {
    filter: saturate(0.42) brightness(1.06) contrast(0.94);
}

/* OSM publishes no dark basemap. Inverting the light one and rotating the hue
   back gives a usable dark map from the same tiles: land goes dark, water
   stays blue-ish, labels turn light. */
:root[data-theme="dark"] .leaflet-tile-pane {
    filter: invert(1) hue-rotate(180deg) saturate(0.5) brightness(0.92) contrast(0.9);
}
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .leaflet-tile-pane {
        filter: invert(1) hue-rotate(180deg) saturate(0.5) brightness(0.92) contrast(0.9);
    }
}

/* ---------------------------------------------------------------------
   SITE FOOTER - a card, matching the surfaces used everywhere else
   --------------------------------------------------------------------- */
.site-footer {
    margin-top: 46px;
    /* .flow is the scrolling column and already has side padding; the footer
       sits inside it so it scrolls with the page rather than being pinned. */
}

.footer-card {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 34px 34px 30px;
}

.footer-top {
    display: grid;
    grid-template-columns: minmax(200px, 1fr) 2.1fr;
    gap: 36px;
}

.footer-logo {
    display: flex;
    align-items: center;
    gap: 9px;
    font-family: var(--font-heading);
    font-weight: 700;
    font-size: 1.06rem;
    color: var(--text-strong);
}
.footer-logo img { width: 26px; height: 26px; }

.footer-tagline {
    margin-top: 10px;
    font-size: 0.86rem;
    color: var(--muted);
    max-width: 30ch;
    line-height: 1.55;
}

.footer-mail {
    display: inline-block;
    margin-top: 14px;
    font-size: 0.86rem;
    font-weight: 600;
    color: var(--primary);
    text-decoration: none;
    border-bottom: 1px solid transparent;
}
.footer-mail:hover { border-bottom-color: var(--primary); }

/* auto-fit rather than a fixed count: the number of groups is a superadmin's
   decision, and the CSS should not have an opinion about it. */
.footer-groups {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: 26px 22px;
}

.footer-group-title {
    font-family: var(--font-heading);
    font-size: 0.86rem;
    font-weight: 600;
    color: var(--text-strong);
    margin: 0 0 11px;
}

.footer-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 9px; }

.footer-list a {
    color: var(--muted);
    text-decoration: none;
    font-size: 0.85rem;
    line-height: 1.4;
    transition: color var(--t);
}
.footer-list a:hover { color: var(--primary); }

.footer-base {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 22px;
    justify-content: space-between;
    padding: 16px 8px 30px;
}
.footer-copy,
.footer-colophon { font-size: 0.76rem; color: var(--faint); margin: 0; }
.footer-colophon a {
    color: var(--muted);
    text-decoration: none;
    border-bottom: 1px solid var(--border-strong);
}
.footer-colophon a:hover { color: var(--primary); border-bottom-color: var(--primary); }

@media (max-width: 760px) {
    .footer-top { grid-template-columns: 1fr; gap: 26px; }
    .footer-card { padding: 26px 22px 24px; }
}

/* ---------- The "more" menu, extended ----------
   Same markup as the icon-only default; only this class is added. Each entry
   becomes a horizontal pill holding a round mark and its label, so the whole
   stack reads as a list of named destinations rather than a column of glyphs.
   Switched under Admin -> General. */

.menu-pill.is-extended .menu-stack {
    /* The entries are pills now, so the container behind them is a panel
       rather than a pill - a pill inside a pill of the same radius reads as a
       mistake. */
    border-radius: var(--radius-lg);
    padding: 7px;
    gap: 3px;
    min-width: 224px;
}

.menu-pill.is-extended .menu-item {
    width: 100%;
    height: auto;
    min-height: 44px;
    justify-content: flex-start;
    gap: 11px;
    padding: 5px 18px 5px 5px;
    border-radius: var(--radius-pill);
    border-color: transparent;
    background: transparent;
    color: var(--text);
}

/* The mark keeps its circle inside the pill. The svg is a direct child of the
   link, so the circle is drawn on the svg itself rather than on a wrapper -
   no extra element, and the icon-only style is left exactly as it was. */
.menu-pill.is-extended .menu-item > svg,
.menu-pill.is-extended .menu-item > .menu-word {
    flex: none;
    box-sizing: border-box;
    width: 34px;
    height: 34px;
    padding: 8px;
    border-radius: 50%;
    background: var(--primary-soft);
    color: var(--primary);
}
.menu-pill.is-extended .menu-item > .menu-word {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    font-size: 0.55rem;
}

/* Un-hide the label that the icon-only style keeps for screen readers. */
.menu-pill.is-extended .menu-label {
    position: static;
    width: auto;
    height: auto;
    margin: 0;
    padding: 0;
    overflow: visible;
    clip: auto;
    clip-path: none;
    white-space: nowrap;
    font-size: 0.87rem;
    font-weight: 600;
}

.menu-pill.is-extended .menu-item:hover,
.menu-pill.is-extended .menu-item:focus-visible {
    background: var(--primary);
    border-color: var(--primary);
    color: var(--on-primary);
    /* No scale here. Growing a full-width pill shoves its neighbours about;
       the icon-only style can afford it because a 40px circle has room. */
    transform: none;
}
.menu-pill.is-extended .menu-item:hover > svg,
.menu-pill.is-extended .menu-item:hover > .menu-word,
.menu-pill.is-extended .menu-item:focus-visible > svg,
.menu-pill.is-extended .menu-item:focus-visible > .menu-word {
    background: rgba(255, 255, 255, 0.22);
    color: var(--on-primary);
}

@media (max-width: 420px) {
    /* The stack is right-anchored under a button near the screen edge, so on a
       narrow phone it has to be allowed to shrink rather than push off-screen. */
    .menu-pill.is-extended .menu-stack {
        min-width: 0;
        max-width: calc(100vw - 24px);
    }
    .menu-pill.is-extended .menu-label { white-space: normal; }
}

/* =====================================================================
   PRE POSKYTOVATEĽOV  (providers.php)
   A walkthrough for the businesses listed here, most of whom have never
   seen the console and are reading this beside an e-mail with their
   login in it. Wide screenshots, generous spacing, numbered steps.
   ===================================================================== */
.guide-lede {
    font-size: 1.02rem;
    line-height: 1.65;
    margin-bottom: 16px;
}

.guide-note {
    padding: 12px 16px;
    margin-bottom: 30px;
    border: 1px solid var(--border);
    border-left: 3px solid var(--primary);
    border-radius: var(--radius);
    background: var(--surface-2);
    color: var(--muted);
    font-size: 0.92rem;
    line-height: 1.6;
}

.guide-step { margin-bottom: 34px; }

.guide-step h2 {
    display: flex;
    align-items: center;
    gap: 10px;
    font-family: var(--font-heading);
    font-size: 1.12rem;
    margin: 0 0 6px;
}

/* The number is the thing somebody's eye returns to after looking away at
   their own screen, so it is a mark rather than a prefix. */
.guide-num {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    background: var(--primary);
    color: #fff;
    font-size: 0.85rem;
    font-weight: 700;
}

.guide-step p {
    margin: 0 0 12px;
    color: var(--muted);
    font-size: 0.95rem;
    line-height: 1.7;
}

.guide-shot {
    margin: 0;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--surface-2);
    /* The screenshots are 1180px wide and the column is narrower, so they
       are always scaled down - height:auto keeps them from stretching. */
    line-height: 0;
}
.guide-shot img { width: 100%; height: auto; display: block; }

.guide-rule {
    border: 0;
    border-top: 1px solid var(--border);
    margin: 30px 0 26px;
}

/* ---------------------------------------------------------------------
   The same guide, on a phone
   ---------------------------------------------------------------------
   A scrolling strip rather than five more stacked pictures. These are
   540px-wide captures of a tall screen: shown at column width they would
   dwarf the desktop shots above them and turn the page into a scroll. Side
   by side they read as one sequence, and the strip is swipeable on the
   device most providers will be holding while they follow it. */
.guide-phones {
    display: flex;
    gap: 14px;
    overflow-x: auto;
    padding-bottom: 10px;
    margin-bottom: 20px;
    /* Each shot settles at the start of the viewport when the strip is
       flicked, so a half-cut phone is never where it comes to rest. */
    scroll-snap-type: x proximity;
    -webkit-overflow-scrolling: touch;
}

.guide-phone {
    margin: 0;
    flex: 0 0 176px;
    scroll-snap-align: start;
}

.guide-phone img {
    width: 100%;
    height: auto;
    display: block;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface-2);
}

.guide-phone figcaption {
    margin-top: 8px;
    font-size: 0.82rem;
    line-height: 1.45;
    color: var(--muted);
}

.guide-get {
    margin-bottom: 18px;
    font-weight: 600;
}
.guide-get a { color: var(--primary); }

/* The note under the strip belongs to the section above it, not to the next
   one - the standing .guide-note margin would push it halfway there. */
.guide-note-inline { margin-bottom: 0; }

.guide-contact {
    font-size: 1rem;
    font-weight: 600;
}
.guide-contact a { color: var(--primary); text-decoration: none; }
.guide-contact a:hover { text-decoration: underline; }

@media (max-width: 640px) {
    .guide-step h2 { font-size: 1.05rem; }
    /* Stack the phone number and address rather than letting them wrap
       mid-number, which reads as two broken links. */
    .guide-contact a { display: block; }
    .guide-contact span { display: none; }
}

/* =========================================================================
   Add your business - the public listing request
   ========================================================================= */

.addco { max-width: 760px; }

.addco-head h1 { margin: 0 0 6px; }
.addco-lead { color: var(--muted); margin: 0 0 18px; }

/* The "this is not the login page" panel. Deliberately loud enough to be read
   before the first field, and quiet enough not to look like an error. */
.addco-notice {
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: 10px;
  background: var(--surface-2, rgba(0, 0, 0, 0.02));
  padding: 14px 16px;
  margin: 0 0 22px;
}
.addco-notice p { margin: 0; font-size: 0.9rem; color: var(--muted); }
.addco-notice-act { margin-top: 8px !important; }
.addco-notice-act a { color: var(--accent); font-weight: 600; text-decoration: none; }
.addco-notice-act a:hover { text-decoration: underline; }

.addco-block {
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 16px 18px 18px;
  margin: 0 0 18px;
}
.addco-block > legend {
  padding: 0 8px;
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--faint);
}

/* Two across on a desktop, stacked on a phone - most of these pairs are a
   short field beside a short field. */
.addco-row { display: grid; gap: 0 16px; grid-template-columns: 1fr 1fr; }
@media (max-width: 620px) { .addco-row { grid-template-columns: 1fr; } }

.addco-tree { margin-top: 10px; }

.addco-animal {
  border: 1px solid var(--line);
  border-radius: 10px;
  margin-bottom: 8px;
  overflow: hidden;
}
.addco-animal > summary {
  cursor: pointer;
  padding: 10px 14px;
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: 10px;
  list-style: none;
}
.addco-animal > summary::-webkit-details-marker { display: none; }
.addco-animal > summary::after {
  content: '+';
  margin-left: auto;
  color: var(--faint);
  font-size: 1.1rem;
  line-height: 1;
}
.addco-animal[open] > summary::after { content: '\2212'; }
.addco-animal[open] > summary { border-bottom: 1px solid var(--line); }
.addco-emoji { font-size: 1.1rem; }

.addco-group { padding: 10px 14px 2px; }
.addco-group + .addco-group { border-top: 1px dashed var(--line); }
.addco-group-name {
  margin: 0 0 6px;
  font-size: 0.75rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--faint);
}
.addco-leaves { display: flex; flex-wrap: wrap; gap: 6px 14px; margin-bottom: 10px; }

/* `.field label` makes every label in a form uppercase, bold and tracked -
   right for a field caption, wrong for a hundred checkbox names and for a
   sentence of consent. Both are labels inside a .field, so both are reset. */
.addco-leaves .addco-leaf,
.addco-consent {
  text-transform: none;
  letter-spacing: normal;
  font-weight: 400;
  color: var(--text);
  margin-bottom: 0;
}

.addco-leaf {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 0.86rem;
  cursor: pointer;
  padding: 3px 0;
}
.addco-leaf input { accent-color: var(--accent); }

.addco-count {
  margin: 10px 0 0;
  font-size: 0.8rem;
  color: var(--faint);
}
.addco-count.is-set { color: var(--accent); font-weight: 600; }

.addco-consent {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  font-size: 0.9rem;
  cursor: pointer;
  line-height: 1.45;
}
.addco-consent input { margin-top: 3px; accent-color: var(--accent); flex: none; }

.addco-review {
  font-size: 0.83rem;
  color: var(--faint);
  margin: 0 0 14px;
  text-align: center;
}

.addco-done { text-align: center; padding: 34px 20px; }
.addco-done-mark { color: var(--accent); margin-bottom: 8px; }
.addco-done h2 { margin: 0 0 8px; }
.addco-done p { color: var(--muted); margin: 0 auto; max-width: 42ch; }
.addco-done-act {
  margin-top: 20px !important;
  display: flex;
  gap: 10px;
  justify-content: center;
  flex-wrap: wrap;
}

/* =========================================================================
   Blog - one article, several languages
   ========================================================================= */

.post-langs {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin: 0 0 16px;
}
.post-langs-label {
  font-size: 0.74rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--faint);
}
.post-lang {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* Wide enough for a flag glyph and for the two boxed letters Windows
     substitutes for one, so the row does not change width by platform. */
  min-width: 42px;
  padding: 5px 10px;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 0.8rem;
  line-height: 1;
  text-decoration: none;
  color: var(--muted);
  transition: border-color 0.15s, color 0.15s, background 0.15s;
}
.post-lang:hover { border-color: var(--accent); color: var(--accent); }
.post-lang.is-active {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 10%, transparent);
  color: var(--accent);
  font-weight: 600;
}
/* The one the article was actually written in. */
.post-lang.is-original::after {
  content: '\2217';
  color: var(--faint);
  font-size: 0.9rem;
  line-height: 1;
}
.post-lang-flag { font-size: 1.05rem; line-height: 1; letter-spacing: 0; }

.post-fallback {
  font-size: 0.83rem;
  color: var(--faint);
  border-left: 2px solid var(--line);
  padding-left: 10px;
  margin: 0 0 18px;
}

/* =========================================================================
   Admin -> General: requests to be listed
   ========================================================================= */

.subs-empty { color: var(--faint); font-size: 0.88rem; margin: 6px 0 0; }

.subs-list { display: flex; flex-direction: column; gap: 10px; margin-top: 12px; }

.sub-card {
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 12px 14px;
}
.sub-card.is-pending { border-left: 3px solid var(--accent); }
.sub-card.is-rejected { opacity: 0.6; }

.sub-top { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.sub-name { font-weight: 700; }
.sub-state {
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 2px 8px;
  border-radius: 999px;
  border: 1px solid var(--line);
  color: var(--faint);
}
.sub-state.is-pending { border-color: var(--accent); color: var(--accent); }
.sub-when { margin-left: auto; font-size: 0.76rem; color: var(--faint); }

.sub-lines { margin: 8px 0 0; font-size: 0.85rem; color: var(--muted); }
.sub-lines div { padding: 1px 0; }
.sub-lines .sub-key { color: var(--faint); display: inline-block; min-width: 92px; }

.sub-tags { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 8px; }
.sub-tag {
  font-size: 0.74rem;
  padding: 2px 8px;
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--muted);
}

.sub-bio {
  margin: 8px 0 0;
  font-size: 0.85rem;
  color: var(--muted);
  white-space: pre-wrap;
  border-left: 2px solid var(--line);
  padding-left: 10px;
}

.sub-acts { display: flex; gap: 8px; margin-top: 12px; flex-wrap: wrap; }
.sub-note-in { margin-top: 8px; }

/* =========================================================================
   Add your business - opening hours
   One row per day: the switch and the day's name on the left, the two
   hour pickers (or "Closed") on the right. Sized to stay on one line on a
   375px phone, where most of this form is filled in.
   ========================================================================= */

.addco-hours-hint { margin: 0 0 12px; }

.addco-week { display: flex; flex-direction: column; }

.addco-day {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  min-height: 48px;
  padding: 6px 0;
}
.addco-day + .addco-day { border-top: 1px solid var(--line); }

/* The switch is a <label> inside no .field, so it keeps the plain body text
   style - no uppercase caption treatment to undo here. */
.addco-day-switch { flex: 0 1 auto; min-width: 0; }
.addco-day-name {
  font-size: 0.92rem;
  color: var(--muted);
  white-space: nowrap;
}
.addco-day.is-on .addco-day-name { color: var(--text); font-weight: 600; }

.addco-day-time {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: none;
}
.addco-day-time .select {
  width: auto;
  min-width: 84px;
  padding-top: 7px;
  padding-bottom: 7px;
  font-variant-numeric: tabular-nums;
}
.addco-dash { color: var(--faint); }

.addco-day-closed {
  font-size: 0.85rem;
  color: var(--faint);
  flex: none;
}

/* A <fieldset> defaults to min-width: min-content, so a row that cannot
   shrink makes the whole block grow past its column instead - on a 375px
   phone the hours block came out at 356px in a 289px space and its pickers
   were cut off at the screen edge. min-width: 0 lets every block on this
   page be as wide as its column and no wider. */
.addco-block { min-width: 0; }

/* On a phone a day plus two pickers is ~330px and there are ~250. The
   pickers take their own line under the day name, lined up with it (switch
   42px + gap 10px), and share that line evenly. A day that is switched off
   still reads on one line: "Csütörtök ... Zárva". */
@media (max-width: 480px) {
  .addco-day { flex-wrap: wrap; row-gap: 6px; }
  .addco-day-time {
    flex: 1 0 100%;
    padding-left: 52px;
  }
  .addco-day-time .select { flex: 1; min-width: 0; }
}
