/* =========================================================================
   Lexicon Admin — design system
   Palette, type pair and visual language taken from the customer-facing
   brand (brand/identity.md): navy primary, terra cotta accent, cream ground,
   Cormorant Garamond + Inter.

   One deliberate departure. The public site is "elegant minimalism, lots of
   white space" — right for a page someone reads once. This is a tool trainers
   open twenty times a day, so the spacing scale is tighter and Cormorant is
   reserved for page titles and the wordmark. Body text, tables and controls
   are all Inter: a serif in a data table is slower to read, and the density
   that makes a marketing page feel calm makes an admin feel sluggish.
   ========================================================================= */

/* ---------------------------------------------------------------- fonts --
   Self-hosted on purpose. Loading these from fonts.googleapis.com sends
   every visitor's IP to Google, which is exactly the kind of quiet leak this
   project's privacy requirement exists to prevent. Run `make fonts` to fetch
   them; until then the fallback stacks below carry the design.             */

@font-face {
    font-family: 'Cormorant Garamond';
    src: url('/assets/fonts/cormorant-garamond-600-latin-ext.woff2') format('woff2');
    font-weight: 600; font-style: normal; font-display: swap;
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
    font-family: 'Cormorant Garamond';
    src: url('/assets/fonts/cormorant-garamond-600-latin.woff2') format('woff2');
    font-weight: 600; font-style: normal; font-display: swap;
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'Inter';
    src: url('/assets/fonts/inter-latin-ext.woff2') format('woff2');
    font-weight: 100 900; font-style: normal; font-display: swap;
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
    font-family: 'Inter';
    src: url('/assets/fonts/inter-latin.woff2') format('woff2');
    font-weight: 100 900; font-style: normal; font-display: swap;
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* --------------------------------------------------------------- tokens */

:root {
    /* Brand — these five are the customer site's, unchanged */
    --navy: #1a2540;
    --terra: #b5541c;
    --cream: #f5f0e8;
    --text-light: #6b7280;
    --border-brand: #e5e7eb;

    /* Derived steps the admin needs and a marketing page does not */
    --navy-900: #0f1626;
    --navy-700: #2a3757;
    --navy-300: #7b86a3;
    --terra-700: #94430f;
    --terra-100: #f4e3d8;
    --cream-50: #fbf9f5;

    /* Status. The brand defines none, so these are chosen to sit beside
       terra without competing with it — terra means "act", never "alert". */
    --success: #2e6b4f;
    --warning: #8a6d1f;
    --danger: #93251c;

    /* Semantic surface */
    --bg: var(--cream);
    --surface: #ffffff;
    --surface-2: var(--cream-50);
    /* The sidebar is light. An always-navy slab down the left is a lot of
       dark to stare at all day, and the brand uses navy for type, not for
       large fills — the public site's ground is cream. */
    --sidebar-bg: #ffffff;
    --sidebar-ink: #5b6478;
    --sidebar-ink-strong: var(--navy);
    --sidebar-border: var(--border);
    --sidebar-active-bg: var(--cream);
    --border: var(--border-brand);
    --border-strong: #d3cec4;
    --text: var(--navy);
    --text-muted: var(--text-light);
    --accent: var(--terra);
    --accent-hover: var(--terra-700);
    --accent-ink: #ffffff;
    --focus: var(--terra);

    /* Type */
    --font-display: 'Cormorant Garamond', 'Iowan Old Style', Georgia, 'Times New Roman', serif;
    --font-body: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;
    --font-mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, monospace;

    /* Scale — 4px base */
    --s1: 4px;  --s2: 8px;  --s3: 12px; --s4: 16px;
    --s5: 24px; --s6: 32px; --s7: 48px; --s8: 64px;

    --radius: 8px;
    --radius-sm: 5px;
    --radius-pill: 999px;

    --shadow-sm: 0 1px 2px rgb(26 37 64 / 6%);
    --shadow: 0 1px 3px rgb(26 37 64 / 8%), 0 8px 24px -12px rgb(26 37 64 / 12%);

    --sidebar-w: 232px;
}

/* Dark is opt-in only.
   Following prefers-color-scheme meant anyone with their OS in dark mode got a
   dark admin whether they wanted one or not, which is the wrong default for a
   tool used in daylight. The palette below applies only when someone asks for
   it with the toggle. */
:root[data-theme="dark"] {
    --bg: #0f1626;
    --sidebar-border: #2b3550;
    --sidebar-active-bg: #232d4a;
    --surface: #182034;
    --surface-2: #1c2540;
    --sidebar-bg: #131b2e;
    --sidebar-ink: #9aa3b5;
    --sidebar-ink-strong: #f2ede4;
    --border: #2b3550;
    --border-strong: #3a4666;
    --text: #eae6dd;
    --text-muted: #9aa3b5;
    --accent: #d4703a;
    --accent-hover: #e2854f;
    --accent-ink: #0f1626;
    --focus: #d4703a;
    --success: #4c9a75;
    --warning: #c2a24a;
    --danger: #d4685c;
}

/* ----------------------------------------------------------------- base */

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

/* The browser's own `[hidden] { display: none }` is a bare attribute selector
   and loses to any class that sets `display` — .btn does, so a hidden button
   stayed on screen. This makes `hidden` mean hidden everywhere. */
[hidden] { display: none !important; }

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

body {
    margin: 0;
    background: var(--bg);
    color: var(--text);
    font-family: var(--font-body);
    font-size: 14.5px;
    line-height: 1.55;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

h1, h2, h3 { margin: 0; font-weight: 600; letter-spacing: -0.01em; }

h1 {
    font-family: var(--font-display);
    font-size: 30px;
    font-weight: 600;
    letter-spacing: 0;
    line-height: 1.15;
}

h2 { font-size: 16px; }
h3 { font-size: 14.5px; }

p { margin: 0 0 var(--s3); }

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

:where(a, button, input, select, textarea, summary):focus-visible {
    outline: 2px solid var(--focus);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
}

hr { border: 0; border-top: 1px solid var(--border); margin: var(--s5) 0; }

code { font-family: var(--font-mono); font-size: 0.9em; }

/* --------------------------------------------------------------- layout */

.app {
    display: grid;
    grid-template-columns: var(--sidebar-w) minmax(0, 1fr);
    min-height: 100vh;
}

.sidebar {
    background: var(--sidebar-bg);
    color: var(--sidebar-ink);
    border-right: 1px solid var(--sidebar-border);
    padding: var(--s5) var(--s3);
    display: flex;
    flex-direction: column;
    gap: var(--s5);
}

.sidebar__brand {
    display: flex;
    align-items: center;
    gap: var(--s3);
    padding: 0 var(--s2);
    color: var(--sidebar-ink-strong);
}

.sidebar__brand img { width: 30px; height: 30px; display: block; }

/* Two flat one-colour marks rather than a filter hack: whichever suits the
   current ground is shown, the other is removed from the layout.
   Note the element in the selector — `.sidebar__brand img` above outranks a
   bare `.logo--dark`, which left both marks painted on top of each other. */
.sidebar__brand img.logo--dark { display: none; }
:root[data-theme="dark"] .sidebar__brand img.logo--light { display: none; }
:root[data-theme="dark"] .sidebar__brand img.logo--dark { display: block; }

.sidebar__wordmark {
    font-family: var(--font-display);
    font-size: 21px;
    font-weight: 600;
    line-height: 1;
}

.sidebar__wordmark span { color: var(--text-muted); font-weight: 400; }

.nav { display: flex; flex-direction: column; gap: 2px; }

.nav__label {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-muted);
    padding: var(--s3) var(--s2) var(--s1);
}

.nav__item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--s2);
    padding: 7px var(--s2);
    border-radius: var(--radius-sm);
    color: var(--sidebar-ink);
    font-size: 14px;
}

