/* VysajTo — design system.
   Rounded, card-based, single warm accent against mostly neutral
   surfaces — modeled on the reference mood boards (rounded mobile-app
   UI, bottom tab bar for primary navigation, bold accent used sparingly).
   Still high-contrast enough for outdoor daylight phone use. See
   docs/02-architecture.md.

   Everything below is built from the tokens in :root — new components
   should reuse them (spacing/radius/shadow/duration/icon-size/focus)
   rather than hardcoding new values, so the whole app keeps reading as
   one system as features are added. */

:root {
    color-scheme: light dark;

    --color-bg: #f6f5f3;
    --color-surface: #ffffff;
    --color-text: #1c1a17;
    --color-text-muted: #746f68;
    --color-border: #e6e2dc;
    --color-accent: #ea6a12;
    --color-accent-rgb: 234, 106, 18;
    --color-accent-hover: #c6560d;
    --color-accent-press: #a8480a;
    --color-accent-contrast: #ffffff;
    --color-danger: #b3261e;
    --color-danger-bg: #fbe9e7;
    --color-success: #1e6b3c;
    --color-success-bg: #e3f3ea;
    --color-warning: #9a5b00;
    --color-warning-bg: #fdf1d9;
    --color-info: #0b5c8f;
    --color-info-bg: #e3eff8;

    /* Fixed "semaphore" colors for status dots / action icons — constant
       across light/dark themes on purpose: these are meant to be an
       immediately-recognizable, unchanging color code (blue/green/red),
       not theme-adaptive UI chrome. */
    --color-dot-blue: #2f6fed;
    --color-dot-green: #1e9150;
    --color-dot-red: #d93025;

    /* Spacing scale — use these instead of one-off rem values so
       padding/margin/gap read as one consistent rhythm. */
    --space-1: 0.25rem;
    --space-2: 0.5rem;
    --space-3: 0.75rem;
    --space-4: 1rem;
    --space-5: 1.5rem;
    --space-6: 2rem;

    --radius: 1rem;
    --radius-sm: 0.6rem;
    --radius-pill: 999px;

    /* Elevation scale — resting (sm/base) vs. hovered/pressed (md) so
       interactive cards/buttons can visibly "lift". */
    --shadow-sm: 0 1px 4px rgba(28, 26, 23, 0.06);
    --shadow: 0 2px 10px rgba(28, 26, 23, 0.07), 0 1px 2px rgba(28, 26, 23, 0.05);
    --shadow-md: 0 6px 20px rgba(28, 26, 23, 0.12), 0 2px 6px rgba(28, 26, 23, 0.08);

    /* Motion — press is snappier than hover; expand/collapse is the
       slowest since it moves layout, not just a color/shadow. */
    --duration-fast: 100ms;
    --duration-base: 150ms;
    --duration-slow: 250ms;
    --ease-standard: cubic-bezier(0.2, 0, 0, 1);
    --transition-interactive: background-color var(--duration-base) var(--ease-standard),
        border-color var(--duration-base) var(--ease-standard),
        box-shadow var(--duration-base) var(--ease-standard),
        transform var(--duration-fast) var(--ease-standard),
        color var(--duration-base) var(--ease-standard);

    /* Icon sizing — every {% icon %} call picks one of these via its
       size= argument instead of a consumer hardcoding pixel widths. */
    --icon-size-xs: 14px;
    --icon-size-sm: 18px;
    --icon-size-md: 22px;
    --icon-size-lg: 28px;

    --focus-ring-color: var(--color-accent);
    --focus-ring-width: 2px;
    --focus-ring-offset: 2px;

    /* Minimum comfortable touch target (WCAG/Apple/Material all land
       near 44px) — applied via padding on icon-only buttons, not by
       inflating the icon itself. */
    --tap-target-min: 44px;
}

@media (prefers-color-scheme: dark) {
    :root {
        --color-bg: #14120f;
        --color-surface: #201d19;
        --color-text: #f3f0ec;
        --color-text-muted: #aba49b;
        --color-border: #32302b;
        --color-accent: #ff8a3d;
        --color-accent-rgb: 255, 138, 61;
        --color-accent-hover: #ffa262;
        --color-accent-press: #ffb583;
        --color-accent-contrast: #1c1200;
        --color-danger: #ff8a80;
        --color-danger-bg: #3a1f1c;
        --color-success: #7fd9a0;
        --color-success-bg: #163b26;
        --color-warning: #f2b866;
        --color-warning-bg: #3a2c10;
        --color-info: #7ec3ee;
        --color-info-bg: #142838;

        --shadow-sm: 0 1px 4px rgba(0, 0, 0, 0.3);
        --shadow: 0 2px 10px rgba(0, 0, 0, 0.4);
        --shadow-md: 0 6px 20px rgba(0, 0, 0, 0.55), 0 2px 6px rgba(0, 0, 0, 0.4);
    }
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
    font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
    background: var(--color-bg);
    color: var(--color-text);
    margin: 0;
    line-height: 1.45;
    font-size: 16px;
}

.page {
    max-width: 38rem;
    margin: 0 auto;
    padding: 0 1rem 2rem;
}
@media (min-width: 641px) {
    .page { max-width: 64rem; padding: 0 1.5rem 2.5rem; }
}

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

h1 { font-size: 1.5rem; margin: 1.25rem 0 0.75rem; }
h2 { font-size: 1.1rem; margin: 1.75rem 0 0.5rem; }

/* Global focus visibility — every interactive element gets the same
   ring, not just form fields. */