.nav__item:hover { background: var(--sidebar-active-bg); text-decoration: none; color: var(--sidebar-ink-strong); }

.nav__item[aria-current="page"] {
    background: var(--sidebar-active-bg);
    color: var(--sidebar-ink-strong);
    font-weight: 500;
    box-shadow: inset 2px 0 0 var(--accent);
}

.nav__item--soon { opacity: 0.45; pointer-events: none; }

.sidebar__foot { margin-top: auto; font-size: 12px; color: var(--sidebar-ink); padding: 0 var(--s2); }
.sidebar__foot a { color: var(--sidebar-ink); }

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

.topbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--s4);
    padding: var(--s3) var(--s6);
    background: var(--surface);
    border-bottom: 1px solid var(--border);
}

.topbar__who { display: flex; align-items: center; gap: var(--s3); font-size: 13.5px; color: var(--text-muted); }

.theme-toggle {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 10px;
    font: inherit;
    font-size: 13px;
    color: var(--text-muted);
    background: transparent;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    cursor: pointer;
}

.theme-toggle:hover { color: var(--text); border-color: var(--border-strong); }
.theme-toggle__dark { display: none; }
:root[data-theme="dark"] .theme-toggle__light { display: none; }
:root[data-theme="dark"] .theme-toggle__dark { display: inline; }