:focus-visible {
    outline: var(--focus-ring-width) solid var(--focus-ring-color);
    outline-offset: var(--focus-ring-offset);
}

/* Header — clean neutral chrome, not a solid color banner; the accent
   lives in buttons/badges/active states instead. */
header.site-header {
    background: var(--color-surface);
    border-bottom: 1px solid var(--color-border);
}
header.site-header .bar {
    max-width: 38rem;
    margin: 0 auto;
    padding: 0.6rem 1rem;
    display: grid;
    /* Equal 1fr side tracks (not auto) so the title sits at the true
       visual center of the bar regardless of the left/right content's
       own width — with two auto tracks, a wider nav-account (language
       switcher + login/signup) than nav-left would pull the title off
       -center even though it's centered within its own track. */
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: 0.5rem 0.75rem;
}
@media (min-width: 641px) {
    header.site-header .bar { max-width: 64rem; padding: 0.85rem 1.5rem; }
}
header.site-header .nav-left { display: flex; align-items: center; gap: 0.5rem; }
header.site-header .brand-icon { display: block; line-height: 0; flex-shrink: 0; }
header.site-header .brand-icon img { display: block; border-radius: 50%; }
@media (min-width: 641px) {
    /* The hamburger moved off to the right (see .nav-account below),
       freeing up room next to the logo — let it read a bit bigger. */
    header.site-header .brand-icon img { width: 72px; height: 72px; }
}
header.site-header .brand-title {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    text-align: center;
    color: var(--color-text);
    text-decoration: none;
    font-weight: 800;
    font-size: clamp(0.95rem, 3.6vw, 1.5rem);
    letter-spacing: 0.01em;
    line-height: 1.15;
}
header.site-header .brand-title:hover { color: var(--color-accent); }

/* Hamburger dropdown — desktop/tablet only; mobile uses the bottom nav
   for the same links instead (see .bottom-nav below). Lives at the
   right-hand end of the header (inside .nav-account, swapped in for the
   login/signup links once authenticated) so it's the first thing the
   eye lands on when scanning the bar left-to-right for "where do I
   navigate" — styled as a visible framed pill rather than a bare muted
   icon, so it doesn't blend into the chrome. */
header.site-header .nav-menu { position: relative; display: none; }
@media (min-width: 641px) {
    header.site-header .nav-menu { display: block; }
}
/* .landing-menu — same trigger/panel look, used only by the landing
   page's own header (see .site-header--landing below), always visible
   at every width unlike .nav-menu above. */
header.site-header .landing-menu { position: relative; display: block; }
header.site-header .nav-menu summary,
header.site-header .landing-menu summary {
    list-style: none;
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-height: var(--tap-target-min);
    padding: 0.6rem 1.1rem;
    border-radius: var(--radius-pill);
    border: 1px solid var(--color-border);
    background: var(--color-surface);
    color: var(--color-text);
    font-weight: 700;
    font-size: 0.95rem;
    box-shadow: var(--shadow-sm);
    transition: var(--transition-interactive);
}
header.site-header .nav-menu summary .icon,
header.site-header .landing-menu summary .icon { width: var(--icon-size-md); height: var(--icon-size-md); }
header.site-header .nav-menu summary::-webkit-details-marker,
header.site-header .landing-menu summary::-webkit-details-marker { display: none; }
header.site-header .nav-menu summary:hover,
header.site-header .landing-menu summary:hover {
    color: var(--color-accent);
    border-color: var(--color-accent);
    background: rgba(var(--color-accent-rgb), 0.06);
    box-shadow: var(--shadow-md);
}
header.site-header .nav-menu summary:active,
header.site-header .landing-menu summary:active { transform: scale(0.96); }
header.site-header .nav-menu[open] summary,
header.site-header .landing-menu[open] summary {
    color: var(--color-accent);
    border-color: var(--color-accent);
    background: rgba(var(--color-accent-rgb), 0.06);
}
header.site-header .nav-menu-panel,
header.site-header .landing-menu-panel {
    position: absolute;
    top: calc(100% + 0.5rem);
    right: 0;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-md);
    padding: var(--space-2);
    min-width: 13rem;
    display: flex;
    flex-direction: column;
    z-index: 30;
}
header.site-header .nav-menu-panel a,
header.site-header .nav-menu-panel button.link-button,
header.site-header .landing-menu-panel a,
header.site-header .landing-menu-panel button.link-button {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: 0.65rem 0.8rem;
    border-radius: var(--radius-sm);
    color: var(--color-text);
    text-decoration: none;
    font-weight: 600;
    font-size: 0.95rem;
    white-space: nowrap;
    transition: var(--transition-interactive);
    width: 100%;
    margin: 0;
    background: none;
    border: none;
    font-family: inherit;
    cursor: pointer;
    text-align: left;
}
header.site-header .nav-menu-panel a .icon,
header.site-header .nav-menu-panel button.link-button .icon,
header.site-header .landing-menu-panel a .icon,
header.site-header .landing-menu-panel button.link-button .icon {
    color: var(--color-text-muted);
    flex-shrink: 0;
}
header.site-header .nav-menu-panel a:hover,
header.site-header .nav-menu-panel button.link-button:hover,
header.site-header .landing-menu-panel a:hover,
header.site-header .landing-menu-panel button.link-button:hover {
    background: var(--color-bg);
    color: var(--color-accent);
}
header.site-header .nav-menu-panel a:hover .icon,
header.site-header .nav-menu-panel button.link-button:hover .icon,
header.site-header .landing-menu-panel a:hover .icon,
header.site-header .landing-menu-panel button.link-button:hover .icon { color: var(--color-accent); }
header.site-header .nav-menu-panel a:active,
header.site-header .nav-menu-panel button.link-button:active,
header.site-header .landing-menu-panel a:active,
header.site-header .landing-menu-panel button.link-button:active { background: var(--color-border); }
header.site-header .nav-menu-panel hr,
header.site-header .landing-menu-panel hr {
    border: none;
    border-top: 1px solid var(--color-border);
    margin: var(--space-2) 0.4rem;
    width: calc(100% - 0.8rem);
}