.content { padding: var(--s6); max-width: 1120px; width: 100%; }

.page-head {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--s4);
    margin-bottom: var(--s5);
}

.page-head__sub { color: var(--text-muted); margin: var(--s1) 0 0; font-size: 14px; }

@media (max-width: 860px) {
    .app { grid-template-columns: minmax(0, 1fr); }
    .sidebar { flex-direction: row; align-items: center; gap: var(--s4); padding: var(--s3) var(--s4); overflow-x: auto; }
    .sidebar__foot, .nav__label { display: none; }
    .nav { flex-direction: row; gap: var(--s1); }
    .nav__item { white-space: nowrap; }
    .content, .topbar { padding-left: var(--s4); padding-right: var(--s4); }
}

/* ---------------------------------------------------------------- cards */

.card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
}

.card__body { padding: var(--s5); }

.card__head {
    padding: var(--s4) var(--s5);
    border-bottom: 1px solid var(--border);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--s3);
}

.card__title { font-size: 14.5px; font-weight: 600; }

.grid { display: grid; gap: var(--s4); }
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.grid--3 { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }

/* ---------------------------------------------------------------- stats */

.stat { padding: var(--s4) var(--s5); }
.stat__label { font-size: 12px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted); }
.stat__value { font-family: var(--font-display); font-size: 32px; line-height: 1.1; margin-top: var(--s1); }
.stat__note { font-size: 12.5px; color: var(--text-muted); margin-top: var(--s1); }
.stat__value--empty { color: var(--border-strong); }
.stat__value--warn { color: var(--warning); }
.stat__value--danger { color: var(--danger); }

/* -------------------------------------------------------------- buttons */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--s2);
    padding: 8px 15px;
    font: inherit;
    font-size: 14px;
    font-weight: 500;
    line-height: 1.3;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    cursor: pointer;
    background: var(--surface);
    color: var(--text);
    white-space: nowrap;
}

.btn:hover { text-decoration: none; }

.btn--primary { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.btn--primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); }

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

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

/* Destructive actions are outlined rather than filled: a wall of solid red
   trains people to click through it. */
.btn--danger { background: transparent; border-color: var(--danger); color: var(--danger); }
.btn--danger:hover { background: var(--danger); color: #fff; }

.btn--block { width: 100%; }
.btn--sm { padding: 5px 10px; font-size: 13px; }

.btn:disabled, .btn[aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; }

.btn-row { display: flex; flex-wrap: wrap; gap: var(--s2); }

/* --------------------------------------------------------------- forms */

.field { margin-bottom: var(--s4); }

.label {
    display: block;
    font-size: 13px;
    font-weight: 500;
    color: var(--text);
    margin-bottom: var(--s1);
}

.hint { font-size: 12.5px; color: var(--text-muted); margin-top: var(--s1); }

.input, .select, .textarea {
    width: 100%;
    padding: 9px 11px;
    font: inherit;
    font-size: 14px;
    color: var(--text);
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
}

.input::placeholder { color: var(--navy-300); }
.input:hover, .select:hover, .textarea:hover { border-color: var(--text-muted); }
.textarea { min-height: 96px; resize: vertical; }

.field--invalid .input { border-color: var(--danger); }
.field__error { font-size: 12.5px; color: var(--danger); margin-top: var(--s1); }

/* -------------------------------------------------------------- tables */

.table-wrap { overflow-x: auto; }

.table { width: 100%; border-collapse: collapse; font-size: 14px; }

.table th {
    text-align: left;
    font-size: 11.5px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
    font-weight: 600;
    padding: var(--s2) var(--s4);
    border-bottom: 1px solid var(--border);
    white-space: nowrap;
}

.table td { padding: 11px var(--s4); border-bottom: 1px solid var(--border); }
.table tbody tr:last-child td { border-bottom: 0; }
.table tbody tr:hover { background: var(--surface-2); }
.table__num { text-align: right; font-variant-numeric: tabular-nums; }
.table__muted { color: var(--text-muted); }
.table__num--negative { color: var(--danger); font-weight: 600; }

/* -------------------------------------------------------------- badges */

.badge {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 2px 9px;
    border-radius: var(--radius-pill);
    font-size: 12px;
    font-weight: 500;
    line-height: 1.6;
    border: 1px solid var(--border-strong);
    color: var(--text-muted);
    background: var(--surface-2);
    /* A badge is a label, never a paragraph — it must not wrap or be squeezed. */
    white-space: nowrap;
    flex: 0 0 auto;
}

.badge--accent { border-color: var(--accent); color: var(--accent); background: transparent; }
.badge--success { border-color: var(--success); color: var(--success); background: transparent; }
.badge--warning { border-color: var(--warning); color: var(--warning); background: transparent; }
.badge--danger { border-color: var(--danger); color: var(--danger); background: transparent; }

/* -------------------------------------------------------------- alerts */

.alert {
    border: 1px solid var(--border);
    border-left: 3px solid var(--text-muted);
    background: var(--surface-2);
    border-radius: var(--radius-sm);
    padding: var(--s3) var(--s4);
    font-size: 14px;
    margin-bottom: var(--s4);
}

.alert--danger { border-left-color: var(--danger); }
.alert--success { border-left-color: var(--success); }
.alert--warning { border-left-color: var(--warning); }
.alert--info { border-left-color: var(--accent); }
.alert__title { font-weight: 600; margin-bottom: 2px; }

/* -------------------------------------------------------------- dialog --
   Native <dialog>: real modality, Esc to close, focus handling and a backdrop
   for free, rather than a div pretending to be a modal. The forms live in the
   DOM either way, so the HTTP tests drive them without opening anything. */

.dialog {
    width: min(640px, calc(100vw - 32px));
    padding: 0;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--text);
    box-shadow: 0 24px 64px -16px rgb(26 37 64 / 35%);
}

.dialog::backdrop {
    background: rgb(26 37 64 / 42%);
    backdrop-filter: blur(2px);
}

.dialog__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--s3);
    padding: var(--s4) var(--s5);
    border-bottom: 1px solid var(--border);
}

.dialog__title { font-family: var(--font-display); font-size: 21px; font-weight: 600; line-height: 1.2; }
.dialog__subtitle { color: var(--text-muted); font-size: 13px; margin-top: 2px; }

.dialog__close {
    border: 0;
    background: transparent;
    color: var(--text-muted);
    font-size: 22px;
    line-height: 1;
    padding: 4px 8px;
    border-radius: var(--radius-sm);
    cursor: pointer;
}