header.site-header .nav-account {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: 0.5rem 0.6rem;
    justify-self: end;
}

/* Login/Sign up — real bordered pill buttons (matching .nav-menu summary
   below) rather than plain text links, so their footprint doesn't visibly
   change between "Log in"/"Přihlásit se" etc. and throw off the header's
   centering — see the .bar grid comment above for the other half of that
   fix (equal 1fr side tracks). */
header.site-header .nav-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: var(--tap-target-min);
    min-width: 5.5rem;
    padding: 0.5rem 0.9rem;
    border-radius: var(--radius-pill);
    border: 1px solid var(--color-border);
    background: var(--color-surface);
    color: var(--color-text);
    text-decoration: none;
    font-weight: 700;
    font-size: 0.85rem;
    white-space: nowrap;
    box-shadow: var(--shadow-sm);
    transition: var(--transition-interactive);
}
header.site-header .nav-btn:hover {
    color: var(--color-accent);
    border-color: var(--color-accent);
    background: rgba(var(--color-accent-rgb), 0.06);
    box-shadow: var(--shadow-md);
}
header.site-header .nav-btn:active { transform: scale(0.96); }

/* Language switcher — flag icon-btns instead of "CS"/"EN" text, reusing
   the shared .icon-btn chrome; [disabled] already dims the active
   language (see .icon-btn[disabled] above). */
header.site-header .lang-flag-btn { font-size: 1.15rem; line-height: 1; }

/* Landing-page-only header (templates/bookings/new.html's {% block
   header %} override) — a big centered logo, which already has the
   company name baked into the artwork, replaces the separate logo+text
   row used everywhere else. The language switcher + account/menu
   trigger stack in the top-right, out of normal flow, so the logo stays
   centered regardless of their width — same principle as the
   1fr/auto/1fr trick above, just via absolute positioning since there's
   no third column to balance against here. Every other page keeps the
   default header untouched.

   Everything lives inside .landing-bar, which is deliberately its own
   class (not a reuse of .bar — that one is already a grid with its own
   column layout that would fight this one) but matches .bar's max-width/
   centering exactly, and is itself the `position: relative` anchor for
   the absolutely-positioned corner stack. Anchoring to the header
   element directly (full viewport width, no max-width) was the earlier
   bug: "right: 0" against the header put the stack at the literal
   browser edge on a wide screen, nowhere near the centered content
   column the rest of the page uses. */
header.site-header.site-header--landing {
    /* Blend into the page instead of reading as a separate surface-toned
       "banner" block — .site-header (above) defaults to --color-surface,
       which is a real, if subtle, different shade from the page's own
       --color-bg (noticeably visible as a warmer, lighter band in dark
       mode). The extra `.site-header` in this selector isn't redundant —
       it's what gives this rule enough specificity to win over that one
       regardless of source order. */
    background: var(--color-bg);
    border-bottom: none;
    padding: 0.75rem 0 0.85rem;
    text-align: center;
}
@media (min-width: 641px) {
    header.site-header.site-header--landing { padding: 1rem 0 1.1rem; }
}
header.site-header--landing .landing-bar {
    position: relative;
    max-width: 38rem;
    margin: 0 auto;
    padding: 0 1rem;
}
@media (min-width: 641px) {
    header.site-header--landing .landing-bar { max-width: 64rem; padding: 0 1.5rem; }
}
header.site-header--landing .landing-actions {
    /* `right` here must match .landing-bar's own horizontal padding
       (not just 0) — absolute positioning offsets are measured from the
       containing block's padding-box OUTER edge, which is unaffected by
       that padding; without this, the stack lands 1rem/1.5rem past
       where the rest of the page's content (.hero, .pricing, etc.)
       actually ends. */
    position: absolute;
    top: 0;
    right: 1rem;
    z-index: 2;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 0.4rem;
}
@media (min-width: 641px) {
    header.site-header--landing .landing-actions { right: 1.5rem; }
}
header.site-header--landing .landing-menu summary { padding: 0.5rem; }
header.site-header--landing .landing-logo { display: inline-block; }
header.site-header--landing .landing-logo img {
    display: block;
    width: 84px;
    height: 84px;
    border-radius: 50%;
}
@media (min-width: 641px) {
    header.site-header--landing .landing-logo img { width: 116px; height: 116px; }
}

header.site-header form { margin: 0; }
header.site-header button.link-button {
    background: none;
    border: none;
    color: var(--color-text-muted);
    font: inherit;
    font-weight: 600;
    font-size: 0.9rem;
    cursor: pointer;
    padding: 0;
    width: auto;
    margin: 0;
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
}
header.site-header button.link-button:hover { color: var(--color-accent); }

header.site-header .lang-switch { display: flex; gap: 0.4rem; }
header.site-header .lang-switch button[disabled] { color: var(--color-text); cursor: default; }