.dialog__close:hover { background: var(--surface-2); color: var(--text); }

.dialog__body { padding: var(--s5); max-height: min(62vh, 560px); overflow-y: auto; }

.dialog__foot {
    display: flex;
    justify-content: flex-end;
    gap: var(--s2);
    padding: var(--s4) var(--s5);
    border-top: 1px solid var(--border);
    background: var(--surface-2);
    border-radius: 0 0 var(--radius) var(--radius);
}

@media (prefers-reduced-motion: no-preference) {
    .dialog[open] { animation: dialog-in .14s ease-out; }

    @keyframes dialog-in {
        from { opacity: 0; transform: translateY(-6px); }
        to { opacity: 1; transform: none; }
    }
}

/* ------------------------------------------------------- section header */

.section-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--s3);
    margin: var(--s6) 0 var(--s3);
}

.section-head h2 { margin: 0; }

/* Fields sitting in a row, each still carrying its own label. */
.field-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s4);
    align-items: flex-end;
}

.field-row .field { margin-bottom: 0; }
.field--narrow { width: 132px; }
.field--date { width: 175px; }
.field--wide { width: 240px; }

/* -------------------------------------------------------------- search --*/

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

.search__input { padding-left: 34px; padding-right: 34px; }

.search__icon {
    position: absolute;
    left: 11px;
    top: 50%;
    transform: translateY(-50%);
    color: var(--text-muted);
    pointer-events: none;
    line-height: 0;
}

.search__clear {
    position: absolute;
    right: 6px;
    top: 50%;
    transform: translateY(-50%);
    border: 0;
    background: transparent;
    color: var(--text-muted);
    font-size: 18px;
    line-height: 1;
    padding: 4px 7px;
    border-radius: var(--radius-pill);
    cursor: pointer;
}

.search__clear:hover { background: var(--surface-2); color: var(--text); }

.kbd {
    display: inline-block;
    padding: 1px 6px;
    border: 1px solid var(--border-strong);
    border-bottom-width: 2px;
    border-radius: 4px;
    font-family: var(--font-mono);
    font-size: 11px;
    color: var(--text-muted);
    background: var(--surface);
}

/* ------------------------------------------------------------ sessions --
   Remaining sessions, as a count plus a row of pips. Bright pips are what is
   LEFT; the faint ones behind them are what has been used. */

.sessions { display: inline-flex; flex-direction: column; gap: 5px; align-items: flex-start; }

.sessions__count {
    font-variant-numeric: tabular-nums;
    font-weight: 650;
    font-size: 15px;
    line-height: 1;
    letter-spacing: -0.01em;
}

.sessions__total { color: var(--text-muted); font-weight: 400; }

.sessions__count--low { color: var(--warning); }
.sessions__count--out { color: var(--danger); }

.pips { display: flex; gap: 3px; }

.pip {
    width: 7px;
    height: 7px;
    border-radius: 2px;
    background: var(--border-strong);
}

.pip--left { background: var(--navy-300); }
.pip--left.pip--ok { background: var(--success); }
.pip--left.pip--low { background: var(--warning); }
.pip--left.pip--out { background: var(--danger); }

.pip--over {
    background: var(--danger);
    /* Set apart from the track so it reads as "past the end", not as part of it. */
    margin-left: 5px;
    box-shadow: -3px 0 0 -1px var(--danger);
}

.pip--over ~ .pip--over { margin-left: 0; box-shadow: none; }

.meter { width: 108px; height: 5px; background: var(--border); border-radius: var(--radius-pill); overflow: hidden; }
.meter__fill { height: 100%; border-radius: inherit; background: var(--success); }
.meter__fill--low { background: var(--warning); }
.meter__fill--out { background: var(--danger); }

/* The client page shows one dog at a time, so it can afford to be bigger. */
.sessions--lg { gap: var(--s2); }
.sessions--lg .sessions__count { font-family: var(--font-display); font-size: 34px; font-weight: 600; }
.sessions--lg .sessions__total { font-size: 20px; }
.sessions--lg .pip { width: 11px; height: 11px; border-radius: 3px; }
.sessions--lg .pips { gap: 4px; }
.sessions--lg .meter { width: 170px; height: 6px; }

/* -------------------------------------------------------- quick actions --*/

.quick { display: inline-flex; border: 1px solid var(--border-strong); border-radius: var(--radius-sm); overflow: hidden; }

.quick button {
    border: 0;
    border-right: 1px solid var(--border-strong);
    background: var(--surface);
    color: var(--text);
    font: inherit;
    font-size: 13px;
    padding: 6px 12px;
    cursor: pointer;
    white-space: nowrap;
}

.quick button:last-child { border-right: 0; }
.quick button:hover { background: var(--surface-2); }
.quick button[data-outcome="attended"]:hover { background: color-mix(in srgb, var(--success) 14%, transparent); color: var(--success); }
.quick button[data-outcome="no_show"]:hover { background: color-mix(in srgb, var(--danger) 14%, transparent); color: var(--danger); }
.quick button[data-outcome="excused"]:hover { background: color-mix(in srgb, var(--warning) 16%, transparent); color: var(--warning); }

/* --------------------------------------------------------------- toasts --*/

.toasts {
    position: fixed;
    right: var(--s5);
    bottom: var(--s5);
    z-index: 60;
    display: flex;
    flex-direction: column;
    gap: var(--s2);
    max-width: min(420px, calc(100vw - 32px));
}

.toast {
    display: flex;
    align-items: center;
    gap: var(--s3);
    padding: var(--s3) var(--s4);
    background: var(--surface);
    border: 1px solid var(--border);
    border-left: 3px solid var(--text-muted);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow);
    font-size: 14px;
}

.toast--success { border-left-color: var(--success); }
.toast--danger { border-left-color: var(--danger); }
.toast--warning { border-left-color: var(--warning); }
.toast--info { border-left-color: var(--accent); }
.toast__text { flex: 1; min-width: 0; }
.toast__action { flex: 0 0 auto; }

@media (prefers-reduced-motion: no-preference) {
    .toast { animation: toast-in .16s ease-out; }

    @keyframes toast-in {
        from { opacity: 0; transform: translateY(8px); }
        to { opacity: 1; transform: none; }
    }
}

/* ------------------------------------------------------------ list rows --*/

.table tbody tr[data-href] { cursor: pointer; }
.table__stack { display: flex; flex-direction: column; gap: 2px; }
.table__stack small { color: var(--text-muted); font-size: 12.5px; }

.chip {
    display: inline-block;
    padding: 1px 8px;
    margin-right: 4px;
    border-radius: var(--radius-pill);
    background: var(--surface-2);
    border: 1px solid var(--border);
    font-size: 12px;
    white-space: nowrap;
}

/* ------------------------------------------------------ inline warning --*/

.inline-warning {
    display: none;
    margin-top: var(--s1);
    font-size: 12.5px;
    color: var(--warning);
}

.inline-warning.is-visible { display: block; }

/* --------------------------------------------------------------- empty */

.empty {
    text-align: center;
    padding: var(--s7) var(--s5);
    color: var(--text-muted);
}

.empty__title { font-family: var(--font-display); font-size: 21px; color: var(--text); margin-bottom: var(--s2); }

/* --------------------------------------------------------------- login */

.auth {
    min-height: 100vh;
    display: grid;
    place-items: center;
    padding: var(--s5);
    background:
        radial-gradient(circle at 12% 8%, rgb(181 84 28 / 7%), transparent 42%),
        radial-gradient(circle at 88% 92%, rgb(26 37 64 / 7%), transparent 46%),
        var(--bg);
}

.auth__panel { width: 100%; max-width: 384px; }