/* Legal-content tables (pages/privacy_*.html, terms_*.html, cookies_*.html) */
.legal-content table { width: 100%; border-collapse: collapse; margin: 1em 0; }
.legal-content th, .legal-content td {
    text-align: left;
    padding: var(--space-2) var(--space-3);
    border-bottom: 1px solid var(--color-border);
}

/* Bottom tab bar — primary navigation on phones. Hidden on wider
   screens, where the header's hamburger .nav-menu takes over instead.
   Icon-only (see the hidden span below) — labels don't scale to six-plus
   destinations at phone width without wrapping/crowding; each icon still
   carries the label as an aria-label on the anchor for accessibility. */
.bottom-nav {
    display: none;
    position: fixed;
    left: 0; right: 0; bottom: 0;
    background: var(--color-surface);
    border-top: 1px solid var(--color-border);
    padding: 0.35rem 0.5rem calc(0.35rem + env(safe-area-inset-bottom, 0px));
    z-index: 20;
}
.bottom-nav .bar { max-width: 38rem; margin: 0 auto; display: flex; }
.bottom-nav a {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0.5rem 0.25rem;
    min-height: var(--tap-target-min);
    color: var(--color-text-muted);
    text-decoration: none;
    border-radius: var(--radius-sm);
    transition: var(--transition-interactive);
}
.bottom-nav a .nav-label { display: none; }
.bottom-nav a:hover { color: var(--color-accent); background: var(--color-bg); }
.bottom-nav a:active { transform: scale(0.94); }
.bottom-nav a.active { color: var(--color-accent); }

/* Unread-count badge on a nav_items entry (currently just "Home" — see
   apps.core.context_processors.nav_items) — a small solid pill sitting
   inline next to the icon. In the bottom-nav, .nav-label is display:none
   so this ends up right beside the (otherwise icon-only) icon rather than
   overlapping it; in the hamburger dropdown it just follows the label
   text like a normal inline badge. */
.nav-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.1rem;
    height: 1.1rem;
    padding: 0 0.3rem;
    margin-left: 0.3rem;
    border-radius: var(--radius-pill);
    background: var(--color-danger);
    color: #fff;
    font-size: 0.68rem;
    font-weight: 700;
    line-height: 1;
}

@media (max-width: 640px) {
    .bottom-nav { display: block; }
    body.has-bottom-nav .page { padding-bottom: 5.25rem; }
}

/* ---------------------------------------------------------------------
   Cards — one component, several modifiers. Every "box on a surface" in
   the app (plain card, list row, expandable disclosure, stat tile,
   marketing tile, profile header) is `.card` plus one of the
   `.card--*` modifiers below, so they all share the same base visual
   language and interactive states.
   ------------------------------------------------------------------ */
fieldset, .card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: 1.1rem 1.2rem;
    margin: 1rem 0;
    transition: var(--transition-interactive);
}
fieldset legend, .card-title { font-weight: 600; padding: 0 0.3rem; }

/* Any card that acts as a button/link gets a visible lift on hover and
   a visible "push" on press — this is the one shared interactive-card
   rule the rest of the file builds on. */
a.card:hover, .card--expandable:hover, .card--stat:hover,
a.card--row:hover, .card--row:has(> a:hover) {
    border-color: var(--color-accent);
    box-shadow: var(--shadow-md);
}
a.card:active, a.card--row:active {
    transform: scale(0.99);
    box-shadow: var(--shadow-sm);
}

/* Two-zone row layout — an info column (title/subtitle text, grows and
   truncates) and an actions column (fixed-width icon buttons) — the
   standard internal structure for list rows and expandable summaries. */
.row-info { flex: 1 1 auto; min-width: 0; }
.row-info .row-title { font-weight: 600; }
.row-info .row-sub { color: var(--color-text-muted); font-size: 0.9rem; }
.row-actions {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: var(--space-2);
}
/* A one-button `<form>` (e.g. a Cancel action) sitting among icon-btn
   anchors in a `.row-actions` strip shouldn't introduce its own block-level
   box — make it a flex item itself (rather than `display: contents`, which
   left its button sitting a couple pixels lower than the sibling anchors
   in testing) so its child button centers exactly like the rest. */
.row-actions form { display: inline-flex; align-items: center; margin: 0; }
/* `.card__body form button` (below) adds top spacing for a submit button
   that follows a stack of form fields (Mark complete, Save changes) — it
   also matches a button inside a `.row-actions` form sitting on its own
   (e.g. Cancel next to the Customer/Edit icon-btns), pushing it a few px
   lower than its siblings. The extra `.icon-btn` in the selector is only
   to out-specificity that rule regardless of source order. */
.row-actions form button.icon-btn { margin-top: 0; }

/* `.card--row` — replaces the old standalone `ul.list li` box rule.
   Applied directly to each <li>. */
ul.list { list-style: none; padding: 0; margin: 0; }
.card--row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-3);
    padding: 0.85rem 1rem;
    margin: 0 0 var(--space-3);
}
.card--row .row-info a { color: var(--color-text); text-decoration: none; font-weight: 600; }
.card--row .row-info a:hover { color: var(--color-accent); }

/* `.card--row-link` — the whole row/card is tappable (its `.stretched-link`
   expands to cover the full card via ::after) while any buttons in
   `.row-actions` (call, email, edit…) stay independently clickable on
   top of it. Use for rows whose only purpose is "tap anywhere to open
   X" — e.g. the customers list, where a tiny name link crowded right
   next to a phone number/icon was hard to tap accurately. */
.card--row-link { position: relative; }
.card--row-link .stretched-link::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 1;
}
.card--row-link .row-actions { position: relative; z-index: 2; }
.card--row-link:has(.stretched-link:hover) { border-color: var(--color-accent); box-shadow: var(--shadow-md); }
.card--row-link:has(.stretched-link:active) { transform: scale(0.99); box-shadow: var(--shadow-sm); }

/* `.card--expandable` — native <details>-based disclosure, replaces the
   old `details.booking-card`. Used for booking cards, the customer
   "Add address"/"Book a discharge" inline forms, and the expandable
   stat-card sections (dashboard tiles, customer-detail sections). */
.card--expandable { padding: 0; overflow: hidden; }
.card__summary {
    list-style: none;
    cursor: pointer;
    padding: 0.9rem 1.1rem;
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
}
.card__summary::-webkit-details-marker { display: none; }
.card__summary .chevron {
    margin-left: auto;
    color: var(--color-text-muted);
    flex-shrink: 0;
    transition: transform var(--duration-base) var(--ease-standard);
}
.card--expandable[open] .card__summary .chevron { transform: rotate(180deg); }
.card__summary:hover { background: var(--color-bg); }
.card__body {
    padding: 0.75rem 1.1rem 1.1rem;
    border-top: 1px solid var(--color-border);
}
.card__body form button { margin-top: 0.75rem; }