.auth__brand { display: flex; align-items: center; gap: var(--s3); margin-bottom: var(--s5); }
.auth__brand img { width: 42px; height: 42px; }
.auth__wordmark { font-family: var(--font-display); font-size: 27px; line-height: 1; font-weight: 600; }
.auth__wordmark span { color: var(--text-muted); font-weight: 400; }
.auth__tagline { color: var(--text-muted); font-size: 13.5px; margin: var(--s1) 0 0; }
.auth__foot { text-align: center; margin: var(--s4) 0 0; font-size: 12.5px; color: var(--text-muted); }

/* --------------------------------------------------------------- utils */

.u-muted { color: var(--text-muted); }
.u-small { font-size: 12.5px; }
.u-mt-0 { margin-top: 0; }
.u-mb-0 { margin-bottom: 0; }
.u-stack > * + * { margin-top: var(--s4); }
.u-row { display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap; }
/* Badge + sentence: keep them on one line and let the sentence wrap inside
   itself rather than dropping below the badge. */
.u-row--label { flex-wrap: nowrap; align-items: baseline; }
.u-row--label > :last-child { min-width: 0; }
.u-nums { font-variant-numeric: tabular-nums; }
.u-nowrap { white-space: nowrap; }
.visually-hidden {
    position: absolute; width: 1px; height: 1px; overflow: hidden;
    clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

@media (prefers-reduced-motion: no-preference) {
    .btn, .nav__item, .input, .table tbody tr { transition: background-color .12s ease, border-color .12s ease, color .12s ease; }
}

/* ------------------------------------------------------------ audit log */

/* The payload is reference material, not something to read down a column, so
   it stays folded until asked for. */
.audit-detail > summary {
    cursor: pointer;
    color: var(--text-muted);
    list-style: none;
}
.audit-detail > summary::-webkit-details-marker { display: none; }
.audit-detail > summary::before { content: '\25B8'; margin-right: 6px; font-size: 10px; }
.audit-detail[open] > summary::before { content: '\25BE'; }
.audit-detail > summary:hover { color: var(--accent); }

.kv {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 2px var(--s3);
    margin: var(--s2) 0 0;
    font-size: 12.5px;
}
.kv dt { color: var(--text-muted); }
.kv dd { margin: 0; word-break: break-word; }

/* ------------------------------------------------------- progress notes */

/* A note lives in a table cell, so the affordance has to be a whole-cell
   click target without looking like a button crammed into a row. */
.note-cell {
    display: flex;
    align-items: baseline;
    gap: 6px;
    width: 100%;
    max-width: 320px;
    padding: 4px 6px;
    margin: -4px -6px;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    background: transparent;
    font: inherit;
    color: var(--text);
    text-align: left;
    cursor: pointer;
}
.note-cell:hover { background: var(--surface-2); border-color: var(--border); }
.note-cell:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

.note-cell__text {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* The one marker on this page that means "the owner will read this". A word,
   not a symbol: a trainer scanning the column should not have to remember what
   a dot meant. */
.note-cell__eye {
    flex: none;
    padding: 1px 5px;
    border: 1px solid var(--accent);
    border-radius: 999px;
    color: var(--accent);
    font-size: 10.5px;
    letter-spacing: 0.02em;
    text-transform: uppercase;
}
.note-cell--empty .note-cell__add { color: var(--text-muted); font-size: 12.5px; }
.note-cell--empty:hover .note-cell__add { color: var(--accent); }

/* Pushes Delete to the far left of the dialog footer, away from Save. */
.dialog__spacer { flex: 1; }

/* A select that reads as text until you go near it — for the trainer column,
   where a full bordered control beside the outcome select would make every
   row look like a form. */
.select--bare {
    /* Sized to the name, so the chevron sits beside it rather than at the far
       edge of the column with a lake of nothing in between. */
    width: auto;
    max-width: 170px;
    padding-left: 6px;
    border-color: transparent;
    background-color: transparent;
    color: var(--text-muted);
}
.select--bare:hover { border-color: var(--border); background-color: var(--surface-2); }
.select--bare:focus { color: var(--text); }

/* -------------------------------------------------------- schedule (day) */

/* A time grid rather than a list. Two classes at 17:00 is the thing you need
   to see at a glance, and a list is exactly the shape that hides it. */
.day {
    --px-per-minute: 0.95;
    position: relative;
    display: grid;
    grid-template-columns: 56px 1fr;
    padding: var(--s4) var(--s5) var(--s5);
}

.day__hours { position: relative; grid-column: 1 / -1; grid-row: 1; }

.day__hour {
    position: absolute;
    left: 0;
    right: 0;
    height: 0;
    top: calc((var(--hour) * 60 - var(--day-first) * 60) * var(--px-per-minute) * 1px);
    border-top: 1px solid var(--border);
}
.day__hour span {
    position: absolute;
    top: -8px;
    left: 0;
    width: 48px;
    font-size: 11.5px;
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
    background: var(--surface);
    padding-right: 6px;
}

.day__events {
    position: relative;
    grid-column: 2;
    grid-row: 1;
    margin: 0;
    padding: 0;
    list-style: none;
    min-height: calc((var(--day-last) - var(--day-first)) * 60 * var(--px-per-minute) * 1px);
}

.slot {
    position: absolute;
    /* Side by side when they overlap. --lanes is how many columns this
       event's cluster needs and --lane is which one it takes; a lone event
       has one lane and fills the width, so the common case is unaffected. */
    left: calc(8px + (100% - 8px) * var(--lane, 0) / var(--lanes, 1));
    width: calc((100% - 8px) / var(--lanes, 1) - 4px);
    top: calc((var(--start) - var(--day-first) * 60) * var(--px-per-minute) * 1px);
    /* A 30-minute floor: shorter than that and the text does not fit, and an
       unreadable block is worse than a slightly wrong one. */
    min-height: 40px;
    height: calc(var(--minutes) * var(--px-per-minute) * 1px);
    display: flex;
    gap: var(--s3);
    align-items: flex-start;
    padding: 7px 10px;
    border: 1px solid var(--border);
    border-left: 3px solid var(--accent);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
    overflow: hidden;
}

/* The clubs read as one thing; individual sessions read as a roster. */
.slot--club { border-left-color: var(--navy); background: var(--cream); }
.slot--low-floor-club { border-left-color: var(--success); background: var(--cream); }
.slot--other { border-left-color: var(--border-strong); }

.slot__time {
    flex: none;
    font-size: 12px;
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
    padding-top: 1px;
}
.slot__body { display: flex; flex-wrap: wrap; align-items: center; gap: 5px; min-width: 0; }
.slot__kind { font-weight: 600; }
.slot__kind--plain { font-weight: 500; }
.slot__dogs { display: flex; flex-wrap: wrap; gap: 4px; }

.chip {
    display: inline-block;
    padding: 1px 8px;
    border: 1px solid var(--border-strong);
    border-radius: 999px;
    background: var(--surface);
    font-size: 12.5px;
}

.allday {
    display: flex;
    align-items: baseline;
    gap: var(--s2);
    padding: 8px 12px;
    margin-bottom: var(--s3);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface);
}
.allday__mark { color: var(--accent); font-size: 9px; }

@media (max-width: 640px) {
    .day { grid-template-columns: 44px 1fr; padding: var(--s3); }
    .slot { flex-direction: column; gap: 2px; }
}

/* Vaccination: a one-field form that has to sit under a card without looking
   like a section of its own. */
.vax {
    display: flex;
    align-items: center;
    gap: var(--s2);
    flex-wrap: wrap;
    margin: calc(var(--s4) * -1) 0 var(--s4);
    padding: 10px var(--s5) var(--s4);
    border: 1px solid var(--border);
    border-top: 0;
    border-radius: 0 0 var(--radius) var(--radius);
    background: var(--surface);
}
.vax .label { margin: 0; }
.vax .input { width: auto; }