.day-heading {
    margin: 1.5rem 0 0.5rem;
    font-size: 0.8rem;
    font-weight: 700;
    color: var(--color-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

/* `.card--stat` — dashboard summary tiles that filter the booking list
   below (see dashboard/home.html: hx-get swaps #booking-list, .active
   marks the current filter). */
.stats { display: flex; flex-wrap: wrap; gap: var(--space-3); margin: 1rem 0; }
.card--stat { flex: 1 1 8rem; margin: 0; padding: 0; border-width: 2px; text-align: center; }
a.card--stat {
    display: block;
    padding: 0.9rem 0.5rem;
    text-decoration: none;
    color: inherit;
}
.card--stat .value { font-size: 1.6rem; font-weight: 700; color: var(--color-accent); line-height: 1.1; }
.card--stat .label { font-size: 0.8rem; color: var(--color-text-muted); }
.card--stat.active,
a.card--stat.active { border-color: var(--color-accent); background: rgba(var(--color-accent-rgb), 0.06); }
@media (min-width: 900px) {
    .card--stat { flex-basis: 9rem; }
}

/* Calendar */
.calendar-nav { display: flex; justify-content: space-between; align-items: center; margin: 0.5rem 0; font-weight: 600; }
table.calendar-grid { width: 100%; border-collapse: collapse; margin: 0.5rem 0 1.5rem; }
table.calendar-grid th {
    font-size: 0.72rem;
    color: var(--color-text-muted);
    font-weight: 600;
    padding-bottom: 0.4rem;
}
table.calendar-grid td { text-align: center; padding: 0.15rem; }
.calendar-day {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    aspect-ratio: 1;
    border-radius: 50%;
    text-decoration: none;
    color: var(--color-text);
    font-size: 0.9rem;
    position: relative;
    transition: var(--transition-interactive);
}
.calendar-day:hover { background: var(--color-bg); }
.calendar-day:active { transform: scale(0.92); }
.calendar-day.outside { color: var(--color-border); }
.calendar-day.today { font-weight: 700; border: 2px solid var(--color-accent); }
.calendar-day.selected { background: var(--color-accent); color: var(--color-accent-contrast); }
.calendar-day.selected:hover { background: var(--color-accent-hover); }
.calendar-day.has-bookings::after {
    content: "";
    width: 4px;
    height: 4px;
    border-radius: 50%;
    background: var(--color-accent);
    position: absolute;
    bottom: 3px;
}
.calendar-day.selected.has-bookings::after { background: var(--color-accent-contrast); }

/* Public landing page: hero / features / pricing */
.hero {
    text-align: center;
    padding: 2rem 1.5rem;
    margin: 1rem 0 1.25rem;
    border-radius: var(--radius);
    background: linear-gradient(180deg, rgba(var(--color-accent-rgb), 0.12) 0%, rgba(var(--color-accent-rgb), 0) 100%);
}
.hero h1 { font-size: 1.85rem; margin-bottom: 0.4rem; }
.hero .tagline { color: var(--color-text-muted); font-size: 1.02rem; margin-bottom: 1.4rem; }
.hero .btn { width: auto; display: inline-block; padding: 0.85rem 2.4rem; margin-top: 0; border-radius: var(--radius-pill); }
.hero .hero-tel { margin-top: 1rem; font-size: 1.05rem; }

.features, .pricing { display: flex; flex-wrap: wrap; gap: var(--space-3); margin: 1rem 0; }
.card--feature { flex: 1 1 13rem; margin: 0; }
.card--feature h3 { margin: 0 0 0.35rem; font-size: 1rem; }
.card--feature p { margin: 0; color: var(--color-text-muted); font-size: 0.92rem; }
.card--pricing { flex: 1 1 9rem; margin: 0; text-align: center; }
.card--pricing .tier { font-weight: 600; }
.card--pricing p { margin: 0.2rem 0 0; font-size: 0.88rem; }

/* Forms */
label { display: block; margin-top: 0.85rem; font-weight: 600; font-size: 0.92rem; }
input, select, textarea {
    width: 100%;
    padding: 0.65rem 0.8rem;
    font-size: 1rem;
    margin-top: 0.3rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    background: var(--color-surface);
    color: var(--color-text);
    transition: var(--transition-interactive);
}
button, input[type="submit"], .btn {
    display: inline-block;
    margin-top: 1.25rem;
    padding: 0.8rem 1.25rem;
    font-size: 1.02rem;
    font-weight: 600;
    width: 100%;
    background: var(--color-accent);
    color: var(--color-accent-contrast);
    border: none;
    border-radius: var(--radius-sm);
    cursor: pointer;
    text-align: center;
    text-decoration: none;
    transition: var(--transition-interactive);
}
/* color: repeated explicitly here (not just inherited from .btn's base
   rule) because the generic `a:hover`/`a:active` rules above otherwise
   win on the `color` property for any <a class="btn"> — since neither
   selector actually conflicts with the other on specificity, the last
   one that touches `color` applies, which made link-buttons' text turn
   invisible (same color as their own hover background). */
button:hover, input[type="submit"]:hover, .btn:hover {
    background: var(--color-accent-hover);
    color: var(--color-accent-contrast);
    box-shadow: var(--shadow-md);
}
button:active, input[type="submit"]:active, .btn:active {
    background: var(--color-accent-press);
    color: var(--color-accent-contrast);
    transform: scale(0.99);
    box-shadow: none;
}

.btn-secondary {
    background: var(--color-surface);
    color: var(--color-accent);
    border: 1px solid var(--color-border);
}
/* color: repeated explicitly here too, same reason as the button:hover
   rule above — .btn-secondary keeps a different background on hover/active
   than the solid .btn does, so it can't inherit .btn:hover/:active's
   color (meant for text on the solid accent-colored background); without
   this the text became unreadable against .btn-secondary's own hover/
   active background. */
.btn-secondary:hover { background: var(--color-bg); border-color: var(--color-accent); color: var(--color-accent-hover); }
.btn-secondary:active { background: var(--color-border); color: var(--color-accent); }

/* Password/Google login divider (accounts/login.html, accounts/signup.html) */
.divider {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin: var(--space-4) 0;
    color: var(--color-text-muted);
    font-size: 0.85rem;
}
.divider::before, .divider::after { content: ""; flex: 1; height: 1px; background: var(--color-border); }

/* Any single-column form page (login/signup/social-login-confirm, the
   public booking form) — .page alone can stretch quite wide (see the
   min-width breakpoint below), which makes inputs look oversized and the
   whole form "bulky" on desktop; cap it to a normal form width and
   center it. */
.form-card { max-width: 26rem; margin: 0 auto; }

/* Google's brand guidelines call for their logo, not a plain text link —
   .btn is display:inline-block by default, so this switches just this
   button to a centered flex row for the logo+label pairing. */
.btn-google { display: flex; align-items: center; justify-content: center; gap: 0.6rem; }

/* "Draft, pending legal review" banner (pages/privacy.html, pages/terms.html) */
.notice-draft {
    background: var(--color-warning-bg);
    color: var(--color-warning);
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-sm);
    margin-bottom: var(--space-4);
    font-size: 0.9rem;
}

/* Irreversible-action warning banner (customers/confirm_delete.html) —
   same shape as .notice-draft, danger palette instead of warning. Its own
   heading/list get color set explicitly since generic h1/li rules
   elsewhere would otherwise apply the page's default text color, not this
   banner's danger one. */
.notice-danger {
    background: var(--color-danger-bg);
    color: var(--color-danger);
    padding: var(--space-4);
    border-radius: var(--radius-sm);
    margin-bottom: var(--space-4);
}
.notice-danger h1 { color: var(--color-danger); display: flex; align-items: center; gap: var(--space-2); margin-top: 0; }
.notice-danger ul { margin: var(--space-3) 0; padding-left: 1.4rem; }
.notice-danger p:last-child { margin-bottom: 0; }

/* Footer (base.html) */
.site-footer {
    margin-top: var(--space-6);
    padding-top: var(--space-4);
    border-top: 1px solid var(--color-border);
    text-align: center;
    color: var(--color-text-muted);
    font-size: 0.85rem;
}
.site-footer a { color: var(--color-text-muted); }
.site-footer a:hover { color: var(--color-accent); }

.errorlist { color: var(--color-danger); padding-left: 1.1rem; margin: 0.25rem 0; font-size: 0.9rem; }
.helptext { font-size: 0.85rem; color: var(--color-text-muted); }

/* Messages (django.contrib.messages) — colored by message.tags so
   errors/warnings read distinctly from a plain success confirmation. */
.messages { list-style: none; padding: 0; margin: 1rem 0 0; }
.messages li {
    padding: 0.75rem 1rem;
    border-radius: var(--radius);
    background: var(--color-success-bg);
    color: var(--color-success);
    margin-bottom: 0.5rem;
    font-weight: 500;
}
.messages li.error { background: var(--color-danger-bg); color: var(--color-danger); }
.messages li.warning { background: var(--color-warning-bg); color: var(--color-warning); }
.messages li.info { background: var(--color-info-bg); color: var(--color-info); }

/* Status badges — invoice status only now (issued/paid); booking status
   uses the colored .status-dot icon instead, see below. */
.badge {
    display: inline-block;
    padding: 0.15rem 0.6rem;
    border-radius: var(--radius-pill);
    font-size: 0.78rem;
    font-weight: 600;
}
.badge-confirmed { background: var(--color-info-bg); color: var(--color-info); }
.badge-completed { background: var(--color-success-bg); color: var(--color-success); }
.badge-cancelled { background: var(--color-border); color: var(--color-text-muted); }
.badge-overdue { background: var(--color-warning-bg); color: var(--color-warning); }
.badge-today { background: var(--color-accent); color: var(--color-accent-contrast); }

/* Icon sizing — every {% icon %} call renders `<span class="icon
   icon-{size}">...</span>`; size lives here, once, instead of being
   redeclared per consumer. */
.icon { display: inline-flex; align-items: center; justify-content: center; line-height: 0; flex-shrink: 0; vertical-align: middle; }
.icon svg { width: 100%; height: 100%; display: block; }
.icon-xs { width: var(--icon-size-xs); height: var(--icon-size-xs); }
.icon-sm { width: var(--icon-size-sm); height: var(--icon-size-sm); }
.icon-md { width: var(--icon-size-md); height: var(--icon-size-md); }
.icon-lg { width: var(--icon-size-lg); height: var(--icon-size-lg); }

/* Booking status dot — apps/bookings/templatetags/booking_extras.py
   (status_dot). A solid colored circle with a white glyph, not a text
   pill: blue/dash = confirmed, green/check = completed, red/x = cancelled. */
.status-dot {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    color: #fff;
    vertical-align: middle;
    flex-shrink: 0;
}
.status-dot--confirmed { background: var(--color-dot-blue); }
.status-dot--completed { background: var(--color-dot-green); }
.status-dot--cancelled { background: var(--color-dot-red); }

/* `.icon-btn` — a shared, tappable (~44px target via padding) icon
   button used for pagination, sort, logout, PDF-open, and any other
   "icon instead of a text link" affordance. Two visual variants: a
   neutral outline (default) and a solid accent-blue square (`.solid`,
   matches the older `.edit-icon` look, kept as an alias below). */
.icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    width: auto;
    min-width: var(--tap-target-min);
    min-height: var(--tap-target-min);
    margin: 0;
    padding: 0.4rem 0.7rem;
    border-radius: var(--radius-sm);
    border: 1px solid var(--color-border);
    background: var(--color-surface);
    color: var(--color-text);
    text-decoration: none;
    font-weight: 600;
    font-size: 0.9rem;
    font-family: inherit;
    line-height: inherit;
    cursor: pointer;
    transition: var(--transition-interactive);
    /* A real <button> (e.g. the Cancel action) needs to render at the exact
       same box metrics as the <a> icon-btns it sits beside in a row — strip
       the browser's native button chrome, which otherwise adds its own
       hidden padding/line-height and shows up as a few stray px of
       vertical offset next to its sibling anchors. */
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
}
.icon-btn:hover { border-color: var(--color-accent); color: var(--color-accent); background: var(--color-bg); }
.icon-btn:active { transform: scale(0.96); background: var(--color-border); }
.icon-btn[disabled], .icon-btn.disabled {
    opacity: 0.4;
    pointer-events: none;
}
.icon-btn.icon-only { padding: 0.4rem; }
.icon-btn.active { border-color: var(--color-accent); color: var(--color-accent); background: rgba(var(--color-accent-rgb), 0.08); }

/* Booking-card action colors — Customer/Edit/Cancel sit side by side on a
   booking card and need to read apart from each other at a glance, not
   just from the neutral pagination/sort icon-btns. One color per action,
   reused everywhere that action appears (dashboard/calendar cards, the
   booking detail page, a customer's own booking history). */
.icon-btn--customer { border-color: var(--color-accent); color: var(--color-accent); }
.icon-btn--customer:hover { border-color: var(--color-accent-hover); color: var(--color-accent-hover); background: var(--color-bg); }
.icon-btn--edit { border-color: var(--color-dot-blue); color: var(--color-dot-blue); }
.icon-btn--edit:hover { background: var(--color-info-bg); }
.icon-btn--cancel { border-color: var(--color-danger); color: var(--color-danger); }
.icon-btn--cancel:hover { background: var(--color-danger-bg); }

/* Go-back button — real browser history, not a link to a fixed parent
   page (see `{% block page_header %}` in base.html; templates that
   shouldn't show it, e.g. the two "home" tabs, override that block
   empty). Sits at the top of every other page's content. */
.back-btn { margin: 0.75rem 0 0.25rem; }

.muted { color: var(--color-text-muted); }
small { color: var(--color-text-muted); }

/* Profile card (customer detail) */
.card--profile h1 { margin-top: 0; }
.profile-line { margin: 0.35rem 0; }
.tel-link {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.15rem 0;
    color: var(--color-text);
    text-decoration: none;
    font-weight: 600;
    transition: var(--transition-interactive);
}
.tel-link .icon { color: var(--color-dot-green); }
.tel-link:hover { color: var(--color-dot-green); }

.email-link {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.15rem 0;
    color: var(--color-text);
    text-decoration: none;
    font-weight: 600;
    transition: var(--transition-interactive);
}
.email-link .icon { color: var(--color-dot-blue); }
.email-link:hover { color: var(--color-dot-blue); }

/* Small icon-only link next to an address (map-pin) or an invoice (pdf) —
   both red: a map pin (matches Google's own pin color) and a document
   icon, opening in a new tab. Map needs no API key (Address.maps_url). */
.icon-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--tap-target-min);
    height: var(--tap-target-min);
    border-radius: var(--radius-sm);
    color: var(--color-dot-red);
    vertical-align: middle;
    transition: var(--transition-interactive);
}
.icon-link:hover { color: #b8261d; background: var(--color-bg); }
.icon-link:active { transform: scale(0.94); }

/* Floating action button — the one-handed-reachable "add" affordance,
   e.g. "+ New customer" on the customers list. */
.fab {
    position: fixed;
    right: 1.25rem;
    bottom: calc(4.75rem + env(safe-area-inset-bottom, 0px));
    width: 3.5rem;
    height: 3.5rem;
    border-radius: 50%;
    background: var(--color-accent);
    color: var(--color-accent-contrast);
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 4px 14px rgba(var(--color-accent-rgb), 0.45);
    text-decoration: none;
    z-index: 15;
    transition: var(--transition-interactive);
}
.fab:hover { background: var(--color-accent-hover); color: var(--color-accent-contrast); box-shadow: 0 6px 20px rgba(var(--color-accent-rgb), 0.55); }
.fab:active { transform: scale(0.93); }
@media (min-width: 641px) {
    .fab { bottom: 1.5rem; }
}

/* Icon-only "Edit" button — a small solid-blue square instead of a text
   link, e.g. next to a customer or an address. Sizing/tap-target shared
   with .icon-btn; kept as its own class since the solid-blue treatment
   is visually distinct (an edit affordance, not a neutral action). */
.edit-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--tap-target-min);
    height: var(--tap-target-min);
    border-radius: var(--radius-sm);
    background: var(--color-dot-blue);
    color: #fff;
    vertical-align: middle;
    transition: var(--transition-interactive);
}
.edit-icon:hover { background: #2657c4; color: #fff; box-shadow: var(--shadow-sm); }
.edit-icon:active { transform: scale(0.94); }

/* Simple label:value field list (invoice detail) — a `<dl>` of
   full-width rows instead of ad hoc `<p><strong>` pairs. */
.field-row {
    display: flex;
    justify-content: space-between;
    gap: var(--space-3);
    padding: 0.5rem 0;
    margin: 0;
    border-bottom: 1px solid var(--color-border);
}
.field-row:last-child { border-bottom: none; }
.field-row dt { color: var(--color-text-muted); font-weight: 600; }
.field-row dd { margin: 0; text-align: right; }
dl.field-list { margin: 0; }

/* Stacked name/phone/email inside a .field-row dd (invoice detail's
   "Customer" row) — one clearly separated line each, phone/email as
   proper tap-to-call/tap-to-email buttons instead of a "Name — phone"
   run-on line. */
.contact-stack { display: flex; flex-direction: column; align-items: flex-end; gap: 0.3rem; }

/* Google Maps InfoWindow content (dashboard/map.html) — its popup chrome
   is always light/white, in both light and dark site themes (that's
   Google's own UI, not ours to restyle), but the content we inject into
   it still lives in our DOM and would otherwise inherit body's themed
   `color` — invisible near-white-on-white text in dark mode. Deliberately
   hardcoded, not a --color-* var: this must NOT follow the site theme. */
.map-infowindow { color: #1c1a17; }
.map-infowindow a { color: #ea6a12; }

/* The InfoWindow's own "×" close button (Google's chrome, not ours) is a
   CSS mask-image icon whose visible color comes from its background-color
   — and unlike the rest of the InfoWindow's fixed-white chrome, this one
   specific control follows prefers-color-scheme on its own, rendering
   white on the assumption it'll sit on a dark background. It never does
   here (the InfoWindow bubble is always white), so in dark mode it's a
   white × on a white popup. !important because this overrides Google's
   own dynamically-injected styles, not anything in our cascade. */
#map .gm-ui-hover-effect span { background-color: #1c1a17 !important; }

/* Custom confirmation dialog (static/js/confirm-dialog.js) — replaces the
   native browser confirm() popup for destructive form submits (booking
   cancellation) with an in-app banner matching the rest of the design
   system. Markup lives once in base.html; any <form data-confirm="..."> is
   intercepted automatically. */
.confirm-dialog { position: fixed; inset: 0; z-index: 100; display: flex; align-items: center; justify-content: center; padding: var(--space-4); }
.confirm-dialog[hidden] { display: none; }
.confirm-dialog__backdrop { position: absolute; inset: 0; background: rgba(0, 0, 0, 0.45); }
.confirm-dialog__panel {
    position: relative;
    width: 100%;
    max-width: 22rem;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-md);
    padding: var(--space-5);
}
.confirm-dialog__message { margin: 0 0 var(--space-4); color: var(--color-text); }
.confirm-dialog__actions { display: flex; gap: var(--space-3); }
/* Override the global `button, .btn { width: 100%; margin-top: 1.25rem }`
   rule — these two sit side by side, not stacked full-width. */
.confirm-dialog__actions .btn { width: auto; flex: 1; margin-top: 0; }

/* Solid-red danger button — the dialog's own destructive-confirm button,
   and reused standalone wherever a real (non-dialog) submit button needs
   the same "this is destructive" treatment, e.g. the customer-deletion
   page. Declared as its own class rather than nested under
   .confirm-dialog__confirm so it works either way. */
.btn-danger { background: var(--color-danger); color: var(--color-accent-contrast); border: none; }
.btn-danger:hover { background: var(--color-danger); color: var(--color-accent-contrast); filter: brightness(0.92); box-shadow: var(--shadow-md); }
.btn-danger:active { background: var(--color-danger); color: var(--color-accent-contrast); filter: brightness(0.85); transform: scale(0.99); box-shadow: none; }
