/* assets/css/style.css */
/* EasyShow Premium Obsidian & Glassmorphic Design System */

:root {
    /* RGB Definitions for translucency */
    --bg-base-rgb: 6, 9, 19;
    --bg-surface-rgb: 15, 19, 34;
    --bg-card-rgb: 20, 26, 46;
    --bg-overlay-rgb: 29, 36, 63;
    
    --accent-primary-rgb: 255, 122, 0;
    
    --text-primary-rgb: 243, 244, 246;
    --text-secondary-rgb: 156, 163, 175;
    --text-muted-rgb: 107, 114, 128;
    
    --border-color-rgb: 30, 37, 64;
    --border-highlight-rgb: 42, 51, 91;
    
    --color-my-dogs-rgb: 239, 68, 68;
    --color-important-rgb: 245, 158, 11;
    --color-orders-rgb: 59, 130, 246;
    --color-friends-rgb: 16, 185, 129;

    /* Color Palette */
    --bg-base: #060913;          /* Deep dark obsidian */
    --bg-surface: #0F1322;       /* Midnight blue-gray surface */
    --bg-card: #141A2E;          /* Muted card background */
    --bg-overlay: #1D243F;       /* Highlight overlays */
    
    --accent-primary: #FF7A00;   /* Premium Vibrant Orange */
    --accent-glow: rgba(255, 122, 0, 0.8);
    
    --text-primary: #F3F4F6;     /* Bright gray */
    --text-secondary: #9CA3AF;   /* Muted gray */
    --text-muted: #6B7280;       /* Darker muted gray */
    
    --border-color: #1E2540;     /* Sharp clean borders */
    --border-highlight: #2A335B; /* Accent borders */

    /* Stacking layers. Anything positioned should pick one of these rather
       than inventing a number, so page content can never rise above the
       sticky header the way an open autocomplete list once did. */
    /* Height of the sticky header. Anything that sticks inside the page has to
       park below it, so the offset lives here instead of being guessed twice. */
    --header-height: 4.125rem;

    --z-content: 5;      /* in-page positioned elements */
    --z-popover: 50;     /* dropdowns and autocomplete lists */
    --z-chrome: 200;     /* sticky header and bottom navigation */
    --z-modal: 1000;     /* modal overlays */
    --z-notice: 9999;    /* toasts and the pull-to-refresh indicator */
    
    /* List priority colors */
    --color-my-dogs: #EF4444;    /* Coral Red */
    --color-important: #F59E0B;  /* Amber Orange */
    --color-orders: #3B82F6;     /* Electric Blue */
    --color-friends: #10B981;    /* Emerald Green */
    
    /* Typography */
    --font-display: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    --font-body: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    
    /* Effects */
    --radius-sm: 8px;
    --radius-md: 14px;
    --radius-lg: 20px;
    --shadow-premium: 0 10px 30px -10px rgba(0, 0, 0, 0.7);
    --transition-premium: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);

    /* The faintest possible lift off the background: hovered rows, striped
       tables, a secondary button under the cursor. It has to invert with the
       theme -- white at 2% is invisible on a white page, and that is a hover
       state and a table stripe silently disappearing rather than a colour
       being slightly off. */
    --tint-subtle: rgba(255, 255, 255, 0.03);
    --tint-subtle-strong: rgba(255, 255, 255, 0.05);
}

/*
 * The light palette.
 *
 * Only the variables are redefined -- nothing below this block knows which
 * theme it is painted in, which is the whole reason 950-odd rules could be
 * given a second palette without being touched. Written once and applied
 * twice: explicitly when the reader chose light, and through
 * prefers-color-scheme when they chose to follow the device.
 *
 * The accent does not change. It is the brand, it carries enough contrast on
 * both grounds, and an orange that shifted with the theme would read as two
 * different products.
 */
:root[data-theme="light"],
:root[data-theme="system"] {
    --bg-base-rgb: 247, 248, 250;
    --bg-surface-rgb: 255, 255, 255;
    --bg-card-rgb: 255, 255, 255;
    --bg-overlay-rgb: 237, 240, 246;

    --text-primary-rgb: 17, 24, 39;
    --text-secondary-rgb: 75, 85, 99;
    --text-muted-rgb: 107, 114, 128;

    --border-color-rgb: 226, 230, 238;
    --border-highlight-rgb: 203, 210, 224;

    --bg-base: #F7F8FA;
    --bg-surface: #FFFFFF;
    --bg-card: #FFFFFF;
    --bg-overlay: #EDF0F6;

    --text-primary: #111827;
    --text-secondary: #4B5563;
    --text-muted: #6B7280;

    --border-color: #E2E6EE;
    --border-highlight: #CBD2E0;

    /* The dark shadow was 70% black lifted off a near-black ground, which on
       white is a smudge. Light needs far less of it to read as raised. */
    --shadow-premium: 0 8px 24px -12px rgba(17, 24, 39, 0.18);

    --tint-subtle: rgba(17, 24, 39, 0.035);
    --tint-subtle-strong: rgba(17, 24, 39, 0.06);
}

/* Chosen light, and meant it: this must win even where the device says dark. */
:root[data-theme="light"] {
    color-scheme: light;
}

/* Following the device. The variables above are the light half, so the dark
   half is simply the defaults from :root, put back when the device asks. */
:root[data-theme="system"] {
    color-scheme: light dark;
}

@media (prefers-color-scheme: dark) {
    :root[data-theme="system"] {
        --bg-base-rgb: 6, 9, 19;
        --bg-surface-rgb: 15, 19, 34;
        --bg-card-rgb: 20, 26, 46;
        --bg-overlay-rgb: 29, 36, 63;

        --text-primary-rgb: 243, 244, 246;
        --text-secondary-rgb: 156, 163, 175;
        --text-muted-rgb: 107, 114, 128;

        --border-color-rgb: 30, 37, 64;
        --border-highlight-rgb: 42, 51, 91;

        --bg-base: #060913;
        --bg-surface: #0F1322;
        --bg-card: #141A2E;
        --bg-overlay: #1D243F;

        --text-primary: #F3F4F6;
        --text-secondary: #9CA3AF;
        --text-muted: #6B7280;

        --border-color: #1E2540;
        --border-highlight: #2A335B;

        --shadow-premium: 0 10px 30px -10px rgba(0, 0, 0, 0.7);

        --tint-subtle: rgba(255, 255, 255, 0.03);
        --tint-subtle-strong: rgba(255, 255, 255, 0.05);
    }
}

/* The document itself never scrolls sideways. body alone is not enough: with a
   fixed overlay open, the horizontal scroll a phone offered belonged to the
   root element, which is what made the dashboard slide left and right behind
   an open dialog.

   clip, not hidden: `hidden` makes this element a scroll container, and a
   sticky descendant sticks to that container rather than to the viewport — it
   unstuck the site header the moment it was added. `clip` refuses the scroll
   without creating the container, so the header keeps its perch. */
html {
    overflow-x: clip;
}

/*
 * Interface size.
 *
 * Three sets, chosen in Settings > Appearance and printed on <html> as
 * data-scale. Nothing below this block knows which set it is drawn at: sizes
 * and spacing are written in rem, so moving the root font size moves type and
 * padding together, which is what "a larger interface" has to mean -- type
 * alone grown inside unchanged boxes is a cramped page, not a bigger one.
 *
 * Compact is the original and is exactly 100%: every rem below was converted
 * from the pixel value it already had, so a reader who never opens this
 * setting sees the app unchanged to the pixel.
 *
 * A percentage rather than a pixel size, because the root font size a reader
 * set in their own browser is a preference too, and multiplying it keeps that
 * honoured. The two larger steps are deliberately modest -- roughly an eighth
 * and a quarter -- since a phone at a ringside has a fixed width, and past
 * that a table stops fitting rather than becoming easier to read.
 */
:root,
:root[data-scale="compact"] {
    font-size: 100%;
}

:root[data-scale="medium"] {
    font-size: 112.5%;
}

:root[data-scale="large"] {
    font-size: 125%;
}

/* Base resets */
* {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

/*input, textarea, select, .btn-premium {*/
/*    box-sizing: border-box;*/
/*}*/

/* The browser hides [hidden] from its own stylesheet, and ANY author `display`
   beats it — so a class like .expo-schedule-pill (display: inline-flex) left
   hidden pills on screen: every show showed "Source changed" while the totals,
   read from the same elements in JS, said zero. Author-level, so it wins. */
[hidden] {
    display: none !important;
}

body {
    background-color: var(--bg-base);
    color: var(--text-primary);
    font-family: var(--font-body);
    font-size: 0.95rem;
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
    padding-bottom: 5.625rem;
    /* clip, not hidden, for the same reason as on html above: hidden makes body
       a scroll container and the sticky header then sticks to body instead of
       to the viewport — which is to say it does not stick at all. */
    overflow-x: clip;
    overscroll-behavior-y: none;
}

/* Header & Branding */
header {
    background-color: rgba(var(--bg-base-rgb), 0.8);
    backdrop-filter: blur(16px);
    border-bottom: 1px solid var(--border-color);
    padding: 0 1.5rem;
    /* Fixed height so --header-height is the truth for sticky offsets below. */
    height: var(--header-height);
    display: flex;
    justify-content: space-between;
    align-items: center;
    position: sticky;
    top: 0;
    z-index: var(--z-chrome);
}

/*
 * The masthead does not take part in the interface size.
 *
 * Everything else in the app is written in rem so that compact, medium and
 * large move type and spacing together -- but the mark, the name beside it and
 * the version under that are the app's signature, not text anybody reads a
 * timetable from. Grown a quarter they crowd out the header without helping
 * anyone, so this corner is pinned in pixels on purpose. The values are the
 * rem they replaced, at the compact root: nothing moves at the default size.
 */
.brand {
    font-family: var(--font-display);
    font-size: 22.4px;
    font-weight: 800;
    letter-spacing: -0.03em;
    color: var(--text-primary);
    display: inline-flex;
    align-items: center;
    gap: 0;
    text-decoration: none;
}

.brand-logo {
    display: block;
    width: 65px;
    height: 65px;
    object-fit: contain;
}

.header-brand {
    display: flex;
    align-items: center;
}

.header-brand-text {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
}

.brand span {
    color: var(--accent-primary);
}

.brand:hover {
    filter: drop-shadow(0 0 8px var(--accent-glow));
}

.clock-panel {
    text-align: right;
    padding-left: 0.4375rem;
    line-height: 1.2;
}

.header-tools {
    align-items: center;
    display: flex;
    gap: 0;
}

.account-avatar {
    align-items: center;
    background: var(--bg-card);
    border: 1px solid var(--border-color);
    border-radius: 50%;
    color: var(--text-primary);
    display: flex;
    flex: 0 0 auto;
    justify-content: center;
    height: 40px;
    margin: 0 0 0 10px;
    /* The unread badge sits on the rim and must be allowed out; the photograph
       is cropped by its own radius instead of by the frame's overflow. */
    overflow: visible;
    position: relative;
    width: 40px;
}

.account-avatar svg {
    fill: none;
    height: 19px;
    stroke: currentColor;
    stroke-linecap: round;
    stroke-width: 1.7;
    width: 19px;
}

.account-avatar img {
    border-radius: 50%;
    display: block;
    height: 100%;
    object-fit: cover;
    width: 100%;
}

/* Feedback nobody has opened. Red, on the rim of the avatar, and only ever
   rendered for an administrator — the header does not draw an empty badge and
   wait, because a badge that is sometimes zero is a badge people learn to
   ignore. */
.account-unread {
    align-items: center;
    background: var(--color-my-dogs);
    border: 2px solid var(--bg-surface);
    border-radius: 999px;
    color: #fff;
    display: flex;
    font: 700 .62rem/1 var(--font-display);
    height: 18px;
    justify-content: center;
    min-width: 18px;
    /* em, not px: the chip grows with its own digits when a reader turns the
       interface size up, and the pixel-padding sweep in test_scale_choice
       stays meaningful. */
    padding: 0 0.3em;
    position: absolute;
    right: -4px;
    top: -4px;
}

.account-avatar.has-unread { border-color: rgba(var(--color-my-dogs-rgb), .6); }

.account-avatar:hover {
    border-color: var(--accent-primary);
    color: var(--accent-primary);
}

.account-avatar:focus-visible {
    outline: 2px solid var(--accent-primary);
    outline-offset: 2px;
}

.guest-account-links {
    align-items: center;
    display: flex;
    gap: 0.5rem;
}

.guest-account-links a {
    border: 1px solid var(--border-color);
    border-radius: 7px;
    color: var(--text-primary);
    font: 700 .72rem var(--font-display);
    padding: 0.4375rem 0.625rem;
    text-decoration: none;
    text-transform: uppercase;
}

.guest-account-links a:last-child {
    background: var(--accent-primary);
    border-color: var(--accent-primary);
    color: #fff;
}

/* The migration ledger. A list of files where the interesting column is the
   one that says whether it ran, so the state is a coloured word next to the
   name rather than something to work out from a date. */
.migration-list { display: grid; gap: 0; }
.migration-row { align-items: start; border-top: 1px solid var(--border-color); display: grid; gap: 1rem; grid-template-columns: 1fr auto; padding: 0.75rem 0; }
.migration-row:first-child { border-top: 0; }
.migration-name strong { display: block; font: 600 .88rem var(--font-display); overflow-wrap: anywhere; }
.migration-name small { color: var(--text-muted); display: block; font-size: .74rem; margin-top: 2px; }
.migration-status { font-weight: 700; }
.migration-ok .migration-status { color: var(--color-friends); }
.migration-adopted .migration-status { color: var(--text-secondary); }
.migration-pending .migration-status { color: var(--color-important); }
.migration-failed .migration-status { color: var(--color-my-dogs); }
.migration-running .migration-status { color: var(--color-orders); }
.migration-changed { color: var(--color-important); }
.migration-output { margin-top: 6px; }
.migration-output summary { color: var(--text-secondary); cursor: pointer; font-size: .74rem; }
.migration-output pre { background: var(--bg-base); border-radius: var(--radius-sm); font-size: .72rem; margin-top: 6px; overflow-x: auto; padding: 0.625rem; white-space: pre-wrap; }
.migration-row .btn-premium { padding: 0.5rem 1rem; width: auto; }

@media (max-width: 560px) {
    .migration-row { grid-template-columns: 1fr; }
    .migration-row .btn-premium { justify-self: start; }
}

/* The plus on the end of a section heading. It sits after the rule rather than
   before it -- ::after is the rule and order puts the button past it -- so the
   heading reads "Lists ————— +". */
.section-add {
    align-items: center;
    background: rgba(var(--accent-primary-rgb), .12);
    border: 1px solid var(--accent-primary);
    border-radius: 8px;
    color: var(--accent-primary);
    cursor: pointer;
    display: inline-flex;
    flex: 0 0 auto;
    font: 700 1.2rem var(--font-display);
    height: 30px;
    justify-content: center;
    line-height: 1;
    order: 1;
    padding: 0;
    transition: var(--transition-premium);
    width: 30px;
}
.section-add:hover { background: var(--accent-primary); color: var(--bg-base); }

/* The kind switches on the Lists page. Same chips as the dashboard, but they
   start at the left edge here: they are the page's first choice, not a filter
   tucked against the right of something already on screen. */
.list-type-filter { flex-wrap: wrap; justify-content: flex-start; }
.list-choose-hint { color: var(--text-muted); font-size: .85rem; margin: 14px 0; }
/* Pencil and bin on the end of a row of a list. */
.list-item-actions { display: flex; flex: 0 0 auto; gap: 0.5rem; }

.list-pill-show { font-size: .72rem; font-weight: 400; opacity: .6; }
.schedule-list-filter { flex-wrap: wrap; margin-bottom: 12px; }
.schedule-list-filter-note { align-self: center; color: var(--accent-primary); font: 700 .72rem var(--font-display); letter-spacing: .04em; text-transform: uppercase; }

/* Translations. The index is a phone book: a code per line, a column per
   language, and a blank column where a translation is missing -- that gap is
   the whole point of the page, so it is spotted without reading anything. */
.translation-search { align-items: stretch; display: flex; gap: 0.625rem; margin-bottom: 10px; max-width: 560px; }
.translation-search .input-field { flex: 1 1 auto; margin: 0; min-width: 0; }
/* .btn-premium is a full-width block by default, which on one row with a field
   eats the field. Beside an input it is only as wide as its own word. */
.translation-search .btn-premium { flex: 0 0 auto; padding: 0.75rem 1.375rem; white-space: nowrap; width: auto; }
.translation-index { margin-top: 24px; }
.translation-letter { display: grid; gap: 0 1.5rem; grid-template-columns: 56px 1fr; margin-bottom: 18px; }
/* The letter follows its own group down and stops at its end, so you always
   know which letter you are inside of. align-self keeps it its own height --
   a stretched grid item fills its area and has nowhere to stick to -- and the
   grid area is the group, which is what confines it to its own block.
   --header-height is the fixed header it must park under; it is a token
   precisely so this offset is not guessed a second time. */
.translation-letter h2 {
    align-self: start;
    color: var(--text-muted);
    font: 700 2rem var(--font-display);
    margin: 0;
    position: sticky;
    text-align: center;
    top: calc(var(--header-height) + 12px);
    z-index: var(--z-content);
}
.translation-rows { display: grid; }
.translation-row { align-items: baseline; border-radius: var(--radius-sm); display: grid; gap: 1rem; grid-template-columns: 1fr auto; padding: 0.375rem 0.5rem; text-decoration: none; }
.translation-row:hover { background: var(--bg-overlay); }
.translation-name { display: grid; gap: 0.0625rem; min-width: 0; }
.translation-text { color: var(--accent-primary); font-size: .92rem; overflow-wrap: anywhere; }
.translation-text.untranslated { color: var(--color-important); font-style: italic; }
.translation-code { color: var(--text-muted); font-size: .7rem; letter-spacing: .02em; overflow-wrap: anywhere; }
.translation-editing-code { color: var(--text-muted); font-size: .78rem; margin: -8px 0 18px; }
.translation-langs { display: grid; gap: 0.25rem; grid-template-columns: repeat(5, 28px); }
.translation-lang-mark { color: var(--text-secondary); font-size: .78rem; text-align: center; }
.translation-lang-mark.missing { border-bottom: 1px solid rgba(var(--color-important-rgb),.35); }

.translation-editor { display: grid; gap: 0.75rem; }
.translation-field { align-items: start; display: grid; gap: 0.625rem; grid-template-columns: 32px 1fr; }
.translation-field .input-field { margin: 0; }
.translation-lang { color: var(--text-muted); font: 700 .72rem var(--font-display); padding-top: 0.625rem; }
.translation-field.missing .input-field { border-color: rgba(var(--color-important-rgb),.5); }
.translation-field.missing .translation-lang { color: var(--color-important); }
.translation-flag { align-items: start; display: grid; gap: 0.625rem; grid-template-columns: 18px 1fr; }
.translation-flag small { color: var(--text-muted); display: block; font-size: .76rem; }
.translation-delete { align-items: center; display: flex; flex-wrap: wrap; gap: 0.75rem; margin-top: 18px; }
.translation-delete .settings-intro { flex: 1; margin: 0; min-width: 240px; }

@media (max-width: 560px) {
    .translation-letter { grid-template-columns: 34px 1fr; gap: 0 0.625rem; }
    .translation-row { grid-template-columns: 1fr; gap: 0.125rem; }
}

.language-choices { display: flex; flex-wrap: wrap; gap: 0.625rem; margin: 18px 0; }
.language-choice { align-items: center; background: var(--bg-base); border: 1px solid var(--border-color); border-radius: var(--radius-sm); color: var(--text-secondary); cursor: pointer; display: flex; font: inherit; gap: 0.625rem; padding: 0.75rem 1rem; transition: var(--transition-premium); }
.language-choice:hover { border-color: var(--accent-primary); color: var(--text-primary); }
.language-choice.active { border-color: var(--accent-primary); color: var(--text-primary); }
.language-choice-code { color: var(--accent-primary); font: 800 .72rem var(--font-display); }
.language-choice:focus-visible { outline: 2px solid var(--accent-primary); outline-offset: 2px; }

/* Theme picker. Same shape as the language choices, plus a swatch: the three
   options differ in how they look, so showing it beats describing it. The
   swatches are painted in literal colours on purpose -- a dark swatch has to
   stay dark while the page around it is light, or it illustrates nothing. */
.theme-choices { display: flex; flex-direction: column; gap: 0.625rem; margin: 18px 0; }
.theme-choice { align-items: center; background: var(--bg-base); border: 1px solid var(--border-color); border-radius: var(--radius-sm); color: var(--text-secondary); cursor: pointer; display: flex; font: inherit; gap: 0.75rem; padding: 0.75rem 1rem; text-align: left; transition: var(--transition-premium); width: 100%; }
.theme-choice:hover { border-color: var(--accent-primary); color: var(--text-primary); }
.theme-choice.active { border-color: var(--accent-primary); color: var(--text-primary); }
.theme-choice:focus-visible { outline: 2px solid var(--accent-primary); outline-offset: 2px; }
.theme-choice-text { display: flex; flex-direction: column; gap: 0.125rem; }
.theme-choice-text strong { color: var(--text-primary); font: 700 .9rem var(--font-display); }
.theme-choice-text small { color: var(--text-muted); font-size: .76rem; }
.theme-choice-swatch { border: 1px solid var(--border-highlight); border-radius: 50%; flex: 0 0 auto; height: 26px; width: 26px; }
.theme-swatch-dark { background: #0F1322; }
.theme-swatch-light { background: #F7F8FA; }
.theme-swatch-system { background: linear-gradient(135deg, #0F1322 0 50%, #F7F8FA 50% 100%); }

/* The size choices reuse the theme rows; the swatch is replaced by an "Aa"
   drawn at the size that choice actually gives, so the row is a sample rather
   than a description of one. Sizes in em against the row's own text, so the
   samples stay in the same proportion whichever set is currently on. */
.scale-choice-sample { align-items: center; color: var(--text-primary); display: flex; flex: 0 0 auto; font-family: var(--font-display); font-weight: 700; justify-content: center; line-height: 1; width: 1.75rem; }
.scale-sample-compact { font-size: .82rem; }
.scale-sample-medium { font-size: 1rem; }
.scale-sample-large { font-size: 1.2rem; }

/* Language switcher. A <details> rather than a scripted menu: it belongs in the
   header for a guest who has not loaded anything yet, and the five entries are
   plain links carrying ?lang, so it works with no JavaScript at all. */
.lang-switch {
    position: relative;
}

.lang-switch > summary {
    border: 1px solid var(--border-color);
    border-radius: 7px;
    color: var(--text-secondary);
    cursor: pointer;
    font: 700 .72rem var(--font-display);
    list-style: none;
    margin: 0 8px;
    padding: 0.4375rem 0.5625rem;
    user-select: none;
}

.lang-switch > summary::-webkit-details-marker { display: none; }

.lang-switch > summary:hover,
.lang-switch[open] > summary {
    border-color: var(--border-highlight);
    color: var(--text-primary);
}

.lang-switch > summary:focus-visible {
    outline: 2px solid var(--accent-primary);
    outline-offset: 2px;
}

.lang-switch-menu {
    background: var(--bg-card);
    border: 1px solid var(--border-color);
    border-radius: 12px;
    box-shadow: 0 8px 32px rgba(0, 0, 0, .4);
    display: flex;
    flex-direction: column;
    min-width: 160px;
    overflow: hidden;
    position: absolute;
    right: 0;
    top: calc(100% + 6px);
    z-index: var(--z-popover);
}

.lang-switch-menu a {
    color: var(--text-secondary);
    font-size: .85rem;
    padding: 0.625rem 0.875rem;
    text-decoration: none;
    white-space: nowrap;
}

.lang-switch-menu a:hover {
    background: var(--bg-overlay);
    color: var(--text-primary);
}

.lang-switch-menu a.active {
    color: var(--accent-primary);
    font-weight: 600;
}

.clock-time {
    font-family: var(--font-display);
    font-size: 1.3rem;
    font-weight: 700;
    color: var(--accent-primary);
    letter-spacing: -0.02em;
}

.blink-colon {
    animation: blink-colon 1s step-end infinite;
}

@keyframes blink-colon {
    50% { opacity: 0; }
}

.clock-date {
    font-size: 0.75rem;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

/* Main Container */
.container {
    max-width: 800px;
    margin: 0 auto;
    padding: 1.25rem;
    /* Clear the fixed bottom nav so the last card is never trapped under it. */
    padding-bottom: calc(5rem + env(safe-area-inset-bottom, 0px));
}
@media (max-width: 500px) {
    .container {
        padding: 0.625rem;
        padding-bottom: calc(4.625rem + env(safe-area-inset-bottom, 0px));
    }
    header {
        padding: 0 0.625rem 0 0.125rem;
    }
}



/* Section Header Typography */
.section-header,
.settings-group-title {
    font-family: var(--font-display);
    font-size: 1.15rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-secondary);
    margin: 32px 0 16px 0;
    display: flex;
    align-items: center;
    gap: 0.75rem;
}

.section-header::after,
.settings-group-title::after {
    content: '';
    flex: 1;
    height: 1px;
    background-color: var(--border-color);
}

/* Active Show Pill */
.active-show-bar {
    background: linear-gradient(90deg, var(--bg-surface) 0%, var(--bg-card) 100%);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    display: flex;
    flex-direction: column;
    margin-bottom: 24px;
    box-shadow: var(--shadow-premium);
    overflow: hidden;
}

.active-show-header {
    padding: 0.875rem 1.25rem;
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
}

/* The dashboard pill and a row of the shows list are the same card: a mark, a
   name, a venue, a tag. They were two families of class saying it twice, which
   is why the mark and the pin had to be added to each of them separately and
   why line-height: 1 landed on one of the two names. The pill keeps only what
   is really its own -- the bar, the header row, the countdown and the day
   buttons -- and everything inside it is .show-card-*.

   The info block still has to be the one that grows: the header is
   space-between, and without this the name and the countdown drift apart. */
.active-show-header .show-card-info { flex: 1 1 auto; }

.active-show-countdown {
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    text-align: right;
    white-space: nowrap;
    line-height: 1.2;
}

.active-show-countdown-value {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 1.4rem;
    color: var(--accent-primary);
}

.active-show-countdown-label {
    font-weight: 400;
    font-size: 1rem;
    color: var(--text-secondary);
}

/* The "now" tag in the countdown's place while the rings run. The badge the
   ring rows wear, a size up: it stands alone on the right, not beside a name.
   Two classes, because .schedule-now-badge is declared further down. */
.schedule-now-badge.active-show-now {
    margin-left: 0;
    font-size: 0.8rem;
    padding: 0.25rem 0.5rem;
}

.active-show-dates {
    display: flex;
    width: 100%;
    border-top: 1px solid var(--border-color);
}

.active-show-date-btn {
    flex: 1;
    text-align: center;
    padding: 0.625rem;
    font-size: 0.85rem;
    font-family: var(--font-display);
    text-decoration: none;
    font-weight: 700;
    color: var(--text-secondary);
    background-color: var(--bg-overlay);
    border-right: 1px solid var(--border-color);
    transition: var(--transition-premium);
}

.active-show-date-btn:last-child {
    border-right: none;
}

.active-show-date-btn:hover {
    background-color: var(--bg-surface);
    color: var(--text-primary);
}

.active-show-date-btn.active {
    background-color: var(--accent-primary);
    color: white;
}

/* A show whose ring schedule has not been imported yet. The name is a span
   rather than a link on this one, so there is nothing to hover and nothing
   to open -- the timetable behind it would be empty. */
.active-show-bar-unscheduled {
    opacity: 0.65;
}

/* The agreement at sign-up, and the cookie question in the welcome dialog. Both
   are a paragraph the reader has to be able to read before answering, so the
   control sits beside the text rather than above a wall of it. */
.auth-agree { align-items: flex-start; display: flex; font-weight: 400; gap: 0.5rem; line-height: 1.35; }
/* .settings-form input is display:block;width:100%, which a checkbox has no
   business inheriting: at full width it pushed the sentence beside it clean off
   the right of the screen. Overridden by element, not by class, so a checkbox
   added to this label later behaves the same. */
.auth-agree input[type="checkbox"] { flex: 0 0 auto; margin: 2px 0 0; width: auto; }
.auth-agree span { flex: 1 1 auto; font-size: .84rem; min-width: 0; }
.auth-agree a { color: var(--accent-primary); }

/* The cookie question, on every page. It sits above the bottom navigation
   rather than over the header — the header carries the brand, the clock and the
   account — and above the raised dashboard circle, the same clearance the
   offline banner takes. Not fixed to the very bottom, because that is where the
   navigation is and a reader's thumb is already there. */
.consent-bar {
    background: var(--bg-card);
    border-top: 1px solid var(--border-color);
    bottom: calc(4.75rem + env(safe-area-inset-bottom, 0px));
    box-shadow: 0 -12px 32px rgba(0,0,0,.45);
    left: 0;
    margin: 0 auto;
    max-width: 800px;
    padding: 0.875rem 1rem;
    position: fixed;
    right: 0;
    z-index: var(--z-notice);
}

.consent-bar[hidden] { display: none !important; }
/* The same question, asked again on the cookies page so an answer can be taken
   back. Hidden until the client has read the stored answer. */
.consent-choice { border-top: 1px solid var(--border-color); margin-top: 14px; padding-top: 0.875rem; }
.consent-choice[hidden] { display: none !important; }
.consent-choice-state { color: var(--text-primary); font: 600 .84rem var(--font-display); margin: 0; }
.consent-bar-text { color: var(--text-secondary); font-size: .82rem; line-height: 1.4; margin: 0; }
.consent-bar a { color: var(--accent-primary); }
.consent-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 12px; }
.consent-actions .btn-premium { flex: 1 1 auto; width: auto; }

@media (min-width: 560px) {
    .consent-bar { border: 1px solid var(--border-color); border-radius: var(--radius-md); left: 16px; right: 16px; }
}

.info-subheading { color: var(--text-primary); font: 700 .92rem var(--font-display); margin: 16px 0 6px; }

/* List Selector Pills */
.list-pills {
    display: flex;
    gap: 0.5rem;
    margin: 20px 0;
    overflow-x: auto;
    padding-bottom: 0.5rem;
}

/* The row of lists scrolls sideways when it does not fit, and the browser's
   default bar is a white slab across a dark page. Same thin bar, page colours. */
.list-pills { scrollbar-color: var(--border-highlight) transparent; scrollbar-width: thin; }
.list-pills::-webkit-scrollbar { height: 6px; }
.list-pills::-webkit-scrollbar-track { background: rgba(var(--bg-base-rgb), .6); border-radius: 3px; }
.list-pills::-webkit-scrollbar-thumb { background: var(--border-highlight); border-radius: 3px; }
.list-pills::-webkit-scrollbar-thumb:hover { background: var(--accent-primary); }

.list-pill {
    padding: 0.5rem 1rem;
    border-radius: 20px;
    font-size: 0.85rem;
    font-family: var(--font-display);
    font-weight: 600;
    text-decoration: none;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    background-color: var(--bg-surface);
    color: var(--text-secondary);
    border: 1px solid var(--border-color);
    transition: var(--transition-premium);
    white-space: nowrap;
}

.list-pill:hover {
    color: var(--text-primary);
    border-color: var(--border-highlight);
}

.list-pill.active {
    color: var(--text-primary);
    background-color: var(--bg-card);
    border-color: var(--accent-primary);
}

.list-pill-dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
}

/* Cards & Layout */
.card-premium {
    background-color: var(--bg-surface);
    /*border: 1px solid var(--border-color);*/
    border-radius: var(--radius-md);
    padding: 0.75rem;
    margin-bottom: 10px;
    box-shadow: var(--shadow-premium);
    transition: var(--transition-premium);
}

/* Hover belongs to a pointer that can hover. On iOS the first tap on an
   element with a hover style is spent producing that hover and the click only
   lands on the second tap, which is why an admin had to tap a ring row twice to
   open the time picker. Touch never enters the hover state now, so the first
   tap is the click. */
@media (hover: hover) {
    .card-premium:hover {
        border-color: var(--border-highlight);
        transform: translateY(-2px);
    }
}

/* Settings subpages */
.settings-group-title:first-of-type { margin-top: 8px; }
/* Who is signed in, and the way out: the header's old account panel, given a
   line of its own at the top of Settings. */
.settings-account { align-items: center; background: var(--bg-surface); border: 1px solid var(--border-color); border-radius: var(--radius-md); display: flex; gap: 1rem; justify-content: space-between; margin-bottom: 0.5rem; padding: 0.875rem 1rem; }
.settings-account-who { display: flex; flex-direction: column; gap: 0.125rem; min-width: 0; }
.settings-account-who strong { color: var(--text-primary); font: 700 1rem var(--font-display); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.settings-account-who small { color: var(--text-muted); font-size: .7rem; letter-spacing: .05em; text-transform: uppercase; }
.settings-account .btn-premium { flex: 0 0 auto; padding: 0.5rem 1rem; width: auto; }
.settings-menu { display: grid; gap: 0.625rem; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.settings-menu-item { align-items: center; background: var(--bg-surface); border: 1px solid var(--border-color); border-radius: var(--radius-md); color: var(--text-primary); display: grid; gap: 0.875rem; grid-template-columns: 42px 1fr auto; padding: 0.5rem 0.5rem; text-decoration: none; transition: var(--transition-premium); }
.settings-menu-item:hover { border-color: var(--accent-primary); transform: translateY(-2px); }
.settings-menu-item:focus-visible, .btn-premium:focus-visible, .settings-back:focus-visible { outline: 2px solid var(--accent-primary); outline-offset: 2px; }
.settings-menu-mark { align-items: center; background: rgba(var(--accent-primary-rgb),.12); border: 1px solid rgba(var(--accent-primary-rgb),.25); border-radius: 50%; color: var(--accent-primary); display: flex; flex: 0 0 42px; height: 42px; justify-content: center; width: 42px; }
/* A drawing rather than the initial of the row's English title, which said
   nothing in the other four languages and collided with itself in English. */
.settings-menu-icon { display: block; height: 20px; width: 20px; }
.settings-menu-item strong { display: block; font: 700 .95rem var(--font-display); }
.settings-menu-item small { color: var(--text-muted); display: block; font-size: .75rem; margin-top: 3px; }
.settings-menu-arrow { color: var(--text-muted); font-size: 1.1rem; transition: transform .2s ease; }
.settings-menu-item:hover .settings-menu-arrow { color: var(--accent-primary); transform: translateX(3px); }
/* A way out of anywhere the bottom navigation does not reach. Rendered once, by
   the header, at the top of the container -- it used to be written by hand on
   seventeen pages, at the bottom of most of them, and was missing entirely from
   a dozen others. */
.settings-back { align-items: center; color: var(--text-secondary); display: inline-flex; font: 700 .78rem var(--font-display); gap: 0.25rem; margin: 2px 0 14px; text-decoration: none; }
.settings-back-icon { height: 15px; width: 15px; }
.settings-back:hover { color: var(--accent-primary); }
.settings-intro { color: var(--text-secondary); margin-bottom: 20px; }
.settings-form { display: grid; gap: 1rem; }
.settings-form label { color: var(--text-primary); font-family: var(--font-display); font-weight: 600; }
.settings-form small { color: var(--text-muted); display: block; font-family: var(--font-body); font-size: .76rem; font-weight: 400; }
.settings-form input, .settings-form select { background: var(--bg-base); border: 1px solid var(--border-color); border-radius: var(--radius-sm); color: var(--text-primary); display: block; font: inherit; margin-top: 6px; padding: 0.625rem 0.75rem; width: 100%; }
.settings-form input:focus, .settings-form select:focus { border-color: var(--accent-primary); outline: none; }
.settings-form .btn-premium { justify-self: start; margin-top: 4px; }
.avatar-field { align-items: center; display: grid; gap: 0.875rem; grid-template-columns: 64px 1fr; }
.avatar-preview-wrap { display: block; height: 64px; width: 64px; }
.profile-avatar { background: var(--bg-base); border: 1px solid var(--border-highlight); border-radius: 50%; display: block; height: 64px; object-fit: cover; width: 64px; }
.profile-avatar-placeholder { align-items: center; color: var(--accent-primary); display: flex; font: 800 1.35rem var(--font-display); justify-content: center; }
.avatar-crop-modal { max-width: 420px; }
.avatar-crop-modal .modal-header small { color: var(--text-muted); display: block; font-size: .73rem; margin-top: 3px; }
.avatar-crop-body { align-items: center; display: flex; flex-direction: column; }
.avatar-crop-stage { background: #050812; cursor: grab; height: min(300px, calc(100vw - 80px)); overflow: hidden; position: relative; touch-action: none; user-select: none; width: min(300px, calc(100vw - 80px)); }
.avatar-crop-stage.dragging { cursor: grabbing; }
.avatar-crop-stage > img { max-width: none; pointer-events: none; position: absolute; user-select: none; }
.avatar-crop-shade { border: 2px solid rgba(255,255,255,.9); border-radius: 50%; box-shadow: 0 0 0 999px rgba(var(--bg-base-rgb),.68), inset 0 0 0 1px rgba(var(--bg-base-rgb),.35); inset: 0; margin: 8px; pointer-events: none; position: absolute; }
.avatar-zoom-label { color: var(--text-secondary); font: 700 .75rem var(--font-display); margin-top: 18px; width: 100%; }
.avatar-zoom-label input { accent-color: var(--accent-primary); display: block; margin-top: 8px; width: 100%; }
.avatar-crop-actions { display: flex; gap: 0.5rem; margin-top: 20px; width: 100%; }
.avatar-crop-actions .btn-premium { flex: 1; font-size: .76rem; padding: 0.625rem 0.75rem; }
.email-status { border-radius: 20px; float: right; font: 700 .66rem var(--font-display); padding: 0.1875rem 0.5rem; }
.email-status-verified { background: rgba(var(--color-friends-rgb),.12); color: var(--color-friends); }
.email-status-pending { background: rgba(var(--color-important-rgb),.1); color: var(--color-important); }
.resend-verification { border-top: 1px solid var(--border-color); margin-top: 18px; padding-top: 0.875rem; }
.resend-verification button { background: none; border: 0; color: var(--accent-primary); cursor: pointer; font: 700 .78rem var(--font-display); padding: 0; }
.verified-copy { color: var(--color-friends) !important; }
.pending-copy { color: var(--color-important) !important; }
.auth-primary-link { box-sizing: border-box; display: block; margin-top: 18px; text-align: center; text-decoration: none; }
.settings-card-title { font-family: var(--font-display); font-size: 1.1rem; font-weight: 700; margin-bottom: 16px; }
.settings-data { color: var(--text-secondary); display: grid; gap: 0.5rem 1rem; grid-template-columns: 100px 1fr; }
.settings-data strong { color: var(--text-primary); }
.status-ok, .status-error { border-radius: 20px; display: inline-block; font-size: .78rem; margin-left: 8px; padding: 0.125rem 0.5rem; }
.status-ok { background: rgba(var(--color-friends-rgb),.12); color: var(--color-friends); }
.status-error { background: rgba(var(--color-my-dogs-rgb),.12); color: var(--color-my-dogs); }
.table-status-list { margin-bottom: 20px; }
.table-status-list > div { border-bottom: 1px solid var(--border-color); display: flex; justify-content: space-between; padding: 0.5625rem 0; }
.settings-warning, .settings-success { border-radius: var(--radius-sm); font-size: .85rem; margin-bottom: 16px; padding: 0.75rem; }
.settings-warning { background: rgba(var(--color-important-rgb),.08); color: var(--color-important); }
.settings-success { background: rgba(var(--color-friends-rgb),.08); color: var(--color-friends); }
.debug-mode-form { border-bottom: 1px solid var(--border-color); margin-bottom: 18px; padding-bottom: 1.125rem; }
.debug-mode-switch { align-items: center; cursor: pointer; display: flex; gap: 1rem; justify-content: space-between; }
.debug-mode-switch > span { min-width: 0; }
.debug-mode-switch strong, .debug-mode-switch small { display: block; }
.debug-mode-switch strong { color: var(--text-primary); font: 700 .95rem var(--font-display); }
.debug-mode-switch small { color: var(--text-muted); font-size: .75rem; margin-top: 3px; }
.debug-mode-switch input { height: 1px; opacity: 0; position: absolute; width: 1px; }
.debug-mode-switch i { background: var(--bg-base); border: 1px solid var(--border-highlight); border-radius: 20px; flex: 0 0 auto; height: 26px; position: relative; transition: var(--transition-premium); width: 46px; }
.debug-mode-switch i::after { background: var(--text-muted); border-radius: 50%; content: ""; height: 18px; left: 3px; position: absolute; top: 3px; transition: var(--transition-premium); width: 18px; }
.debug-mode-switch input:checked + i { background: rgba(var(--accent-primary-rgb),.2); border-color: var(--accent-primary); }
.debug-mode-switch input:checked + i::after { background: var(--accent-primary); transform: translateX(20px); }
.debug-mode-switch input:focus-visible + i { outline: 2px solid var(--accent-primary); outline-offset: 2px; }
.debug-clock-status { background: rgba(var(--color-important-rgb),.08); border: 1px solid rgba(var(--color-important-rgb),.22); border-radius: var(--radius-sm); color: var(--color-important); margin-bottom: 18px; padding: 0.875rem; }
.debug-clock-status strong, .debug-clock-status span { display: block; }
.debug-clock-status span { font-size: .82rem; margin-top: 3px; }
.debug-clock-reset { border-top: 1px solid var(--border-color); margin-top: 18px; padding-top: 1.125rem; }
/* Beside the mark, and pinned with it: see .brand above. */
.debug-clock-tag {
    background: rgba(var(--color-important-rgb), 0.2);
    border: 1px solid rgba(var(--color-important-rgb), 0.4);
    color: var(--color-important);
    padding: 3px 6px;
    border-radius: var(--radius-sm);
    font-size: 16px;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    margin-left: 12px;
    transition: background 0.2s;
}
.debug-clock-tag:hover {
    background: rgba(var(--color-important-rgb), 0.3);
}
.benefit-banner { align-items: center; background: linear-gradient(110deg, rgba(var(--accent-primary-rgb),.15), var(--bg-surface)); border: 1px solid rgba(var(--accent-primary-rgb),.35); border-radius: var(--radius-md); display: flex; gap: 1.25rem; justify-content: space-between; margin: 16px 0 24px; padding: 1.25rem; }
.benefit-banner strong { color: var(--text-primary); display: block; font: 700 1.05rem var(--font-display); }
.benefit-banner span { color: var(--text-secondary); display: block; font-size: .82rem; margin-top: 2px; }
.benefit-actions { display: flex; flex: 0 0 auto; gap: 0.5rem; }
.benefit-actions .btn-premium { font-size: .72rem; padding: 0.5625rem 0.75rem; text-decoration: none; width: auto; }
.users-layout { display: grid; gap: 1rem; }
.settings-section-bar { align-items: center; display: flex; justify-content: space-between; margin-bottom: 12px; }
.section-header-group { display: flex; flex-direction: column; gap: 0.2rem; }
.settings-section-bar .section-header { margin: 0; }
.settings-section-bar .btn-premium { font-size: .75rem; padding: 0.5625rem 0.8125rem; width: auto; }
.directory-tools { align-items: center; display: flex; gap: 0.5rem; }
/* Two buttons share the right edge of a section bar, so they shrink to fit. */
.btn-compact { font-size: .7rem !important; padding: 0.4375rem 0.6875rem !important; white-space: nowrap; }
/* Stop stands beside the menu rather than inside it, and is only there at all
   while a run is going. */
.breed-toolbar { display: flex; align-items: center; gap: 0.5rem; }
.breed-toolbar > [hidden] { display: none; }
.directory-count { color: var(--text-muted); font: 700 .72rem var(--font-display); text-transform: uppercase; }
.judges-directory { display: grid; gap: 0.75rem; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.judge-card { background: var(--bg-surface); border: 1px solid var(--border-color); border-radius: var(--radius-md); box-shadow: var(--shadow-premium); overflow: hidden; }
.judge-card-heading { align-items: center; display: flex; gap: 0.75rem; padding: 1rem; }
.judge-monogram { align-items: center; background: rgba(var(--accent-primary-rgb),.12); border: 1px solid rgba(var(--accent-primary-rgb),.25); border-radius: 50%; color: var(--accent-primary); display: flex; flex: 0 0 auto; font: 800 .9rem var(--font-display); height: 42px; justify-content: center; width: 42px; }
.judge-photo { border: 1px solid var(--border-color); border-radius: 50%; flex: 0 0 auto; height: 42px; object-fit: cover; width: 42px; }
.judge-card-identity { flex: 1 1 auto; min-width: 0; }
.judge-card h2 { color: var(--text-primary); font: 700 .95rem var(--font-display); margin: 0; }
.judge-name-link { color: inherit; text-decoration: none; }
.judge-name-link:hover { color: var(--accent-primary); }
.judge-name-link:focus-visible { border-radius: 3px; outline: 2px solid var(--accent-primary); outline-offset: 3px; }
.judge-card-heading p { color: var(--text-muted); font-size: .73rem; margin-top: 3px; }
.judge-card-controls { align-items: center; display: flex; gap: 0.375rem; opacity: 0; pointer-events: none; transform: translateX(5px); transition: opacity .18s ease, transform .18s ease; }
.judge-card:hover .judge-card-controls, .judge-card:focus-within .judge-card-controls { opacity: 1; pointer-events: auto; transform: translateX(0); }
.judge-card-controls form { margin: 0; }
.judge-card-controls .btn-premium { font-size: .68rem; padding: 0.4375rem 0.5rem; text-decoration: none; width: auto; }
.judge-show-list { border-top: 1px solid var(--border-color); display: grid; }
.judge-show-list > p { color: var(--text-muted); font-size: .75rem; padding: 0.75rem 1rem; }
.judge-show-list a { align-items: center; color: var(--text-secondary); display: flex; font-size: .78rem; gap: 0.75rem; justify-content: space-between; padding: 0.625rem 1rem; text-decoration: none; }
.judge-show-list a + a { border-top: 1px solid rgba(var(--border-color-rgb),.7); }
.judge-show-list a:hover { background: var(--bg-card); color: var(--text-primary); }
.judge-show-list strong { font-weight: 600; }
.judge-show-list span { color: var(--text-muted); flex: 0 0 auto; font-size: .7rem; }
.judge-profile-heading { align-items: center; display: flex; gap: 0.875rem; margin-bottom: 18px; }
.judge-profile-heading .judge-monogram { height: 52px; width: 52px; }
.judge-profile-heading .judge-photo { height: 52px; width: 52px; }
.judge-profile-heading .section-header { margin: 0; }
.judge-profile-heading p { color: var(--text-muted); font-size: .78rem; margin-top: 4px; }
.judge-edit-layout { align-items: start; display: grid; gap: 1rem; grid-template-columns: minmax(0, 1fr) minmax(280px, .85fr); }
.judge-edit-layout .card-premium { margin-bottom: 0; }
.judge-history-card .judge-show-list { margin: 0 -20px -20px; }
.users-card { overflow: hidden; }
.users-table-wrap { overflow-x: auto; }
.users-table { border-collapse: collapse; min-width: 520px; width: 100%; }
.users-table th, .users-table td { border-bottom: 1px solid var(--border-color); padding: 0.6875rem 0.5rem; text-align: left; }
.users-table th { color: var(--text-muted); font: 700 .7rem var(--font-display); text-transform: uppercase; }
.users-table td { color: var(--text-secondary); font-size: .84rem; }
.users-table td strong { color: var(--text-primary); display: block; }
.users-table td small { color: var(--accent-primary); display: block; }
.user-role { border-radius: 20px; display: inline-block; font: 700 .7rem var(--font-display); padding: 0.1875rem 0.5rem; text-transform: uppercase; }
.user-role-admin { background: rgba(var(--accent-primary-rgb),.12); color: var(--accent-primary); }
.user-role-user { background: rgba(var(--color-orders-rgb),.12); color: var(--color-orders); }
.user-actions, .form-actions { align-items: center; display: flex; gap: 0.4375rem; }
.user-actions form { margin: 0; }
/* A flex <td> leaves the table box model, so its border stops tracking the row
   and draws a stub beside the buttons. Keep action cells as real cells. */
.users-table td.user-actions { display: table-cell; vertical-align: middle; white-space: nowrap; }
.users-table td.user-actions > * { display: inline-block; margin: 0; vertical-align: middle; }
.users-table td.user-actions > * + * { margin-left: 7px; }
/* The rule above wins over .btn-premium's flex centring, which left the icon
   of an icon-only control pinned to the top left of its 34px box. Icon buttons
   stay inline in the cell and keep centring their glyph. */
.users-table td.user-actions > .action-icon-button { align-items: center; display: inline-flex; justify-content: center; }

/* Exposition catalogue --------------------------------------------------- */
/* Season sources: one card per calendar year. */
.season-source-grid { display: flex; flex-direction: column; gap: 1rem; margin-bottom: 28px; }
.season-source { display: flex; flex-direction: column; gap: 0.75rem; margin: 0; }
.season-source:hover { transform: none; }
.season-source-active { box-shadow: var(--shadow-premium), inset 0 0 0 1px rgba(var(--accent-primary-rgb),.35); }
.season-source-head { align-items: baseline; display: flex; gap: 0.625rem; justify-content: space-between; }
.season-source-head strong { color: var(--text-primary); font: 700 1rem var(--font-display); }
.season-source-year { background: rgba(var(--accent-primary-rgb),.12); border-radius: 20px; color: var(--accent-primary); font: 700 .68rem var(--font-display); padding: 0.1875rem 0.5625rem; }
.season-source-url { color: var(--text-muted); font-size: .76rem; overflow: hidden; text-decoration: none; text-overflow: ellipsis; white-space: nowrap; }
.season-source-url:hover { color: var(--accent-primary); }
.season-source-stats { border-top: 1px solid var(--border-color); display: flex; gap: 1.625rem; margin: 0; padding-top: 0.75rem; }
.season-source-stats dt { color: var(--text-muted); font: 700 .64rem var(--font-display); letter-spacing: .04em; text-transform: uppercase; }
.season-source-stats dd { color: var(--text-primary); font-size: .84rem; margin: 3px 0 0; }
.season-source-stats dd a { color: var(--accent-primary); text-decoration: none; }
.season-source-stats dd a:hover { text-decoration: underline; }
.season-source-result { color: var(--text-secondary); font-size: .76rem; margin: -4px 0 0; }
.season-source-actions { align-items: center; display: flex; gap: 0.5rem; margin-top: auto; }
.season-source-actions form { margin: 0; }
.season-source-actions .btn-premium { font-size: .74rem; padding: 0.5625rem 1rem; white-space: nowrap; width: auto; }

/* The narrated import. Hidden until a run starts, then a headline the reader
   watches and a log they can scroll back through — capped in height so a
   thirty-line run does not push the rest of the season grid off the screen. */
.season-import-run { border-top: 1px solid var(--border-color); display: flex; flex-direction: column; gap: 0.5rem; margin-top: 12px; padding-top: 0.75rem; }
.season-import-status { font-size: .78rem; line-height: 1.45; }
.season-import-status-running { color: var(--text-secondary); }
.season-import-status-ok { color: var(--accent-primary); }
.season-import-status-error { color: var(--color-my-dogs); }
.season-import-status a { color: var(--accent-primary); margin-left: 4px; }
.season-import-log { display: flex; flex-direction: column; gap: 0.25rem; list-style: none; margin: 0; max-height: 220px; overflow-y: auto; padding: 0; }
.season-import-line { color: var(--text-secondary); display: flex; font-size: .74rem; gap: 0.5rem; line-height: 1.4; }
.season-import-stage { color: var(--text-muted); flex: 0 0 52px; font: 700 .62rem var(--font-display); letter-spacing: .04em; padding-top: 0.125rem; text-transform: uppercase; }
.season-import-error span:last-child { color: var(--color-my-dogs); }
.season-import-warning span:last-child { color: var(--color-important); }
.season-import-done span:last-child { color: var(--accent-primary); }

/* Year picker: the year view of a date field, on its own. */
.year-picker { position: relative; }
/* The panel sits in the flow rather than floating over the form: its host modal
   clips to its rounded corners, so an absolutely positioned grid lost its last
   row. Opening it grows the dialog instead, and the body scrolls if that runs
   the modal past the viewport. */
.year-picker-panel { background: var(--bg-base); border: 1px solid var(--border-highlight); border-radius: var(--radius-md); margin-top: 6px; padding: 0.75rem; }
.year-picker-head { align-items: center; display: flex; justify-content: space-between; margin-bottom: 10px; }
.year-picker-range { color: var(--text-primary); font: 700 .84rem var(--font-display); }
.year-picker-nav { background: none; border: none; border-radius: var(--radius-sm); color: var(--text-secondary); cursor: pointer; font-size: 1.1rem; line-height: 1; padding: 0.25rem 0.625rem; }
.year-picker-nav:hover { background: var(--bg-overlay); color: var(--text-primary); }
.year-picker-grid { display: grid; gap: 0.375rem; grid-template-columns: repeat(3, 1fr); }
.year-picker-year { background: var(--bg-base); border: 1px solid transparent; border-radius: var(--radius-sm); color: var(--text-primary); cursor: pointer; font: 600 .84rem var(--font-display); padding: 0.5625rem 0; transition: var(--transition-premium); }
.year-picker-year:hover { background: var(--bg-overlay); }
.year-picker-year-now { border-color: rgba(var(--accent-primary-rgb),.45); }
.year-picker-year-active { background: var(--accent-primary); border-color: var(--accent-primary); color: #fff; }

/* Season tabs: the imported shows below belong to whichever year is active. */
.season-tabs { display: flex; flex-wrap: wrap; gap: 0.25rem; margin-bottom: 16px; overflow-x: auto; }
.season-tab { align-items: center; border-bottom: 2px solid transparent; color: var(--text-secondary); display: inline-flex; font: 600 .86rem var(--font-display); gap: 0.4375rem; padding: 0.5625rem 0.875rem; text-decoration: none; transition: var(--transition-premium); white-space: nowrap; }
.season-tab:hover { background: var(--bg-overlay); color: var(--text-primary); }
.season-tab small { background: var(--bg-overlay); border-radius: 20px; color: var(--text-muted); font: 700 .68rem var(--font-display); padding: 0.125rem 0.4375rem; }
.season-tab-active { border-bottom-color: var(--accent-primary); color: var(--accent-primary); }
.season-tab-active small { background: rgba(var(--accent-primary-rgb),.14); color: var(--accent-primary); }

/* Imported shows: a card per show, its expositions listed inside. */
.expo-show-grid {
    display: grid;
    gap: 0.875rem;
}

.expo-show {
    margin: 0;
    padding: 0;
    container-type: inline-size;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    /* A #show-<id> link from the watch mail lands on the card, not under the
       fixed header and the card's own sticky head. */
    scroll-margin-top: calc(var(--header-height) + 1rem);
}

.expo-show:hover {
    transform: none;
}

/* The show name stays put while its expositions scroll, but it parks under the
   page header instead of at the viewport top -- and keeps --z-content, so a
   card can never paint over the header the way it did before. */
.expo-show-head {
    align-items: baseline;
    background: var(--bg-card);
    border-bottom: 1px solid var(--border-color);
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem 0.75rem;
    justify-content: space-between;
    padding: 0.3125rem 0.9375rem 0.625rem 0.9375rem;
    position: sticky;
    top: var(--header-height);
    z-index: var(--z-content);
    border-top-left-radius: var(--radius-md);
    border-top-right-radius: var(--radius-md);
    box-sizing: content-box;
}


.expo-show-name {
    color: var(--text-primary);
    font: 700 .98rem var(--font-display);
    text-decoration: none;
}

.expo-show-name:hover {
    color: var(--accent-primary);
}

.expo-show-name:focus-visible {
    border-radius: 3px;
    outline: 2px solid var(--accent-primary);
    outline-offset: 3px;
}

/* The square-with-an-arrow beside the name: the exposition on cpc.pt. Sized to
   the check button next to it so the two read as one pair of controls. */
.expo-show-source {
    align-items: center;
    color: var(--text-muted);
    display: inline-flex;
    flex: 0 0 auto;
    justify-content: center;
    height: 26px;
    width: 26px;
    border-radius: 7px;
    text-decoration: none;
}

.expo-show-source .action-icon {
    height: 15px;
    width: 15px;
}

.expo-show-source:hover {
    background: var(--tint-subtle);
    color: var(--accent-primary);
}

.expo-show-source:focus-visible {
    outline: 2px solid var(--accent-primary);
    outline-offset: 2px;
}

.expo-show-name-orphan {
    color: var(--text-muted);
    font-style: italic;
    font-weight: 600;
}

/* The show's venue, once, on its own line at the foot of the head. The pin is
   decoration, hidden from screen readers, so it carries no spacing of its own. */
.expo-show-place {
    color: var(--text-muted);
    flex: 1 1 100%;
    font-size: .74rem;
}

.expo-show-place-pin {
    display: inline-block;
    height: 13px;
    margin-right: 4px;
    vertical-align: -2px;
    width: 13px;
}

.expo-show-meta {
    align-items: center;
    color: var(--text-muted);
    display: flex;
    flex-wrap: wrap;
    font-size: .76rem;
    gap: 0.5rem;
}

/* Catalogued and scheduled are two different imports. These say, at a glance,
   which shows still have no ring schedule behind them. */
.expo-schedule-pill { align-items: baseline; border: 1px solid transparent; border-radius: 999px; display: inline-flex; font: 700 .66rem var(--font-display); gap: 0.375rem; letter-spacing: .03em; padding: 0.1875rem 0.5625rem; white-space: nowrap; }
.expo-schedule-pill small { font-weight: 600; opacity: .75; }
.expo-schedule-complete { background: rgba(var(--color-friends-rgb), .12); border-color: rgba(var(--color-friends-rgb), .35); color: var(--color-friends); }
.expo-schedule-partial { background: rgba(var(--color-important-rgb), .12); border-color: rgba(var(--color-important-rgb), .35); color: var(--color-important); }
.expo-schedule-missing { background: rgba(var(--color-my-dogs-rgb), .1); border-color: rgba(var(--color-my-dogs-rgb), .3); color: var(--color-my-dogs); }
.expo-schedule-stale { background: rgba(var(--accent-primary-rgb), .12); border-color: rgba(var(--accent-primary-rgb), .4); color: var(--accent-primary); }
.schedule-legend { display: flex; flex-wrap: wrap; gap: 0.375rem; }

/* The same pills are the quick filter, so they have to look pressable. While a
   filter is on, the states left out fade back instead of disappearing — the
   counts are still the point of the row. */
.expo-schedule-filter { appearance: none; cursor: pointer; transition: var(--transition-premium); }
.expo-schedule-filter:hover { filter: brightness(1.25); }
.expo-schedule-filter[aria-pressed="true"] { border-color: currentColor; box-shadow: 0 0 0 2px rgba(var(--accent-primary-rgb), .28); }
.schedule-legend[data-filter-active] .expo-schedule-filter[aria-pressed="false"] { opacity: .4; }

/* One import per show day, run straight from the row. */
.expo-days { display: grid; gap: 0.375rem; grid-column: 1 / -1; margin-top: 4px; }
.expo-day { align-items: center; background: rgba(var(--bg-overlay-rgb), .35); border: 1px solid var(--border-color); border-left: 3px solid var(--border-highlight); border-radius: 8px; display: flex; flex-wrap: wrap; gap: 0.625rem; padding: 0.4375rem 0.625rem; }
.expo-day-missing { border-left-color: rgba(var(--color-my-dogs-rgb), .5); }
.expo-day-imported { border-left-color: rgba(var(--color-friends-rgb), .5); }
.expo-day-stale { border-left-color: var(--accent-primary); }
.expo-day-date { color: var(--text-primary); font: 700 .74rem var(--font-display); min-width: 74px; }
.expo-day-state { color: var(--text-secondary); flex: 1 1 auto; font-size: .72rem; min-width: 0; }
.expo-day-state small { color: var(--text-muted); }
.expo-day-missing .expo-day-state { color: var(--color-my-dogs); }
.expo-day-imported .expo-day-state { color: var(--color-friends); }
.expo-day-stale .expo-day-state { color: var(--accent-primary); }
.expo-day-blocked { color: var(--text-muted); font-size: .7rem; font-style: italic; }
.expo-day .expo-day-import { align-items: center; display: inline-flex; flex: 0 0 auto; gap: 0.375rem; width: auto; min-height: 0; padding: 0.3125rem 0.625rem; border-radius: 7px; font: 700 .68rem var(--font-display); }
.expo-day .expo-day-import .action-icon { height: 14px; width: 14px; }
.expo-day .expo-day-import:disabled { cursor: progress; opacity: .6; }
.expo-day-message { flex: 1 1 100%; font-size: .7rem; color: var(--text-secondary); margin: 2px 0 0; }
.expo-day-message-error { color: var(--color-my-dogs); }

/* The run's own account of itself, under the day it belongs to. Capped and
   scrollable: a day that follows three Horários pages writes a dozen lines, and
   the list of days must stay readable while one of them is running. */
.expo-day-log { flex: 1 1 100%; display: flex; flex-direction: column; gap: 0.1875rem; list-style: none; margin: 6px 0 0; max-height: 180px; overflow-y: auto; padding: 0; }
.expo-day-log-line { color: var(--text-secondary); display: flex; font-size: .7rem; gap: 0.5rem; line-height: 1.4; }
.expo-day-log-stage { color: var(--text-muted); flex: 0 0 46px; font: 700 .58rem var(--font-display); letter-spacing: .04em; padding-top: 0.0625rem; text-transform: uppercase; }
.expo-day-log-failed span:last-child { color: var(--color-my-dogs); }
.expo-day-log-error span:last-child { color: var(--color-my-dogs); }
.expo-day-log-done span:last-child { color: var(--accent-primary); }
/* What the importer found, under the day it was importing: the missing pieces,
   the page checks behind the verdict, and root's technical detail. */
.expo-day-diagnostics { flex: 1 1 100%; margin: 4px 0 0; }
.expo-day-diagnostics > * + * { margin-top: 4px; }
.expo-show-head .expo-show-check { align-items: center; display: inline-flex; flex: 0 0 auto; gap: 0.375rem; width: auto; min-height: 0; padding: 0.3125rem 0.5625rem; border-radius: 7px; font: 700 .68rem var(--font-display); letter-spacing: .04em; }
.expo-show-head .expo-show-check .action-icon { height: 15px; width: 15px; }

/* Everything that walks the whole list lives behind one trigger, so the
   section bar keeps one button no matter how many bulk runs there are. */
.bulk-actions { position: relative; }
.bulk-actions-trigger { align-items: center; display: inline-flex; gap: 0.375rem; justify-content: center; width: auto; }
.bulk-actions-menu { background: var(--bg-card); border: 1px solid var(--border-color); border-radius: 12px; box-shadow: 0 8px 32px rgba(0,0,0,.4); display: flex; flex-direction: column; max-width: min(320px, 84vw); min-width: 240px; overflow: hidden; position: absolute; right: 0; top: calc(100% + 6px); z-index: var(--z-popover); }
.bulk-actions-menu[hidden] { display: none; }
/* The season importer's menu hangs off its own trigger, which already sits at
   the right of a wide bar. The lists page's trigger sits at the left, and a menu
   anchored to a narrow trigger has nowhere to go: right:0 pushes it off the left
   of the screen, left:0 off the right. So it is anchored to the action bar
   instead, which spans the content — the panel lines up with the right edge of
   the page whatever the button under it is called or how wide it is. */
/* An open list has one control and it sits at the right, where a thumb holding
   the phone already is — the list itself is read down the left. The menu hangs
   off the bar rather than off the button, because the button is narrow: right:0
   against it would push the panel off the left of the screen. Anchored to the
   bar, which spans the content, both the button and the panel line up with the
   right edge of the page. */
.page-action-bar-end { justify-content: flex-end; }
.page-action-bar { position: relative; }
.page-action-bar .bulk-actions { position: static; }
.page-action-bar .bulk-actions-menu { left: auto; right: 0; }
.bulk-actions-trigger .action-icon { height: 15px; width: 15px; }
.bulk-actions-menu .bulk-menu-item { display: grid; gap: 0.125rem; }
.bulk-actions-menu .bulk-menu-item small { color: var(--text-muted); font-size: .72rem; font-weight: 500; }
.bulk-actions-menu .bulk-menu-item + .bulk-menu-item { border-top: 1px solid rgba(var(--border-color-rgb),.7); }

/* A left rail repeats the state on the card itself, so the list can be read by
   shape instead of by reading every pill. */
.expo-show-complete { border-left: 3px solid rgba(var(--color-friends-rgb), .45); }
.expo-show-partial { border-left: 3px solid rgba(var(--color-important-rgb), .55); }
.expo-show-missing { border-left: 3px solid rgba(var(--color-my-dogs-rgb), .55); }

/* nowrap so the button always stays on the show name's line; a long name
   wraps its own text instead of pushing the button down. */
.expo-show-title { align-items: center; display: flex; flex-wrap: wrap; gap: 0.625rem; min-width: 0; }
/* The check's verdict takes the whole next line rather than squeezing the name:
   its evidence is several lines long once opened. */
.expo-show-title > .expo-check-result { flex: 1 1 100%; }
.expo-show-title .expo-show-name { min-width: 0; }
/* Icon-only by default; the label appears when the card is wide enough.
   Scoped under .expo-show-head to outrank the later .btn-premium base rule,
   which is full width by default. */
.expo-show-head .expo-show-import { align-items: center; display: inline-flex; flex: 0 0 auto; gap: 0.375rem; width: auto; min-height: 0; padding: 0.3125rem 0.5625rem; border-radius: 7px; font: 700 .68rem var(--font-display); letter-spacing: .04em; }
.expo-show-head .expo-show-import .action-icon { height: 15px; width: 15px; }
.expo-show-head .expo-show-import-label { display: none; }
@container (min-width: 440px) { .expo-show-head .expo-show-import-label { display: inline; } }

.expo-list { display: grid; list-style: none; margin: 0; padding: 0; }
.expo-item { align-items: center; display: grid; gap: 0.375rem 1rem; grid-template-columns: 74px minmax(0, 1fr) auto auto; padding: 0.75rem 1.25rem; }
.expo-item + .expo-item { border-top: 1px solid rgba(var(--border-color-rgb),.7); }
.expo-date { color: var(--accent-primary); font: 700 .76rem var(--font-display); }
.expo-body { display: grid; gap: 0.125rem; min-width: 0; }
.expo-name { color: var(--text-primary); font-size: .86rem; }
.expo-place { color: var(--text-muted); font-size: .74rem; }
.expo-tags { display: flex; flex-wrap: wrap; gap: 0.3125rem; justify-content: flex-end; }
.expo-tag { background: rgba(var(--accent-primary-rgb),.1); border-radius: 20px; color: var(--accent-primary); font: 700 .64rem var(--font-display); padding: 0.1875rem 0.5625rem; white-space: nowrap; }
.expo-tag-open { background: rgba(var(--color-friends-rgb),.12); color: var(--color-friends); }
.expo-tag-muted { background: rgba(var(--text-muted-rgb),.14); color: var(--text-muted); }
.expo-tag-alert { background: rgba(var(--color-my-dogs-rgb),.14); color: var(--color-my-dogs); }
.expo-actions { margin: 0; }
.expo-item-removed .expo-name, .expo-item-removed .expo-place, .expo-item-removed .expo-date { opacity: .55; text-decoration: line-through; }

.import-warning-list { color: var(--text-secondary); font-size: .82rem; margin: 0; padding-left: 1.125rem; }
.import-warning-list li + li { margin-top: 6px; }

/* Single-show editor: two-column form, full-width fields where it helps. */
.show-edit-form { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.show-edit-form .field-wide { grid-column: 1 / -1; }
.expo-edit-card { padding-top: 1rem; }
.expo-edit-card:hover { transform: none; }
.expo-edit-card-removed { opacity: .72; }
.expo-edit-head { align-items: center; border-bottom: 1px solid var(--border-color); display: flex; flex-wrap: wrap; gap: 0.375rem 0.75rem; margin-bottom: 18px; padding-bottom: 0.875rem; }
.expo-edit-head strong { color: var(--text-primary); font: 700 .92rem var(--font-display); margin-right: auto; }
.expo-edit-tools { align-items: center; border-top: 1px solid var(--border-color); display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 18px; padding-top: 0.875rem; }
.expo-edit-tools form { align-items: center; display: flex; gap: 0.5rem; margin: 0; }
.expo-edit-tools .btn-premium { font-size: .72rem; padding: 0.5rem 0.75rem; width: auto; }
.expo-move-form { margin-left: auto !important; }
.expo-move-form select { background: var(--bg-base); border: 1px solid var(--border-color); border-radius: var(--radius-sm); color: var(--text-primary); font: inherit; font-size: .78rem; max-width: 210px; padding: 0.4375rem 0.625rem; }
.expo-lock-note { align-items: center; background: rgba(var(--accent-primary-rgb),.07); border-radius: var(--radius-sm); color: var(--text-secondary); display: flex; flex-wrap: wrap; gap: 0.625rem; font-size: .8rem; justify-content: space-between; margin-top: 18px; padding: 0.75rem 0.875rem; }
.expo-lock-note form { margin: 0; }
.expo-lock-note .btn-premium { font-size: .72rem; padding: 0.4375rem 0.6875rem; width: auto; }
.expo-danger-card { box-shadow: var(--shadow-premium), inset 0 0 0 1px rgba(var(--color-my-dogs-rgb),.25); }
.expo-danger-card:hover { transform: none; }
.expo-danger-card .settings-intro { margin-bottom: 14px; }
.expo-danger-card .btn-premium { width: auto; }

@media (max-width: 640px) {
    .show-edit-form { grid-template-columns: minmax(0, 1fr); }
    /* Keep Move and the delete button sharing one line instead of stacking. */
    .expo-move-form { flex: 1 1 160px; margin-left: 0 !important; }
    .expo-move-form select { flex: 1; max-width: none; min-width: 0; }
}

@media (max-width: 720px) {
    .expo-item { grid-template-columns: minmax(0, 1fr) auto; }
    .expo-date { grid-column: 1; }
    .expo-body { grid-column: 1 / -1; }
    .expo-tags { grid-column: 1; justify-content: flex-start; }
    .expo-actions { grid-column: 2; grid-row: 1; justify-self: end; }
}
.user-actions .btn-premium, .form-actions .btn-premium { font-size: .7rem; padding: 0.4375rem 0.5625rem; text-decoration: none; width: auto; }
.btn-danger { background: rgba(var(--color-my-dogs-rgb),.12); color: var(--color-my-dogs); }
.btn-danger:hover { background: rgba(var(--color-my-dogs-rgb),.22); }
.action-icon-button { flex: 0 0 34px; height: 34px; padding: 0 !important; width: 34px !important; }
.action-icon { display: block; height: 17px; width: 17px; }
.auth-page { align-items: center; display: flex; justify-content: center; min-height: 100vh; padding: 1.5rem; }
.auth-card { background: var(--bg-surface); border: 1px solid var(--border-color); border-radius: var(--radius-lg); box-shadow: var(--shadow-premium); max-width: 420px; padding: 2rem; width: 100%; }
.auth-card h1 { font: 800 1.8rem var(--font-display); margin-top: 24px; }
.auth-card > p { color: var(--text-secondary); margin: 4px 0 22px; }
.auth-card .auth-switch { border-top: 1px solid var(--border-color); font-size: .8rem; margin: 22px 0 0; padding-top: 1.125rem; text-align: center; }
.auth-switch a { color: var(--accent-primary); font-weight: 700; text-decoration: none; }
.database-actions { display: flex; flex-wrap: wrap; gap: 0.75rem; }
.database-actions p { color: var(--text-muted); font-size: .75rem; margin-top: 5px; max-width: 220px; }
.test-dashboard { background: var(--bg-surface); border: 1px solid var(--border-color); border-radius: var(--radius-md); box-shadow: var(--shadow-premium); overflow: hidden; }
.test-dashboard-summary { align-items: center; background: linear-gradient(110deg, var(--bg-card), var(--bg-surface)); border-bottom: 1px solid var(--border-color); display: flex; gap: 1rem; justify-content: space-between; padding: 1.125rem 1.25rem; }
.test-dashboard-summary strong { display: block; font: 700 1.05rem var(--font-display); }
.test-dashboard-summary span { color: var(--text-muted); font-size: .8rem; }
.test-dashboard-actions { display: flex; gap: 0.5rem; }
.test-dashboard-actions .btn-premium { font-size: .76rem; padding: 0.5rem 0.6875rem; }
.test-command { align-items: flex-end; color: var(--text-secondary); display: flex; flex-wrap: wrap; font-size: .8rem; gap: 0.5rem; padding: 0.875rem 1.25rem 0.25rem; }
.test-command span { color: var(--text-muted); display: block; font-size: .7rem; margin-bottom: 4px; text-transform: uppercase; }
/* The label keeps its own line above the command; the tallies sit off to the right. */
.test-command > span:first-child { flex-basis: 100%; margin-bottom: 0; }
.test-command code { background: var(--bg-base); border: 1px solid var(--border-color); border-radius: 5px; color: var(--text-primary); display: inline-block; padding: 0.3125rem 0.5rem; }

/* Tally and filter in one control: the number says how many, pressing it shows which. */
.test-command .test-filters { display: inline-flex; gap: 0.375rem; margin-bottom: 0; margin-left: auto; }
.test-filter { background: var(--bg-base); border: 1px solid var(--border-color); border-radius: 5px; color: var(--text-muted); cursor: pointer; font: 700 .68rem var(--font-display); letter-spacing: .04em; padding: 0.3125rem 0.5625rem; }
.test-filter span { color: var(--text-primary); display: inline; font-size: .78rem; margin: 0 0 0 5px; text-transform: none; }
.test-filter:hover { border-color: var(--text-muted); }
.test-filter-passed[aria-pressed="true"] { background: rgba(var(--color-friends-rgb),.16); border-color: var(--color-friends); color: var(--color-friends); }
.test-filter-skipped[aria-pressed="true"] { background: rgba(var(--color-important-rgb),.16); border-color: var(--color-important); color: var(--color-important); }
.test-filter-failed[aria-pressed="true"] { background: rgba(var(--color-my-dogs-rgb),.16); border-color: var(--color-my-dogs); color: var(--color-my-dogs); }
.test-filter[aria-pressed="true"] span { color: inherit; }
.test-table-wrap { overflow-x: auto; padding: 0.875rem 1.25rem 1.25rem; }
.test-table { border-collapse: collapse; min-width: 620px; width: 100%; }
.test-table th { border-bottom: 1px solid var(--border-color); color: var(--text-muted); font: 700 .7rem var(--font-display); letter-spacing: .05em; padding: 0.5625rem 0.5rem; text-align: left; text-transform: uppercase; }
.test-table td { border-bottom: 1px solid rgba(var(--border-color-rgb),.7); color: var(--text-secondary); font-size: .82rem; padding: 0.8125rem 0.5rem; vertical-align: top; }
.test-table tr:last-child td { border-bottom: 0; }
.test-table strong { color: var(--text-primary); display: block; font-family: var(--font-display); }
.test-table small { color: var(--text-muted); display: block; font: .73rem monospace; margin-top: 2px; }
.test-table input { accent-color: var(--accent-primary); cursor: pointer; }
.test-status { font-family: var(--font-display); font-weight: 700; }
.test-status.passed { color: var(--color-friends); }
.test-status.failed { color: var(--color-my-dogs); }
.test-status.skipped { color: var(--text-muted); }
/* The row currently executing, while the run walks the table one test at a time. */
.test-status.running { color: var(--color-important); }
.test-table details { color: var(--text-primary); cursor: pointer; }
.test-table summary { font-size: .78rem; }
.test-table pre { color: var(--text-secondary); font: .72rem/1.4 monospace; margin-top: 8px; max-width: 300px; white-space: pre-wrap; }
@media (max-width: 560px) { .test-dashboard-summary { align-items: stretch; flex-direction: column; } .test-dashboard-actions .btn-premium { flex: 1; } }
@media (max-width: 620px) { .settings-menu { grid-template-columns: 1fr; } }
@media (max-width: 700px) { .judges-directory { grid-template-columns: 1fr; } }
@media (max-width: 760px) { .judge-edit-layout { grid-template-columns: 1fr; } }
@media (hover: none), (pointer: coarse) { .judge-card-controls { opacity: 1; pointer-events: auto; transform: none; } }
@media (max-width: 520px) { .settings-section-bar, .directory-tools { align-items: stretch; flex-direction: column; } .judge-card-heading { align-items: flex-start; flex-wrap: wrap; } .judge-card-controls { margin-left: 54px; } }
/* The tools row stacks its own children on a narrow screen, and a stretched
   column makes every button full width. The buttons here are short labels next
   to a count, so the row stays a row that wraps, and they keep their own size. */
@media (max-width: 520px) {
    /* flex-end so that if the row does wrap on a very narrow screen, what
       wrapped stays with the buttons on the right rather than starting a new
       left-aligned line of its own. */
    .directory-tools { align-items: center; flex-direction: row; flex-wrap: wrap; justify-content: flex-end; }
    .directory-tools .btn-premium { flex: 0 0 auto; width: auto; }
    /* The tools row is full width once the section bar stacks, so the count
       holds the left edge and the buttons are pushed to the right together. */
    .directory-tools .directory-count { margin-right: auto; }
}
@media (max-width: 520px) { .header-tools { gap: 0; } .account-avatar { height: 30px; margin: 0 8px; width: 30px; } .account-avatar svg { height: 17px; width: 17px; } }
@media (max-width: 620px) { .benefit-banner { align-items: stretch; flex-direction: column; } .benefit-actions .btn-premium { flex: 1; } }

/* Upcoming Table Layout (Distinctive, minimalist approach) */
.matches-list {
    background-color: var(--bg-surface);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    overflow: hidden;
    margin-bottom: 24px;
    box-shadow: var(--shadow-premium);
}

.match-item {
    display: grid;
    grid-template-columns: 80px 1fr 100px;
    align-items: center;
    padding: 0.3125rem 0.3125rem 0.3125rem 1.25rem;
    border-bottom: 1px solid var(--border-color);
    position: relative;
    transition: var(--transition-premium);
}

.match-item:last-child {
    border-bottom: none;
}

.match-item:hover {
    background-color: var(--tint-subtle);
}

.match-priority-indicator {
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 4px;
    background-color: var(--prio-color, var(--border-color));
}

.match-time-ring {
    display: flex;
    flex-direction: column;
}

.match-time {
    font-family: var(--font-display);
    font-size: 1.15rem;
    font-weight: 700;
    line-height: 1.1;
    color: var(--text-primary);
}

/* The tracker's two switches. Both read as ticks, so the off state is a real
   button rather than an absence — the pair has to look like two independent
   things, not like one choice with two options. */
.tracker-filters { display: flex; gap: 0.5rem; justify-content: flex-end; margin-bottom: 14px; }
.tracker-filter {
    align-items: center;
    background: var(--bg-surface);
    border: 1px solid var(--border-color);
    border-radius: 8px;
    color: var(--text-muted);
    display: inline-flex;
    font: 700 .78rem var(--font-display);
    gap: 0.375rem;
    padding: 0.375rem 0.875rem;
    text-decoration: none;
    transition: var(--transition-premium);
}
.tracker-filter.active {
    background: rgba(var(--accent-primary-rgb), .14);
    border-color: var(--accent-primary);
    color: var(--text-primary);
}
.tracker-filter:not(.active) .favorite-star { color: var(--border-color); }

/* Said beside the Rings heading only while a ring is actually working. */
.live-tag {
    background: var(--color-friends);
    border-radius: 4px;
    color: #06210F;
    display: inline-block;
    font: 800 .62rem var(--font-display);
    letter-spacing: .06em;
    margin-left: 8px;
    padding: 0.1875rem 0.4375rem;
    text-transform: uppercase;
    vertical-align: middle;
}

.breed-lists-check {
    align-items: center;
    cursor: pointer;
    display: flex;
    font-family: var(--font-display);
    font-weight: 600;
    gap: 0.625rem;
}
.breed-lists-check input { height: 18px; width: 18px; accent-color: var(--accent-primary); }

/* The star that marks a favourite. Hollow until it is one, and always in the
   accent colour, so one glance down a list finds them. */
.favorite-form { display: inline; }
.favorite-star {
    background: none;
    border: 0;
    color: var(--border-color);
    cursor: pointer;
    font-size: 1rem;
    line-height: 1;
    padding: 0 0.25rem 0 0;
    transition: var(--transition-premium);
}
.favorite-star.is-favorite { color: var(--accent-primary); }
@media (hover: hover) {
    .favorite-star:hover { color: var(--accent-primary); }
}

/* A breed that sits on one of the viewer's lists carries that list's colour
   after its name, so a ring reads for one's own dogs without being read. */
/* Beside a time that is not the one the timetable printed. */
.time-shifted {
    background: var(--color-my-dogs);
    border-radius: 50%;
    display: inline-block;
    height: 6px;
    margin-left: 0;
    vertical-align: middle;
    width: 6px;
}

.breed-list-dot {
    border-radius: 50%;
    display: inline-block;
    height: 7px;
    margin-left: 2px;
    vertical-align: middle;
    width: 7px;
}

.time-ahead {
    display: block;
    font-family: var(--font-display);
    font-size: 0.7rem;
    font-weight: 700;
    line-height: 1.3;
    color: var(--text-muted);
}

/* The ring is a jump to that ring's card, so it is a button — styled as the
   label it has always been, and reachable from a keyboard because of it. */
.match-ring {
    background: none;
    border: 0;
    cursor: pointer;
    padding: 0;
    text-align: left;
    font-family: var(--font-display);
    font-size: 0.75rem;
    font-weight: 700;
    color: var(--accent-primary);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    padding-top: 0.25rem;
}

.match-details {
    display: flex;
    flex-direction: column;
    padding-right: 0.75rem;
}

.match-breed {
    font-family: var(--font-display);
    font-size: 1.1rem;
    font-weight: 600;
    color: var(--text-primary);
    line-height: 1;
    padding-bottom: 0.5rem;
}

.match-meta {
    text-align: right;
    display: flex;
    flex-direction: column;
}

.match-dogs {
    font-size: 0.8rem;
    color: var(--text-secondary);
}

.match-order {
    font-size: 0.75rem;
    color: var(--text-muted);
}

/* LIVE RING TRACKER (Signature Element Grid) */
.rings-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1rem;
    margin-bottom: 32px;
}

@media (min-width: 600px) {
    .rings-grid {
        grid-template-columns: 1fr 1fr;
    }
}

.ring-node {
    background-color: var(--bg-surface);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    padding: 1.25rem;
    box-shadow: var(--shadow-premium);
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    position: relative;
    overflow: hidden;
    transition: var(--transition-premium);
}

.ring-node:hover {
    border-color: var(--border-highlight);
    box-shadow: 0 15px 35px -10px rgba(0,0,0,0.8);
}

.ring-node.active-ring {
    border-color: rgba(var(--accent-primary-rgb), 0.4);
    box-shadow: 0 0 20px rgba(var(--accent-primary-rgb), 0.1);
}

.ring-node-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 1.25rem;
    margin-bottom: 16px;
}

.ring-node-heading {
    min-width: 0;
}

.ring-node-title {
    font-family: var(--font-display);
    font-size: 1.25rem;
    font-weight: 800;
    color: var(--text-primary);
}

.ring-node-judge {
    font-size: 0.75rem;
    color: var(--text-muted);
    line-height: 1.25;
    margin-top: 2px;
    /*max-width: 55%;*/
    text-align: right;
}

.ring-node-judge span,
.ring-node-judge strong {
    display: block;
}

.ring-node-judge strong {
    color: var(--text-secondary);
    font-weight: 600;
}

.ring-node-delay {
    display: inline-block;
    font-size: 0.75rem;
    font-weight: 700;
    margin-top: 6px;
    padding: 0.1875rem 0.5rem;
    border-radius: 6px;
}

.ring-node-delay.delayed {
    background-color: rgba(var(--color-important-rgb), 0.1);
    color: var(--color-important);
    border: 1px solid rgba(var(--color-important-rgb), 0.2);
}

.ring-node-delay.early {
    background-color: rgba(var(--color-friends-rgb), 0.1);
    color: var(--color-friends);
    border: 1px solid rgba(var(--color-friends-rgb), 0.2);
}

.ring-node-body {
    background-color: rgba(var(--bg-base-rgb), 0.4);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    padding: 0.875rem;
    margin-bottom: 16px;
}

.ring-sequence-row {
    align-items: baseline;
    display: grid;
    gap: 0.625rem;
    grid-template-columns: 46px minmax(0, 1fr);
    line-height: 1.25;
    min-width: 0;
}

.ring-sequence-row + .ring-sequence-row {
    margin-top: 10px;
}

.ring-sequence-row time {
    font-variant-numeric: tabular-nums;
}

.ring-sequence-muted {
    color: var(--text-muted);
    font-size: 0.78rem;
    font-weight: 400;
}

.ring-sequence-muted span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ring-sequence-current {
    color: var(--text-primary);
    font-family: var(--font-display);
    font-size: 1.17rem;
    font-weight: 800;
}

.ring-sequence-current strong {
    min-width: 0;
    overflow-wrap: anywhere;
}

.ring-sequence-current small {
    color: var(--text-secondary);
    font-size: 0.68em;
    font-weight: 600;
    white-space: nowrap;
}

/* Button & UI elements */
.btn-premium {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 0.85rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    padding: 0.75rem;
    border-radius: var(--radius-sm);
    border: none;
    cursor: pointer;
    transition: var(--transition-premium);
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    width: 100%;
    /* An <a> styled as a button is still a link to the browser: it arrives
       underlined and in the visited colour unless both are said here. */
    text-decoration: none;
    color: var(--text-primary);
}

.btn-premium-primary {
    background-color: var(--accent-primary);
    color: white;
    box-shadow: 0 4px 15px rgba(var(--accent-primary-rgb), 0.2);
}

.btn-premium-primary:hover {
    background-color: #E06B00;
    box-shadow: 0 6px 20px rgba(var(--accent-primary-rgb), 0.35);
}

.btn-premium-secondary {
    background-color: var(--bg-overlay);
    color: var(--text-primary);
    border: 1px solid var(--border-color);
}

.btn-premium-secondary:hover {
    background-color: var(--tint-subtle-strong);
}

/* Lists styling */
.list-item-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0.875rem 0;
    border-bottom: 1px solid var(--border-color);
}

.list-item-row:last-child {
    border-bottom: none;
}

/* Forms styling */
.group-form {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

.input-field {
    width: 100%;
    background-color: rgba(var(--bg-base-rgb), 0.6);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    padding: 0.75rem 1rem;
    color: var(--text-primary);
    font-family: var(--font-body);
    font-size: 0.95rem;
    transition: var(--transition-premium);
}

.input-field:focus {
    outline: none;
    border-color: var(--accent-primary);
    box-shadow: 0 0 0 3px rgba(var(--accent-primary-rgb), 0.15);
}

.input-field[type="date"]::-webkit-calendar-picker-indicator,
.input-field[type="time"]::-webkit-calendar-picker-indicator {
    filter: invert(1) brightness(2);
    cursor: pointer;
}

.label-field {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 0.85rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-secondary);
    margin-bottom: 6px;
    display: block;
}

/* A row of buttons that open the page's modals, standing where the form it
   replaced used to be. */
.page-action-bar { display: flex; flex-wrap: wrap; gap: 0.625rem; margin-top: 20px; }
/* .btn-premium is a full-width block by default, which is right inside a form
   and wrong in a row of actions: one button there stretched across the page and
   read as a banner rather than as something to press. Here each button is as
   wide as its own words. */
.page-action-bar .btn-premium { flex: 0 0 auto; width: auto; }

/* Not even on a phone: a button as wide as the screen reads as a banner, and
   these are ordinary actions. They wrap onto the next line instead. */
.page-action-bar .btn-premium { max-width: 100%; }

.modal-lede { color: var(--text-secondary); font-size: .84rem; margin-bottom: 16px; }
.color-field-row input[type="color"] { background: var(--bg-base); border: 1px solid var(--border-color); border-radius: 7px; height: 42px; padding: 0.1875rem; width: 60px; }

/* Autocomplete suggestion popups */
.autocomplete-container {
    position: relative;
}

.suggestions-box {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    background-color: var(--bg-surface);
    border: 1px solid var(--border-highlight);
    border-radius: var(--radius-sm);
    max-height: 220px;
    overflow-y: auto;
    z-index: var(--z-popover);
    box-shadow: 0 10px 25px rgba(0,0,0,0.8);
}

.suggestion-node {
    padding: 0.75rem 1rem;
    cursor: pointer;
    border-bottom: 1px solid var(--border-color);
    transition: var(--transition-premium);
}

.suggestion-node:hover {
    background-color: var(--bg-overlay);
}

.modal-body .suggestions-box { position: static; margin-top: 6px; box-shadow: none; max-height: 190px; }

/* Bottom Bar PWA Navigation */

/* Five tabs, and the middle one is not a tab.

   The dashboard is where every other page leads back to, and it used to be the
   first of five identical cells — the far corner of a phone, the last place a
   thumb reaches. It is now a circle in the centre of the bar, standing above
   it, with the other four pushed in towards it. The bar is shorter than it was
   by exactly enough for the circle to stand proud without growing the strip of
   screen the navigation costs. */
.bar-nav {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    background-color: rgba(var(--bg-surface-rgb), 0.96);
    backdrop-filter: blur(16px);
    border-top: 1px solid var(--border-color);
    padding: 0;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    /* Above all page content, and level with the sticky header. */
    z-index: var(--z-chrome);
    box-shadow: 0 -10px 30px rgba(0,0,0,0.5);
    /* viewport-fit=cover: keep the tabs clear of the iOS home indicator. */
    padding-bottom: env(safe-area-inset-bottom, 0px);
}

.bar-tab {
    display: flex;
    flex-direction: column;
    align-items: center;
    color: var(--text-secondary);
    text-decoration: none;
    font-size: 0.7rem;
    font-family: var(--font-display);
    font-weight: 600;
    gap: 0.1875rem;
    transition: var(--transition-premium);
    padding: 0.375rem 0.375rem 0.4375rem;
    border-radius: var(--radius-sm);
    border: 1px solid transparent;
    /* The four ordinary tabs share the bar evenly. min-width:0 lets a long word
       ellipsise inside its own tab instead of pushing the neighbours off. */
    flex: 1 1 0;
    min-width: 0;
    /* Room in the middle for the circle, which is taken out of the flow. */
    max-width: 5.5rem;
}

.bar-tab-word {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.bar-icon { display: block; }

.bar-icon-glyph {
    display: block;
    height: 22px;
    width: 22px;
}

.bar-tab:hover {
    color: var(--text-primary);
    background-color: var(--tint-subtle);
}

.bar-tab.active {
    color: var(--accent-primary);
    background-color: rgba(var(--accent-primary-rgb), 0.08);
    border-color: rgba(var(--accent-primary-rgb), 0.2);
    box-shadow: inset 0 0 10px rgba(var(--accent-primary-rgb), 0.05);
}

/* The hub: a circle lifted clear of the bar, wider than a tab and taller than
   the bar it sits in. It stands well proud rather than merely peeping over the
   edge — half of it is above the border, which is what makes it read as one
   button rather than as a fifth tab with a round background.

   margin-top is negative by the amount it rises, so the bar's own height is
   unchanged and the page below it needs no extra clearance. */
.bar-tab-hub {
    align-items: center;
    background: linear-gradient(160deg, var(--accent-primary) 0%, rgba(var(--accent-primary-rgb), .78) 100%);
    border: 3px solid var(--bg-surface);
    border-radius: 999px;
    box-shadow: 0 6px 18px rgba(var(--accent-primary-rgb), .45);
    color: #fff;
    flex: 0 0 auto;
    gap: 0;
    height: 68px;
    justify-content: center;
    margin: -32px 0.625rem 0;
    padding: 0;
    width: 68px;
}

.bar-tab-hub:hover,
.bar-tab-hub.active {
    background-color: transparent;
    border-color: var(--bg-surface);
    box-shadow: 0 8px 22px rgba(var(--accent-primary-rgb), .6);
    color: #fff;
}

/* The circle says which page it is by being the circle. Its word would have to
   sit outside it, on the bar, level with nothing. */
.bar-tab-hub .bar-tab-word { display: none; }

.bar-tab-hub .bar-icon-glyph {
    height: 30px;
    stroke-width: 1.8;
    width: 30px;
}

/* Toast Notifications */
.toast-container {
    position: fixed;
    top: 24px;
    left: 50%;
    transform: translateX(-50%);
    width: 90%;
    max-width: 400px;
    z-index: var(--z-notice);
    display: flex;
    flex-direction: column;
    gap: 0.625rem;
}

.toast {
    background-color: var(--bg-surface);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    padding: 1rem 1.25rem;
    box-shadow: 0 20px 40px rgba(0,0,0,0.8);
    display: flex;
    align-items: flex-start;
    gap: 0.875rem;
    position: relative;
    animation: slide-down 0.4s cubic-bezier(0.16, 1, 0.3, 1) forwards;
    transition: opacity 0.3s ease, transform 0.3s ease;
}

@keyframes slide-down {
    from {
        opacity: 0;
        transform: translateY(-20px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

.toast-error {
    border-left: 4px solid var(--color-my-dogs);
    border-color: rgba(var(--color-my-dogs-rgb), 0.3) rgba(var(--color-my-dogs-rgb), 0.3) rgba(var(--color-my-dogs-rgb), 0.3) var(--color-my-dogs);
}

.toast-success {
    border-left: 4px solid var(--color-friends);
    border-color: rgba(var(--color-friends-rgb), 0.3) rgba(var(--color-friends-rgb), 0.3) rgba(var(--color-friends-rgb), 0.3) var(--color-friends);
}

.toast-icon {
    font-size: 1.25rem;
    line-height: 1;
    margin-top: 2px;
}

.toast-content {
    flex: 1;
}

.toast-title {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 0.95rem;
    margin-bottom: 2px;
}

.toast-message {
    font-size: 0.85rem;
    color: var(--text-secondary);
    line-height: 1.4;
}

.toast-close {
    background: none;
    border: none;
    color: var(--text-muted);
    font-size: 1.2rem;
    cursor: pointer;
    line-height: 1;
    transition: var(--transition-premium);
}

.toast-close:hover {
    color: var(--text-primary);
}

/* Modal System */
.modal-overlay {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    /* The dialog scrolls inside the overlay, and the scroll stops there: a
       gesture that runs past its end must not be handed to the page behind. */
    overflow: auto;
    overscroll-behavior: contain;
    padding: 0.75rem;
    background-color: rgba(var(--bg-base-rgb), 0.8);
    backdrop-filter: blur(12px);
    z-index: var(--z-modal);
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
}

.modal-overlay.active {
    opacity: 1;
    pointer-events: auto;
}

.modal-container {
    background-color: var(--bg-surface);
    border: 1px solid var(--border-highlight);
    border-radius: var(--radius-lg);
    width: 90%;
    max-width: min(520px, calc(100vw - 24px));
    /* A flex item refuses to shrink below its content's min-content width
       unless it is told to. The ring picker's <select> is as wide as its
       longest breed name, so on a phone the dialog grew past the screen and
       the page could be dragged sideways behind it. */
    min-width: 0;
    box-shadow: var(--shadow-premium), 0 30px 60px -15px rgba(0, 0, 0, 0.9);
    transform: scale(0.92) translateY(10px);
    transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
    overflow: hidden;
    /* A dialog that grows -- the year grid opening, a long form -- stops at the
       viewport and scrolls its body, instead of running off both edges where
       overflow: hidden puts it out of reach. */
    display: flex;
    flex-direction: column;
    max-height: 90vh;
}

.modal-overlay.active .modal-container {
    transform: scale(1) translateY(0);
}

.modal-header {
    padding: 1.125rem 1.5rem;
    border-bottom: 1px solid var(--border-color);
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-shrink: 0;
}

.modal-title {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 1.15rem;
    letter-spacing: -0.01em;
    color: var(--text-primary);
}

.modal-close {
    background: none;
    border: none;
    color: var(--text-muted);
    font-size: 1.6rem;
    cursor: pointer;
    line-height: 1;
    transition: var(--transition-premium);
    padding: 0.25rem;
}

.modal-close:hover {
    color: var(--color-my-dogs);
}

.modal-body {
    padding: 1.5rem;
    overflow-y: auto;
    min-width: 0;
}

/* Same story one level down: a long option must not set the dialog's width. */
.modal-body select.input-field {
    max-width: 100%;
    text-overflow: ellipsis;
}

/* While a dialog is open the page behind it does not scroll — in either
   direction. Without this the document keeps its own scroll under a fixed
   overlay, which on a phone reads as the screen sliding about by itself. */
body.modal-open {
    overflow: hidden;
}

/* Shows Page Layout Styles */
.show-card-layout {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.75rem;
}

/* Whether a show has run or has not is said by one glyph at the front of the
   card, and by nothing else.

   The past block used to be painted at half opacity, which said it clearly and
   cost the reader the block: a name at 50% on a dark ground is hard to read,
   and the block exists to be read. Every card is now at full strength and
   carries a tick or a clock. Same drawing twice — a circle with something in
   it — so the column of them reads as one mark, not as decoration. */
.show-card-mark {
    align-items: center;
    display: inline-flex;
    flex: 0 0 auto;
    justify-content: center;
}

.show-card-mark-icon {
    display: block;
    height: 17px;
    width: 17px;
}

/* The mark sits on the name's own line rather than in a column down the left of
   the card. On the left it read as a control — something to press — and it
   pushed the name and the venue in by its whole width for a fact about the show
   that the name is already carrying. baseline alignment keeps it sitting with
   the type rather than centred against a name that has wrapped to two lines. */
.show-card-heading {
    align-items: baseline;
    display: flex;
    /* The dashboard pill puts an "on now" badge and the dates on this line
       beside the name, so it has to be able to take a second row on a phone. */
    flex-wrap: wrap;
    gap: 0.4375rem;
}

.show-card-heading .show-card-mark { transform: translateY(2px); }

/* Where the show is. Drawn, for the same reason the marks are: an emoji is the
   device's picture, on its own baseline, in its own colour. */
.show-card-pin {
    display: inline-block;
    height: 14px;
    margin-right: 5px;
    vertical-align: -2px;
    width: 14px;
}

/* The tick is quiet: it says "nothing left to wait for". */
.show-card-mark-circle-check { color: var(--text-muted); }

/* The clock is not: it is the half of the list that has not happened. */
.show-card-mark-clock { color: var(--accent-primary); }

/* The show running today. The block only exists on those days, so it is the
   one thing on the page worth pointing at. */
.show-section-now .section-header {
    color: var(--accent-primary);
}

.show-section-now .show-card {
    border: 1px solid rgba(var(--accent-primary-rgb), .45);
    background: linear-gradient(135deg, rgba(var(--accent-primary-rgb), .1) 0%, var(--bg-surface) 60%);
}

#company_field {
    position: absolute;
    left: -5000px;
}
/* The past block is folded away above the rest of the page. Its own header
   scrolls off when it opens, so the toggle lives at the bottom, where it keeps
   its place on screen. */
.folded-section-toggle {
    align-items: center;
    background: none;
    border: 1px dashed var(--border-color);
    border-radius: var(--radius-md);
    color: var(--text-muted);
    cursor: pointer;
    display: flex;
    font: 700 .72rem var(--font-display);
    gap: 0.5rem;
    justify-content: center;
    letter-spacing: .06em;
    margin: 16px 0 4px;
    padding: 0.625rem 0.875rem;
    text-transform: uppercase;
    width: 100%;
}

.folded-section-toggle:hover {
    border-color: rgba(var(--accent-primary-rgb), .5);
    color: var(--accent-primary);
}

/* Tags on a show card: what is missing, and what is still open. Wrapped so a
   card can carry both without either being pushed off the edge. */
.show-card-tags { display: flex; flex-wrap: wrap; gap: 0.375rem; }

.show-card-tag {
    background: rgba(var(--color-my-dogs-rgb), .1);
    border: 1px solid rgba(var(--color-my-dogs-rgb), .3);
    border-radius: 999px;
    color: var(--color-my-dogs);
    display: inline-flex;
    font: 700 .66rem var(--font-display);
    letter-spacing: .03em;
    margin-top: 4px;
    padding: 0.1875rem 0.5625rem;
    white-space: nowrap;
}

/* Entries still open is the one piece of good news a card carries, so it is the
   one tag painted in the "go" colour rather than the warning one.

   After the base rule, not before it. Same specificity, so source order decides,
   and while this sat above .show-card-tag the base rule's `border` shorthand and
   `color` won and the tag came out in the warning colour. Invisible for as long
   as the tag itself was: it only ever appeared for three days after an import,
   so nobody was looking at a green that was not green. */
.show-card-tag-open {
    background: rgba(var(--color-friends-rgb), .12);
    border-color: rgba(var(--color-friends-rgb), .35);
    color: var(--color-friends);
}

.show-card-info {
    display: flex;
    flex: 1;
    flex-direction: column;
    gap: 0.125rem;
    min-width: 0;
}

/* line-height 1: a show name is one line of display type sitting directly above
   its venue, and the font's own leading opened a gap that read as a paragraph
   break inside a single card. A name long enough to wrap still wraps. */
.show-card-name {
    color: var(--text-primary);
    display: inline-block;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 1.05rem;
    letter-spacing: -0.01em;
    line-height: 1;
    text-decoration: none;
    transition: var(--transition-premium);
}

.show-card-place {
    align-items: baseline;
    color: var(--text-secondary);
    display: flex;
    font-size: 0.8rem;
    margin-top: 4px;
}

/* A show with no schedule is not a link — there is nothing behind it yet — so
   only the anchor answers to hover. */
a.show-card-name:hover {
    color: var(--accent-primary);
}

.show-card-actions {
    display: flex;
    align-items: center;
    gap: 1rem;
}

.show-card-actions .btn-premium {
    width: auto;
    padding: 0.5rem 1rem;
    font-size: 0.8rem;
}

/* The days on one line, the year under them. "28 Feb - 1 Mar 2026" on one line
   either wrapped wherever it liked or pushed the name; and the days are what a
   reader is after, the year only what tells two Bejas apart. */
.show-card-date {
    display: flex;
    flex-direction: column;
    text-align: right;
}

.show-card-days {
    color: var(--accent-primary);
    font: 700 0.9rem/1.1 var(--font-display);
    white-space: nowrap;
}

.show-card-year {
    color: var(--text-muted);
    font: 600 0.74rem/1.2 var(--font-display);
    letter-spacing: .04em;
    white-space: nowrap;
}

/* Schedule views: imported table and ring-by-ring day board */
.schedule-heading {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    gap: 1rem;
    margin: 0 0 10px;
}

.schedule-eyebrow {
    display: inline-block;
    color: var(--accent-primary);
    font: 700 0.72rem/1 var(--font-display);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    margin-bottom: 7px;
    text-decoration: none;
    transition: opacity 0.2s;
}
.schedule-eyebrow:hover {
    opacity: 0.8;
}

.schedule-heading h1 {
    font: 800 clamp(1.45rem, 4vw, 2rem)/1.15 var(--font-display);
    letter-spacing: -0.035em;
}

.schedule-subtitle { color: var(--text-secondary); font-size: 0.84rem; margin-top: 6px; }

.schedule-view-switch {
    display: flex;
    padding: 0.25rem;
    background: var(--bg-card);
    border: 1px solid var(--border-color);
    border-radius: 10px;
    flex-shrink: 0;
}

.schedule-view-option, .schedule-date-tab {
    color: var(--text-secondary);
    text-decoration: none;
    font: 700 0.78rem var(--font-display);
    transition: var(--transition-premium);
}

.schedule-view-option { padding: 0.4375rem 0.625rem; border-radius: 6px; }
.schedule-view-option.active { color: #fff; background: var(--accent-primary); }

/* One row: the day switcher on the left, the view switcher on the right. */
.schedule-tools { align-items: center; display: flex; flex-wrap: nowrap; gap: 0.75rem; justify-content: space-between; margin-bottom: 20px; }
.schedule-tools .schedule-view-switch { flex: 0 0 auto; margin-left: auto; }
.schedule-date-tabs { display: flex; flex: 0 1 auto; gap: 0.5rem; min-width: 0; overflow-x: auto; scrollbar-width: none; }
.schedule-date-tabs::-webkit-scrollbar { display: none; }
.schedule-date-tab { min-width: 55px; padding: 0.5rem 0.75rem; text-align: center; background: var(--bg-surface); border: 1px solid var(--border-color); border-radius: 10px; }
.schedule-date-tab span { display: block; font-size: 0.68rem; text-transform: uppercase; }
.schedule-date-tab strong { display: block; color: var(--text-primary); font-size: 1rem; }
.schedule-date-tab.active { border-color: var(--accent-primary); background: var(--accent-glow); color: var(--accent-primary); }
.schedule-date-tab.active span { color: var(--bg-base); }

.schedule-ring-filter { display: grid; gap: 0.375rem; grid-auto-columns: 1fr; grid-auto-flow: column; margin-bottom: 8px; width: 100%; }
.schedule-ring-filter-btn { align-items: center; background: var(--bg-surface); border: 1px solid var(--border-color); border-radius: 8px; color: var(--text-secondary); cursor: pointer; display: inline-flex; font: 700 .78rem var(--font-display); justify-content: center; overflow: hidden; padding: 0.375rem 0.25rem; transition: var(--transition-premium); white-space: nowrap; }
.schedule-ring-filter-btn .ring-word { margin-right: 5px; }
.schedule-ring-filter-btn:hover { border-color: var(--accent-primary); color: var(--accent-primary); }
.schedule-ring-filter-btn.active { background: var(--accent-primary); border-color: var(--accent-primary); color: #fff; }
.schedule-ring-filter-btn.past { opacity: .4; }

/* Free-text quick search sitting right under the ring row. */
.schedule-search { margin-bottom: 20px; position: relative; width: 100%; }
.schedule-search-input { background: var(--bg-surface); border: 1px solid var(--border-color); border-radius: 8px; color: var(--text-primary); font: 500 .85rem var(--font-body); padding: 0.5625rem 2.125rem 0.5625rem 0.75rem; transition: var(--transition-premium); width: 100%; }
.schedule-search-input::placeholder { color: var(--text-muted); }
.schedule-search-input:focus { border-color: var(--accent-primary); outline: none; }
.schedule-search-input::-webkit-search-cancel-button { display: none; }
.schedule-search-clear { background: none; border: 0; color: var(--text-muted); cursor: pointer; font: 700 1.1rem/1 var(--font-display); padding: 0.25rem 0.5rem; position: absolute; right: 4px; top: 50%; transform: translateY(-50%); }
.schedule-search-clear:hover { color: var(--accent-primary); }
.schedule-search-empty { color: var(--text-secondary); font-size: .85rem; margin: 0 0 20px; text-align: center; }
.is-filtered-out { display: none !important; }

.schedule-ring-tables { display: grid; gap: 1.625rem; }
.schedule-ring-table { min-width: 0; }
.schedule-ring-table h2 { align-items: baseline; color: var(--text-primary); display: flex; flex-wrap: wrap; font: 800 1.05rem var(--font-display); gap: 0.25rem 0.625rem; margin: 0 0 10px; }
.schedule-ring-table h2 small { color: var(--text-secondary); font: 600 .82rem var(--font-display); }
.schedule-table-wrap { overflow-x: auto; border: 1px solid var(--border-color); border-radius: var(--radius-md); background: var(--bg-surface); box-shadow: var(--shadow-premium); }
/* Fixed layout, or every ring table sizes its columns to its own longest breed
   and the day reads as a pile of unrelated tables instead of one list. */
.schedule-table { width: 100%; border-collapse: collapse; table-layout: fixed; text-align: left; }
.schedule-table th:first-child, .schedule-table td:first-child { width: 84px; }
.schedule-table th:last-child, .schedule-table td:last-child { width: 76px; }

.schedule-table th {
    padding: 0.5rem 0.5rem;
    font-size: .64rem;
    letter-spacing: .03em;
    color: var(--text-muted);
    text-transform: uppercase;
    background: var(--bg-card);
}
/* A fixed column is a promise the header has to keep. "Собаки" set wide and
   spaced is 64px of min-content against a 58px column, and the table pushed
   the extra six pixels out sideways: wrapping is allowed here so no
   translation of a heading can ever hand the table a horizontal scrollbar. */
.schedule-table th { overflow-wrap: anywhere; }
.schedule-table td { padding: 0.1875rem 0.5rem; border-top: 1px solid var(--border-color); color: var(--text-secondary); font-size: .86rem; }
@media (hover: hover) { .schedule-table tr:hover td { background: var(--tint-subtle); } }
.schedule-table tr.past td { opacity: .4; }
/* The row in the ring says so by being lit, not by wearing a tag. A badge on
   the row competed with the breed name for the same glance; the colour of the
   row is read before either of them. */
.schedule-table tr.now td { background: rgba(var(--accent-primary-rgb), .12); }
.schedule-table tr.now td:first-child { box-shadow: inset 3px 0 0 var(--accent-primary); }
.schedule-now-badge { background: var(--accent-primary); color: var(--bg-base); font-size: 0.65rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.05em; padding: 0.125rem 0.375rem; border-radius: 4px; margin-left: 8px; display: inline-block; vertical-align: middle; line-height: 1; }
/* The same badge, paler: a breed still to come says how long, and must not
   compete with the one that is actually in the ring. */
.schedule-now-badge.is-ahead {
    background: rgba(var(--accent-primary-rgb), .22);
    color: var(--text-secondary);
    /* "+1h23m" is a reading, not a label: upper case mangles the h and the m. */
    text-transform: none;
}

.schedule-next-badge { background: transparent; color: var(--text-muted); border: 1px solid var(--border-color); font-size: 0.65rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.05em; padding: 0.0625rem 0.3125rem; border-radius: 4px; margin-left: 8px; display: inline-block; vertical-align: middle; line-height: 1; }
.schedule-table-time { color: var(--accent-primary) !important; font: 800 .95rem var(--font-display); }
.schedule-table-breed { color: var(--text-primary) !important; font: 600 .95rem var(--font-display); word-wrap: break-word; word-break: break-word; white-space: normal; }

@media (max-width: 500px) {
    .schedule-table th {
        padding: 0.5rem 0.5rem;
        font-size: .64rem;
        letter-spacing: .03em;
    }
    .schedule-table th:first-child, .schedule-table td:first-child {width: 62px; padding: 0.1875rem 0.1875rem 0.1875rem 0.5rem; }
    .schedule-table th:last-child, .schedule-table td:last-child { width: 66px; }
}

.schedule-day-page { overflow: hidden; padding-bottom: 0; }
.schedule-day-scroll { height: var(--schedule-viewport-height, calc(100dvh - 250px)); overflow: auto; overscroll-behavior: contain; scrollbar-gutter: stable; }
.schedule-day-grid { display: grid; grid-template-columns: 40px minmax(360px, 1fr); min-width: max(500px, var(--schedule-min-width)); position: relative; }
.schedule-time-axis { align-self: start; background: var(--bg-base); box-shadow: 1px 0 0 var(--border-color); height: calc(var(--schedule-height) + 39px); left: 0; position: sticky; width: 40px; z-index: 5; }
.schedule-time-axis time { color: var(--text-muted); font: 700 .66rem var(--font-display); position: absolute; right: 6px; transform: translateY(-50%); }
.schedule-rings { display: grid; grid-template-columns: repeat(var(--ring-count), minmax(180px, 1fr)); min-width: 0; border: 1px solid var(--border-color); border-radius: var(--radius-md); overflow: visible; background: var(--bg-surface); }
.schedule-ring-column { min-width: 0; border-left: 1px solid var(--border-color); }
.schedule-ring-column:first-child { border-left: 0; }
.schedule-ring-column > header { height: 39px; display: flex; align-items: center; padding: 0 0.75rem; position: sticky; top: 0; z-index: 4; background: var(--bg-card); border-bottom: 1px solid var(--border-color); color: var(--text-primary); font: 800 .82rem var(--font-display); }
.schedule-ring-track { height: var(--schedule-height); position: relative; }
.schedule-hour-line { border-top: 1px dashed rgba(var(--text-secondary-rgb),.14); left: 0; position: absolute; right: 0; }
.schedule-event { left: 5px; min-height: 46px; overflow: hidden; padding: 0.375rem 0.5rem 0.4375rem; position: absolute; right: 5px; z-index: 1; border-radius: 5px; background: linear-gradient(135deg, #202945 0%, rgba(32,41,69,0) 100%); box-shadow: 0 3px 10px rgba(0,0,0,.2); color: var(--text-primary); line-height: 1.18; }
.schedule-event::before { background: linear-gradient(to bottom, var(--accent-primary) 0%, rgba(var(--accent-primary-rgb),0) 100%); content: ""; inset: 0 auto 0 0; position: absolute; width: 3px; }
.schedule-event-meta { align-items: baseline; display: flex; justify-content: space-between; gap: 0.5rem; }
.schedule-event time { color: #ffad64; font: 800 .68rem var(--font-display); }
.schedule-event strong { display: block; margin-top: 3px; font: 700 .76rem/1.22 var(--font-display); overflow-wrap: anywhere; }
.schedule-event-count { flex: 0 0 auto; color: var(--text-secondary); font: 700 .65rem var(--font-display); white-space: nowrap; }
.schedule-current-time { background: var(--color-my-dogs); box-shadow: 0 0 8px rgba(var(--color-my-dogs-rgb),.55); height: 2px; left: 40px; pointer-events: none; position: absolute; right: 0; top: calc(39px + var(--current-time-top, 0px)); z-index: 3; }
.schedule-current-time::before { background: var(--color-my-dogs); border: 2px solid var(--bg-base); border-radius: 50%; content: ""; height: 8px; left: 0; position: absolute; top: 50%; transform: translate(-50%, -50%); width: 8px; }
.schedule-empty-state { margin-top: 32px; text-align: center; }

@media (max-width: 560px) {
    .schedule-heading { align-items: flex-start; flex-direction: column; }
    .schedule-tools { gap: 0.5rem; }
    .schedule-date-tab { min-width: 46px; padding: 0.4375rem 0.5625rem; }
    .schedule-view-option { padding: 0.4375rem 0.5rem; }
    .bar-tab { padding: 0.3125rem 0.1875rem 0.375rem; font-size: .62rem; }
    .bar-tab-hub { height: 64px; margin: -30px 0.375rem 0; padding: 0; width: 64px; }
}

.import-show-preview {
    background-color: var(--tint-subtle);
    border: 1px solid var(--border-color);
    padding: 0.75rem;
    border-radius: var(--radius-sm);
    margin-bottom: 12px;
}

.import-show-preview-label {
    font-size: 0.8rem;
    color: var(--text-secondary);
    text-transform: uppercase;
    font-weight: bold;
    letter-spacing: 0.05em;
}

.import-show-preview-name {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 1.05rem;
    margin-top: 4px;
    color: var(--accent-primary);
}

/* Import Tabs */
.import-tabs {
    display: flex;
    gap: 0.25rem;
    margin-bottom: 16px;
    background-color: var(--bg-card);
    border-radius: var(--radius-sm);
    padding: 0.25rem;
    border: 1px solid var(--accent-glow)
}

.import-tab {
    flex: 1;
    padding: 0.625rem 0.75rem;
    border: none;
    background: none;
    color: var(--text-secondary);
    font-family: var(--font-body);
    font-size: 0.85rem;
    font-weight: 600;
    cursor: pointer;
    border-radius: 6px;
    transition: var(--transition-premium);
}

.import-tab:hover {
    color: var(--text-primary);
    background-color: var(--bg-overlay);
}

.import-tab.active {
    background-color: var(--accent-primary);
    color: white;
}

/* Import Panels */
.import-panel {
    display: none;
}

.import-panel.active {
    display: block;
}

/* Import Hints */
.import-field-hint {
    font-size: 0.75rem;
    color: var(--text-muted);
    font-weight: normal;
    display: block;
    margin-top: 4px;
    margin-bottom: 8px;
    line-height: 1.5;
}

/* Import Result Feedback */
.import-result {
    margin-top: 12px;
    padding: 0;
    font-size: 0.85rem;
    border-radius: var(--radius-sm);
    transition: var(--transition-premium);
}

.import-result:empty {
    display: none;
}

/* Pre-import page checks: what the page must contain, and what it does. */
.import-note { font-size: .74rem; margin-top: 8px; opacity: .85; word-break: break-all; }
.import-problems { display: grid; gap: 0.3125rem; font-size: .78rem; list-style: none; margin: 10px 0 0; padding: 0; }
.import-problems li { padding-left: 1rem; position: relative; }
.import-problems li::before { content: "•"; left: 3px; position: absolute; }
.import-checks ul { display: grid; gap: 0.25rem; list-style: none; margin: 8px 0 0; padding: 0; }
.import-checks li { align-items: baseline; display: flex; font-size: .72rem; gap: 0.5rem; justify-content: space-between; }
.import-checks li small { color: var(--text-muted); flex: 0 0 auto; }
.import-checks .check-ok { color: var(--color-friends); }
.import-checks .check-fail { color: var(--color-my-dogs); }

/* Root-only diagnostics, shown under an error toast or an import result. */
.import-detail, .toast-detail { margin-top: 8px; }
.import-detail summary, .toast-detail summary { cursor: pointer; font: 700 .68rem var(--font-display); letter-spacing: .06em; opacity: .8; text-transform: uppercase; }
.import-detail pre, .toast-detail pre {
    background: rgba(0,0,0,.28);
    border: 1px solid var(--border-color);
    border-radius: 6px;
    color: var(--text-secondary);
    font-size: .7rem;
    line-height: 1.45;
    margin-top: 6px;
    max-height: 220px;
    overflow: auto;
    padding: 0.5rem 0.625rem;
    white-space: pre-wrap;
    word-break: break-word;
}

.import-result-success {
    padding: 0.75rem;
    background-color: rgba(var(--color-friends-rgb), 0.1);
    border: 1px solid rgba(var(--color-friends-rgb), 0.3);
    color: var(--color-friends);
}

.import-result-error {
    padding: 0.75rem;
    background-color: rgba(var(--color-my-dogs-rgb), 0.1);
    border: 1px solid rgba(var(--color-my-dogs-rgb), 0.3);
    color: var(--color-my-dogs);
}
button.link-button {
    appearance: none;
    border: 0;
    padding: 0;
    background: transparent;
    color: inherit;
    font: inherit;
    text-decoration: underline;
    cursor: pointer;
}

/* Breed CRUD specific styles */
.breed-search-card {
    padding: 0.75rem 1rem;
    margin-bottom: 16px;
}
.breed-search-input {
    width: 100%;
    padding: 0.625rem 0.875rem;
    background: var(--bg-base);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    color: var(--text-primary);
    font: inherit;
    font-size: 0.9rem;
    transition: var(--transition-premium);
}
.breed-search-input:focus {
    border-color: var(--accent-primary);
    outline: none;
    box-shadow: 0 0 0 2px rgba(var(--accent-primary-rgb), 0.2);
}
/* Name and actions only: two columns need no horizontal scroll floor. */
#breeds-table { min-width: 0; }
#breeds-table td.user-actions, #breeds-table th:last-child { width: 1%; }
.breed-edit-layout {
    display: grid;
    gap: 1rem;
    grid-template-columns: minmax(0, 1fr) minmax(280px, 0.85fr);
    align-items: start;
}
/* Same reason as the track above: a grid item defaults to a min-content floor,
   so any card holding something wide would widen the page instead of scrolling
   or wrapping inside itself. */
.breed-edit-layout > * { min-width: 0; }
/* Every name the breed answers to, in one list: the catalogue's own first, then
   the aliases. Each row is a button because each row opens an editor, and a
   thing you click is a control whether or not it looks like one. */
.breed-name-list {
    display: flex;
    flex-direction: column;
    gap: 0.375rem;
    margin-top: 16px;
}
.breed-name-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    width: 100%;
    padding: 0.625rem 0.75rem;
    border: 1px solid var(--border-color);
    border-radius: 8px;
    background: var(--bg-card);
    color: var(--text-primary);
    font: inherit;
    text-align: left;
    cursor: pointer;
}
.breed-name-item:hover { border-color: var(--accent-primary); }
.breed-name-item-text { min-width: 0; overflow-wrap: anywhere; font-size: .85rem; }
.breed-name-item-main .breed-name-item-text { font-weight: 700; }
.breed-name-item-tags {
    display: flex;
    align-items: center;
    flex: 0 0 auto;
    gap: 0.5rem;
}
.breed-name-item-tags small { font-size: .7rem; color: var(--text-secondary); }
/* The two things a name can have done to it that are not a save, side by side
   under the form: each is its own submission, so each is its own form. */
.breed-name-modal-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.625rem;
    margin-top: 16px;
    padding-top: 0.875rem;
    border-top: 1px solid var(--border-color);
}
.breed-name-modal-actions .btn-premium { width: auto; font-size: .72rem; padding: 0.5625rem 0.8125rem; }
/* The one name that is the breed rather than a way of finding it. */
.breed-name-badge {
    padding: 0.125rem 0.5rem;
    border-radius: 4px;
    background: var(--accent-glow);
    color: var(--bg-card);
    font-size: .66rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
}
/* Aliases are added through a modal, so the card header carries the button. */
.breed-alias-card-head {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    justify-content: space-between;
}
.breed-alias-card-head .settings-card-title { margin-bottom: 0; }
.breed-alias-card-head .btn-premium { font-size: .72rem; padding: 0.5625rem 0.8125rem; white-space: nowrap; width: auto; }
.alias-lang {
    background: var(--bg-overlay);
    padding: 0.125rem 0.375rem;
    border-radius: 4px;
    font-size: 0.75rem;
    color: var(--text-secondary);
    text-transform: uppercase;
}
/* Two lines above the catalogue: what the run is doing, and where the
   catalogue stands. The second is permanent, so the block never collapses and
   the table below it does not jump when a fetch starts or ends. */
.fci-run-status { margin-bottom: 12px; }
.fci-run-line { margin: 0; font-size: .78rem; }
.fci-run-line + .fci-run-line { margin-top: 2px; }
.fci-run-line b { color: var(--text-primary); font-weight: 700; }
.fci-run-line[hidden] { display: none; }

/* Catalogue row: a 35px slot, then the name. The slot is always there — with a
   picture, with the paw when the breed has FCI data but no picture, and empty
   when it has neither — so every name in the table starts at the same x. */
.breed-name-cell {
    display: flex;
    align-items: center;
    gap: 0.625rem;
}
/* The tick leads the row in a column of its own, so the heading over the names
   labels the names rather than the checkbox. */
.breed-check, .breed-head-select input {
    flex: 0 0 auto;
    width: 16px;
    height: 16px;
    margin: 0;
    accent-color: var(--accent-primary);
    cursor: pointer;
}
#breeds-table th.breed-head-select, #breeds-table td.breed-cell-select { width: 1%; padding-right: 0; }
/* The picture has its own column, so "Breed Name" stands over the names. */
#breeds-table th.breed-head-thumb, #breeds-table td.breed-cell-thumb { width: 1%; padding-right: 0; }
#breeds-table th.breed-head-group, #breeds-table td.breed-cell-group { width: 1%; white-space: nowrap; }
#breeds-table th.breed-head-std, #breeds-table td.breed-cell-std { width: 1%; white-space: nowrap; }
/* A heading you can click is a button, so it is one — keyboard and all. */
.breed-head-sort button {
    display: inline-flex;
    align-items: center;
    gap: 0.3125rem;
    padding: 0;
    border: 0;
    background: none;
    color: inherit;
    font: inherit;
    text-transform: inherit;
    letter-spacing: inherit;
    cursor: pointer;
}
.breed-head-sort button:hover { color: var(--text-primary); }
.breed-sort-arrow { font-size: .6rem; color: var(--accent-primary); }
.merge-choice-list {
    display: flex;
    flex-direction: column;
    gap: 0.375rem;
    max-height: 280px;
    overflow-y: auto;
    margin-bottom: 4px;
}
.merge-choice {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    padding: 0.5625rem 0.6875rem;
    border: 1px solid var(--border-color);
    border-radius: 8px;
    background: var(--bg-card);
    cursor: pointer;
    font-size: .82rem;
}
.merge-choice:hover { border-color: var(--accent-primary); }
.merge-choice input { width: auto; margin: 0; accent-color: var(--accent-primary); }
.merge-choice:has(input:checked) { border-color: var(--accent-primary); }
.breed-delete-form { margin-top: 16px; padding-top: 0.875rem; border-top: 1px solid var(--border-color); }
.breed-delete-form .btn-premium { width: auto; font-size: .72rem; padding: 0.5625rem 0.8125rem; }
.breed-delete-note { margin-top: 16px; padding-top: 0.875rem; border-top: 1px solid var(--border-color); font-size: .72rem; }
/* The name and its note are one column beside the picture, not siblings of it.
   As flex items of the row they could not shrink below their own text, so a
   long name wrapped underneath the picture instead of beside it — min-width:0
   is what lets the text wrap inside the cell it was given. */
.breed-name-body { min-width: 0; flex: 1 1 auto; }
.breed-name-body strong { overflow-wrap: anywhere; }
.breed-thumb {
    flex: 0 0 auto;
    width: 35px;
    height: 35px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 7px;
    overflow: hidden;
}
/* Not square? Fill the square and crop, rather than letterbox the dog. The paw
   is excluded — it is a placeholder sitting in the slot, not the picture. */
.breed-thumb img:not(.breed-paw) { width: 100%; height: 100%; object-fit: cover; display: block; }
.breed-thumb .breed-paw { display: none; width: 22px; height: 22px; object-fit: contain; }
.breed-thumb-photo { background: var(--bg-overlay); }
.breed-thumb-empty { background: rgba(var(--color-important-rgb), .1); }
.breed-thumb-empty .breed-paw { display: block; }
.breed-fci-note { font-size: .7rem; color: var(--text-secondary); }
/* The group has its own column now, so the tag only has to be a tag. */
.breed-group-tag {
    display: inline-block;
    padding: 0.1875rem 0.5rem;
    border: 1px solid var(--accent-glow);
    border-radius: var(--radius-sm);
    color: var(--accent-glow);
    font-weight: 700;
    font-size: .68rem;
    letter-spacing: .04em;
    white-space: nowrap;
}
.breed-group-tag[hidden] { display: none; }
/* The standard body, in the same shape as the group but quieter: it is the
   same word down most of the column, so it reads as a marker rather than
   competing with the group beside it. Empty until the breed has actually been
   read from that body, so the column shows what is confirmed. */
.breed-std-tag {
    display: inline-block;
    padding: 0.1875rem 0.5rem;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    color: var(--text-secondary);
    font-weight: 700;
    font-size: .66rem;
    letter-spacing: .04em;
    white-space: nowrap;
}
.breed-std-tag[hidden] { display: none; }
/* How many of the six names the breed carries. Deliberately plain until it is
   complete: a column of green ticks down a mostly-translated catalogue says
   nothing, while the few incomplete rows are what the eye should catch. */
.breed-cell-langs { white-space: nowrap; }
.breed-lang-count {
    display: inline-block;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
    font-size: .78rem;
    font-weight: 600;
}
.breed-lang-count.is-complete { color: var(--text-muted); }
/* English and nothing else -- what a fresh import leaves behind, and the set
   worth running a translation hunt over first. */
.breed-lang-tag {
    display: inline-block;
    margin-left: 6px;
    padding: 0.125rem 0.4375rem;
    border-radius: var(--radius-sm);
    background: color-mix(in srgb, var(--accent-color) 16%, transparent);
    color: var(--accent-color);
    font-weight: 700;
    font-size: .62rem;
    letter-spacing: .04em;
    white-space: nowrap;
}
/* The summary sits above the table with its filter beside it, so the count and
   the way to act on it are one thing rather than two. */
.breed-translation-card {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    align-items: center;
    justify-content: space-between;
}
.breed-translation-card .settings-intro { margin: 0; }
.breed-translation-card .btn-premium.is-active {
    border-color: var(--accent-color);
    color: var(--accent-color);
}

/* "This one needs a person." Sits before the group tag and takes the auto
   margin when it is showing, so the pair stays against the right edge. */
.breed-status-tag {
    border-radius: var(--radius-sm);
    flex: 0 0 auto;
    margin-left: auto;
    padding: 0 0.375rem 0.0625rem 0.375rem;
    background: rgba(var(--color-important-rgb), .14);
    color: var(--color-important);
    font: 700 .68rem var(--font-display);
    letter-spacing: .04em;
    white-space: nowrap;
}
.breed-status-tag[hidden] { display: none; }
.breed-fci-note-error { color: var(--color-my-dogs); }
.breed-fci-note-warn { color: var(--color-important); }

/* The FCI card reads as a profile: portrait, official name, group and standard
   number on one line, the source link at its foot. Editing happens in a modal,
   so nothing here is a form control. */
.fci-profile {
    display: flex;
    align-items: flex-start;
    gap: 0.875rem;
    margin-top: 4px;
}
.fci-profile-photo {
    flex: 0 0 auto;
    width: 96px;
    height: 96px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--border-color);
    border-radius: 10px;
    background: var(--bg-overlay);
    overflow: hidden;
}
.fci-profile-photo img { width: 100%; height: 100%; object-fit: cover; }
.fci-profile-photo-empty { font-size: .68rem; color: var(--text-secondary); text-align: center; padding: 0 0.375rem; }
.fci-profile-facts {
    display: flex;
    flex-direction: column;
    gap: 0.375rem;
    min-width: 0;
}
/* Whose name it is, then the name. The label leads the line rather than sitting
   under the numbers, because "Podengo Português" is what the CPC calls this
   breed and the FCI would call it something else. */
.fci-profile-title {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 0.5rem;
    min-width: 0;
}
.fci-profile-title strong { font-size: 1rem; color: var(--text-primary); word-break: break-word; }
.fci-profile-title strong:empty::before { content: '—'; color: var(--text-secondary); }
.fci-profile-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 0.375rem 0.875rem;
    font-size: .78rem;
    color: var(--text-secondary);
}
.fci-profile-meta em { font-style: normal; font-weight: 600; color: var(--text-primary); }
.fci-profile-meta em:empty::before { content: '—'; font-weight: 400; color: var(--text-secondary); }
.fci-profile-hint { font-size: .72rem; color: var(--text-secondary); }
/* Whose standard this is, and the button that reads it — one line under the
   group and the number, because the name is what says which site Fetch asks. */
.fci-profile-standard {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.625rem;
    margin-top: 2px;
}
.fci-standard-name {
    font-size: .74rem;
    font-weight: 700;
    letter-spacing: .04em;
    color: var(--text-primary);
    background: var(--bg-overlay);
    border: 1px solid var(--border-color);
    border-radius: 6px;
    padding: 0.1875rem 0.5625rem;
}
.fci-profile-standard .btn-premium { width: auto; font-size: .72rem; padding: 0.4375rem 0.75rem; }
/* The undo is a form, so that it is a POST with a token like every other write.
   It still has to sit in the row as if it were just the button inside it. */
.fci-unlink-form { display: inline-flex; }
.fci-unlink-form[hidden] { display: none; }
.fci-profile-footer {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.625rem;
    margin-top: 16px;
    padding-top: 0.875rem;
    border-top: 1px solid var(--border-color);
}
.fci-profile-footer small { font-size: .7rem; color: var(--text-secondary); }
.fci-profile-footer .btn-premium { margin-left: auto; width: auto; font-size: .72rem; padding: 0.5625rem 0.8125rem; }
.fci-profile-link { font-size: .78rem; color: var(--accent-primary); text-decoration: none; }
.fci-profile-link:hover { text-decoration: underline; }
/* Group and standard number are one line in the editor too. */
.fci-form-row { display: flex; gap: 0.75rem; }
.fci-form-row > label { flex: 1 1 0; min-width: 0; }
.fci-remove-image {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: .78rem;
}
.fci-remove-image input { width: auto; margin: 0; }

/* FCI lookup: the verdict line, then the ranked matches when the FCI's
   "contains" search returned more than this breed. */
.fci-lookup-status {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    margin: 12px 0;
    padding: 0.625rem 0.75rem;
    border-radius: 8px;
    background: var(--bg-overlay);
    font-size: .78rem;
    color: var(--text-secondary);
}
.fci-lookup-status strong { color: var(--text-primary); font-size: .8rem; }
.fci-lookup-status small { font-size: .72rem; line-height: 1.4; word-break: break-word; }
.fci-lookup-ok strong { color: var(--accent-primary); }
.fci-lookup-warn strong { color: var(--color-my-dogs); }
.fci-lookup-error strong { color: var(--color-my-dogs); }
.fci-lookup-matches {
    display: flex;
    flex-direction: column;
    gap: 0.375rem;
    margin-bottom: 12px;
    max-height: 260px;
    overflow-y: auto;
}
.fci-match {
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
    width: 100%;
    padding: 0.5rem 0.625rem;
    border: 1px solid var(--border-color);
    border-radius: 8px;
    background: var(--bg-card);
    color: var(--text-primary);
    text-align: left;
    cursor: pointer;
}
.fci-match:hover { border-color: var(--accent-primary); }
.fci-match strong { font-size: .8rem; }
.fci-match small { font-size: .7rem; color: var(--text-secondary); }
.breed-name-link {
    color: inherit;
    text-decoration: none;
}
.breed-name-link:hover {
    color: var(--accent-primary);
}

@media (max-width: 768px) {
    .breed-edit-layout {
        /* minmax(0, …), not 1fr: a plain 1fr track cannot shrink below its
           content's min-content width, so anything wide inside a card — the
           alias table this once held, a long official name, an image — became
           the column's floor and pushed the whole page sideways on anything
           narrower. Wide content scrolls or wraps inside its own card instead. */
        grid-template-columns: minmax(0, 1fr);
    }
}

/* Pull to Refresh */
.ptr-indicator {
    position: fixed;
    top: -50px;
    left: 0;
    width: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    height: 50px;
    z-index: var(--z-notice);
    pointer-events: none;
    transition: transform 0.2s ease;
}
.ptr-indicator .ptr-box {
    background: var(--bg-card);
    box-shadow: var(--shadow-premium);
    border-radius: 50%;
    width: 40px;
    height: 40px;
    display: flex;
    justify-content: center;
    align-items: center;
    color: var(--text-primary);
    font-size: 1.2rem;
    transition: transform 0.2s ease;
    border: 1px solid var(--border-color);
}
.ptr-indicator.ptr-ready .ptr-box {
    transform: rotate(180deg);
}
.ptr-indicator.ptr-loading .ptr-box {
    animation: ptr-spin 1s linear infinite;
    transform: rotate(0deg);
}
@keyframes ptr-spin {
    100% { transform: rotate(360deg); }
}


/* --- Users Bulk Actions & FAB --- */
.checkbox-col {
    width: 25px;
    text-align: center;
}

.users-table tbody tr.row-selected {
    background-color: rgba(var(--accent-primary-rgb), 0.1);
}

.bulk-fab-container {
    position: fixed;
    bottom: 100px;
    right: 24px;
    z-index: var(--z-modal);
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 0.5rem;
    opacity: 0;
    pointer-events: none;
    transform: translateY(20px) scale(0.9);
    transition: opacity 0.3s ease, transform 0.3s ease;
}

.bulk-fab-container.visible {
    opacity: 1;
    pointer-events: auto;
    transform: translateY(0) scale(1);
}

.bulk-fab-trigger {
    width: 56px;
    height: 56px;
    border-radius: 50%;
    background-color: var(--accent-primary);
    color: #fff;
    border: none;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: transform 0.2s, background-color 0.2s;
}

.bulk-fab-trigger:hover, .bulk-fab-trigger:focus-visible {
    background-color: var(--accent-primary);
    transform: scale(1.05);
}

.bulk-fab-trigger:active {
    transform: scale(0.95);
}

.bulk-fab-menu {
    background-color: var(--bg-card);
    border: 1px solid var(--border-color);
    border-radius: 12px;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    min-width: 150px;
}

.bulk-menu-item {
    background: none;
    border: none;
    padding: 0.75rem 1rem;
    text-align: left;
    color: var(--text-primary);
    font: inherit;
    font-size: 0.875rem;
    font-weight: 500;
    cursor: pointer;
    transition: background-color 0.2s;
    width: 100%;
}

.bulk-menu-item:hover {
    background-color: var(--bg-surface);
}

.bulk-menu-danger {
    color: var(--color-my-dogs);
}

.bulk-menu-danger:hover {
    background-color: rgba(var(--color-my-dogs-rgb), 0.1);
}

/* --- User Card Modal --- */
.user-card-trigger {
    background: none;
    border: none;
    padding: 0;
    color: var(--text-primary);
    font: inherit;
    font-weight: 600;
    cursor: pointer;
    text-decoration: underline;
    text-decoration-color: transparent;
    transition: text-decoration-color 0.2s;
}

.user-card-trigger:hover {
    text-decoration-color: var(--accent-primary);
}

.user-card-container {
    max-width: 400px;
}

.user-card-header {
    display: flex;
    align-items: center;
    gap: 1rem;
    margin-bottom: 24px;
}

.user-card-avatar {
    width: 64px;
    height: 64px;
    border-radius: 50%;
    overflow: hidden;
    flex-shrink: 0;
    background-color: var(--bg-base);
    border: 1px solid var(--border-color);
}

.user-card-avatar img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.avatar-placeholder {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.5rem;
    font-weight: bold;
    color: var(--text-secondary);
}

.user-card-info {
    flex-grow: 1;
}

.user-card-name {
    margin: 0 0 4px 0;
    font-size: 1.125rem;
    color: var(--text-primary);
}

.user-card-email {
    font-size: 0.875rem;
    color: var(--text-secondary);
}

.user-card-details {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

.user-card-detail-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0.75rem;
    background-color: var(--bg-base);
    border-radius: 8px;
    border: 1px solid var(--border-color);
}

.detail-label {
    font-size: 0.875rem;
    color: var(--text-secondary);
}

.detail-value {
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--text-primary);
}

.user-badge {
    padding: 0.25rem 0.5rem;
    border-radius: 12px;
    font-size: 0.75rem;
    font-weight: 600;
}

.user-badge.verified {
    background-color: rgba(var(--color-friends-rgb), 0.1);
    color: var(--color-friends);
}

.user-badge.pending {
    background-color: rgba(var(--color-important-rgb), 0.1);
    color: var(--color-important);
}

/* ==========================================================================
   Version history (/versionlog/)
   Rendered from settings/changelog.php. The page used to carry these rules as
   inline styles emitted by a markdown pass in PHP.
   ========================================================================== */
.changelog { margin-top: 20px; }

.changelog-title {
    font-family: var(--font-display);
    font-weight: 800;
    margin-bottom: 20px;
    padding-bottom: 0.625rem;
    border-bottom: 1px solid var(--border-color);
}

.changelog-release + .changelog-release { margin-top: 28px; }

.changelog-version {
    display: flex;
    align-items: baseline;
    gap: 0.625rem;
    font-family: var(--font-display);
    font-weight: 700;
    color: var(--accent-primary);
    margin-bottom: 10px;
}

.changelog-version time {
    font-family: var(--font-body);
    font-size: 0.8rem;
    font-weight: 400;
    color: var(--text-secondary);
}

.changelog-changes {
    padding-left: 1.25rem;
    margin: 0;
}

.changelog-changes li {
    margin-bottom: 8px;
    color: var(--text-secondary);
    line-height: 1.5;
}

.changelog-empty { color: var(--text-secondary); }
.changelog-lede { color: var(--text-secondary); font-size: .88rem; line-height: 1.6; margin: 0 0 18px; }
.info-build { color: var(--text-primary); font: 700 .95rem var(--font-display); margin: 0 0 6px; }

/* The build log: one card per deploy. */
.build-entry + .build-entry { margin-top: 12px; }
.build-head { align-items: baseline; display: flex; flex-wrap: wrap; gap: 0.625rem; }
.build-head strong { font: 700 1rem var(--font-display); }
.build-version { background: rgba(var(--accent-primary-rgb), .12); border-radius: var(--radius-sm); color: var(--accent-primary); font: 700 .78rem var(--font-display); padding: 0.125rem 0.5rem; }
.build-head time, .build-count { color: var(--text-muted); font-size: .78rem; }
/* Check source: the icon turns while the request is out, and the verdict stays
   beside the button with its evidence folded away behind it. */
.expo-show-check.is-checking .action-icon { animation: expo-check-spin 1s linear infinite; transform-origin: 50% 50%; }
@keyframes expo-check-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
    /* A turning icon is the only sign the press was heard, so it does not stop
       moving -- it pulses instead of spinning. */
    .expo-show-check.is-checking .action-icon { animation: expo-check-pulse 1.4s ease-in-out infinite; }
    @keyframes expo-check-pulse { 50% { opacity: .35; } }
}
.expo-check-result { align-items: baseline; display: inline-flex; flex-wrap: wrap; font-size: .78rem; gap: 0.5rem; }
.expo-check-result strong { font: 700 .78rem var(--font-display); }
.expo-check-result[data-check-verdict="unchanged"] strong { color: var(--color-friends); }
.expo-check-result[data-check-verdict="changed"] strong { color: var(--accent-primary); }
.expo-check-result[data-check-verdict="error"] strong { color: var(--color-my-dogs); }
.expo-check-result[data-check-verdict="idle"] strong { color: var(--text-muted); }
.expo-check-detail summary { color: var(--text-muted); cursor: pointer; }
.expo-check-detail ul { color: var(--text-muted); font-size: .74rem; line-height: 1.5; margin: 6px 0 0; padding-left: 1rem; }
.expo-check-detail li { overflow-wrap: anywhere; }
/* The check's evidence sits in the card body, below the sticky header, so the
   fold-out grows the card and pushes the day list down instead of painting over
   it. Its own strip so the boundary reads. */
.expo-check-evidence { padding: 0.625rem 0.9375rem; background: var(--bg-elevated, var(--tint-subtle)); border-bottom: 1px solid var(--border-color); }
.expo-check-evidence:empty { display: none; }
.expo-check-evidence .expo-check-detail summary { font-size: .8rem; font-weight: 600; }

.build-note { color: var(--text-secondary); font-size: .86rem; line-height: 1.55; margin: 10px 0 0; padding-left: 1.125rem; }
.build-note li + li { margin-top: 4px; }
.build-headline { color: var(--text-muted); font-size: .78rem; margin: 8px 0 0; }
.build-notes-heading { color: var(--text-muted); font: 700 .72rem var(--font-display); letter-spacing: .1em; margin: 14px 0 6px; text-transform: uppercase; }
.build-notes { color: var(--text-secondary); font-size: .84rem; line-height: 1.55; margin: 0; padding-left: 1.125rem; }
.build-notes-internal { color: var(--text-muted); }
.build-files { margin-top: 12px; }
.build-files summary { color: var(--text-secondary); cursor: pointer; font-size: .8rem; }
.build-files ul { color: var(--text-muted); font-family: var(--font-mono, monospace); font-size: .76rem; line-height: 1.5; margin: 8px 0 0; padding-left: 1.125rem; }
.settings-empty { color: var(--text-secondary); }

.changelog-foot {
    margin-top: 30px;
    padding-top: 1.25rem;
    border-top: 1px solid var(--border-color);
    text-align: center;
}

.changelog-foot .btn-premium { width: auto; padding: 0.625rem 1.5rem; }

/* Remote page probe (Settings → Debug). The body panel holds somebody else's
   markup as plain text, so it scrolls on both axes rather than reflowing. */
.probe-table { border-collapse: collapse; font-size: .82rem; margin-top: 16px; width: 100%; }
.probe-table th,
.probe-table td { border-bottom: 1px solid var(--border-color); padding: 0.4375rem 0.625rem; text-align: left; vertical-align: top; }
.probe-table th { color: var(--text-muted); font-weight: 600; white-space: nowrap; width: 34%; }
.probe-table td { color: var(--text-secondary); word-break: break-word; }
/* The reachability bench is a wide, many-column table, not the probe's two-column
   key/value list, so its header cells are not a fixed third of the width. Each
   entrance opens with a full-width title row above its metrics. */
.cpc-bench-table th { width: auto; white-space: nowrap; }
.cpc-bench-table .cpc-bench-head td { border-top: 2px solid var(--border-color); padding-top: 0.75rem; }
.cpc-bench-table .cpc-bench-head strong { color: var(--text-primary, var(--text-secondary)); }
.cpc-bench-table .cpc-bench-head small { color: var(--text-muted); font-weight: 400; }
/* Why a rung did not serve the page, under its title. It is the half of the
   answer the verdict column has no room for. */
.cpc-bench-table .cpc-bench-why { color: var(--color-my-dogs); font-size: .72rem; font-weight: 400; line-height: 1.45; margin-top: 4px; }
.probe-body {
    background: var(--bg-base);
    border: 1px solid var(--border-color);
    border-radius: 8px;
    color: var(--text-secondary);
    font: .72rem/1.5 monospace;
    max-height: 420px;
    overflow: auto;
    padding: 0.75rem;
    white-space: pre-wrap;
    word-break: break-word;
}

/* A judge's country: the flag for recognition, the code because several flags
   are indistinguishable at this size. Printed inline after the name. */
.judge-flag {
    align-items: center;
    display: inline-flex;
    gap: 0.25rem;
    margin-left: 7px;
    vertical-align: baseline;
    white-space: nowrap;
}
.judge-flag-glyph { font-size: 1.05em; line-height: 1; }
.judge-flag-code {
    background: rgba(var(--border-color-rgb), .55);
    border-radius: 4px;
    color: var(--text-muted);
    font: 600 .68rem/1 monospace;
    letter-spacing: .04em;
    padding: 0.1875rem 0.25rem;
}
.judge-card-identity h2 .judge-flag { margin-left: 8px; }

/* The show that has just finished. Shaded rather than hidden: it is behind you,
   but for a few days it is still the one being looked up. */
.recent-show-bar { opacity: .62; }
.recent-show-bar:hover,
.recent-show-bar:focus-within { opacity: 1; }
.schedule-past-badge {
    background: var(--bg-overlay);
    border-radius: 4px;
    color: var(--text-muted);
    display: inline-block;
    font-size: .65rem;
    font-weight: 800;
    letter-spacing: .05em;
    line-height: 1;
    margin-left: 8px;
    padding: 0.125rem 0.375rem;
    text-transform: uppercase;
    vertical-align: middle;
}
/* The show that has just finished is lifted out of the folded block, so it is
   already in a place of its own. It needs no dimming to say it is over — the
   tick at its front says that. */

/* Reordering a ring (root, table view): the whole row is the handle. Nothing
   saves on drop — the bar below and its confirmation do — so the row needs no
   extra column and the breed keeps the width. */
tr.schedule-row-dragging { opacity: .5; }
tr.schedule-row-dragging td { background: var(--bg-overlay); }

/* CPC Challenge: the entrance list is dragged the same way, and says so — the
   row is the grip, so the cursor has to admit that before anyone tries. While a
   drag is running, text selection would fight the finger. */
[data-cpc-sources][data-reorderable="1"] .debug-mode-switch { cursor: grab; }
[data-cpc-sources].cpc-sources-dragging { user-select: none; }
[data-cpc-sources].cpc-sources-dragging .debug-mode-switch { cursor: grabbing; }
.debug-mode-switch.cpc-source-dragging { background: var(--bg-overlay); border-radius: 10px; opacity: .6; }

/* "Changed and not saved", perched on the bottom navigation like the offline
   banner: visible wherever the operator has scrolled to, gone when the order
   is dragged back to where it started. */
.reorder-panel {
    align-items: center;
    background: var(--bg-card);
    border-top: 1px solid var(--accent-primary);
    display: flex;
    gap: 0.75rem;
    justify-content: center;
    left: 0;
    padding: 0.625rem 0.875rem;
    position: fixed;
    right: 0;
    z-index: var(--z-notice);
}
.reorder-panel span { color: var(--text-primary); font: 600 .82rem var(--font-display); }
.reorder-panel .btn-premium { flex: 0 0 auto; width: auto; }
.reorder-question { font-weight: 700; margin-top: 12px; }

/* Deciding between names nobody could choose between automatically.
   One card per breed, one block per language, because that is the shape the
   question has: "what is this breed called in Ukrainian, given these." The two
   quiet actions are deliberately quiet — taking a name is the common answer and
   the only one that should read as a button. */
.breed-review-summary .settings-intro { margin: 0; }

.breed-review-card { margin-bottom: 16px; }

.breed-review-head {
    padding-bottom: 0.75rem;
    border-bottom: 1px solid var(--border-color);
}
.breed-review-head .settings-card-title { margin-bottom: 4px; }
/* The mapping's explanation, said once for the breed rather than repeated
   under every language it proposed. */
.breed-review-note {
    margin: 6px 0 0;
    color: var(--text-muted);
    font-size: .78rem;
    line-height: 1.45;
}

.breed-review-lang { padding: 0.75rem 0; }
.breed-review-lang + .breed-review-lang { border-top: 1px solid var(--border-color); }
.breed-review-lang-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    margin-bottom: 10px;
}
/* "None of these" is one of the answers, so it sits with the question rather
   than at the bottom of the page. */
.breed-review-dismiss { margin: 0; }

.breed-review-option {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.625rem;
    padding: 0.625rem 0.75rem;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm, 8px);
    background: rgba(var(--bg-overlay-rgb), .35);
}
.breed-review-option + .breed-review-option { margin-top: 8px; }

.breed-review-option-body { min-width: 0; }
.breed-review-name {
    display: block;
    font-family: var(--font-display, inherit);
    font-size: 1rem;
    line-height: 1.3;
}
.breed-review-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-top: 3px;
    color: var(--text-muted);
    font-size: .72rem;
}
.breed-review-source { color: var(--text-secondary); }

.breed-review-confidence {
    font-weight: 700;
    letter-spacing: .03em;
    text-transform: uppercase;
}
.breed-review-confidence-certain { color: #10B981; }
.breed-review-confidence-likely  { color: var(--accent-primary); }
.breed-review-confidence-unsure  { color: var(--text-muted); }

/* .btn-premium is width:100% for the full-width forms it was written for, so
   the buttons in a row have to opt out or each one fills its own line. */
.breed-review-option-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}
.breed-review-option-actions form,
.breed-review-dismiss { flex: 0 0 auto; }
.breed-review-option-actions .btn-premium,
.breed-review-dismiss .btn-premium {
    width: auto;
    padding: 0.5rem 0.875rem;
    font-size: .78rem;
}

/* A third weight below secondary: bordered but not filled, for the answers that
   should be available without inviting a click. */
.btn-premium-ghost {
    background: transparent;
    color: var(--text-secondary);
    border: 1px solid var(--border-color);
}
.btn-premium-ghost:hover {
    background: rgba(var(--bg-overlay-rgb), .6);
    color: var(--text-primary);
}

@media (max-width: 520px) {
    /* The name and its answers stop competing for one line. */
    .breed-review-option { flex-direction: column; align-items: stretch; }
    .breed-review-option-actions { justify-content: flex-start; }
}

/* "None of the above, and I know what it should be." Last in the block because
   it is the least common answer, and present in every block because a shortlist
   being wrong about the variety is not rare. */
.breed-review-own {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin: 10px 0 0;
}
.breed-review-own input[type="text"] {
    flex: 1 1 200px;
    min-width: 0;
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    background: var(--bg-surface);
    color: var(--text-primary);
    font-size: .85rem;
}
.breed-review-own input[type="text"]:focus {
    border-color: var(--accent-primary);
    outline: none;
}
.breed-review-own .btn-premium {
    width: auto;
    flex: 0 0 auto;
    padding: 0.5rem 0.875rem;
    font-size: .78rem;
}

/* --- Feedback: the public form and the operator's inbox ------------------- */

.info-card + .info-card { margin-top: 16px; }
.info-card p { color: var(--text-secondary); font-size: .88rem; line-height: 1.6; margin: 0 0 10px; }
.info-card .info-lede { color: var(--text-primary); }
.info-card .info-note { color: var(--text-muted); font-size: .8rem; }
.info-card .section-header { margin-top: 0; }
.info-roadmap { color: var(--text-secondary); font-size: .88rem; line-height: 1.6; margin: 0 0 12px; padding-left: 1.25rem; }
.info-roadmap li { margin-bottom: 6px; }

/* The welcome card, while it is standing inside the dialog. The dialog already
   provides the surface, the border and the padding, so the card drops all
   three, and its own heading gives way to the dialog's title rather than
   printing the same words twice. In the page it is an ordinary card again —
   none of this applies there, which is the point of moving the node instead of
   restyling it. */
.modal-body .shows-intro-card {
    background: none;
    border: 0;
    box-shadow: none;
    padding: 0;
    margin: 0;
}
.modal-body .shows-intro-card .section-header { display: none; }
.shows-intro-dismiss { width: 100%; margin-top: 4px; }
.feedback-field { margin-bottom: 14px; }
.feedback-card .page-action-bar { margin-top: 4px; }
.feedback-reply-to { color: var(--text-muted); font-size: .82rem; margin: 0 0 14px; }
/* The honeypot. Off the page rather than display:none, because a bot that
   checks for a hidden field skips a hidden one and fills this. */
.feedback-company { height: 0; left: -9999px; overflow: hidden; position: absolute; width: 0; }

.feedback-filters { margin-bottom: 14px; }

.feedback-entry {
    border: 1px solid var(--border-color);
    border-radius: 10px;
    margin-bottom: 12px;
    padding: 0.75rem 0.875rem;
}
/* A closed entry recedes; a new one carries the accent edge. */
.feedback-entry-new { border-left: 3px solid var(--accent-primary); }
.feedback-entry-done { opacity: .55; }
.feedback-entry-head {
    align-items: baseline;
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-bottom: 8px;
}
.feedback-kind-tag {
    background: rgba(var(--accent-primary-rgb), .12);
    border-radius: 6px;
    color: var(--accent-primary);
    font: 700 .68rem var(--font-display);
    letter-spacing: .04em;
    padding: 0.125rem 0.5rem;
    text-transform: uppercase;
}
.feedback-entry-meta { color: var(--text-muted); font-size: .75rem; }
.feedback-entry-message { font-size: .88rem; margin: 0 0 8px; white-space: pre-line; }
.feedback-entry-contact { color: var(--text-secondary); font-size: .78rem; margin: 0 0 8px; }

/* --- Usage: daily table and the hour bars --------------------------------- */

.usage-table { border-collapse: collapse; font-size: .82rem; width: 100%; }
.usage-table th {
    color: var(--text-muted);
    font: 700 .68rem var(--font-display);
    letter-spacing: .05em;
    padding: 0.375rem 0.5rem;
    text-align: left;
    text-transform: uppercase;
}
.usage-table td { border-top: 1px solid var(--border-color); padding: 0.375rem 0.5rem; }
.usage-table a { color: var(--accent-primary); text-decoration: none; }

.usage-hours { display: grid; gap: 0.1875rem; }
.usage-hour-row { align-items: center; display: grid; gap: 0.5rem; grid-template-columns: 24px 1fr 40px; }
.usage-hour-label { color: var(--text-muted); font-size: .7rem; text-align: right; }
.usage-hour-bar {
    background: var(--accent-primary);
    border-radius: 3px;
    display: block;
    height: 10px;
    min-width: 0;
    opacity: .8;
}
.usage-hour-count { font-size: .72rem; }

/* --- Who was here, on a day of the usage page ------------------------------- */

.usage-subheading { color: var(--text-primary); font: 700 .82rem var(--font-display); letter-spacing: .04em; margin: 22px 0 10px; text-transform: uppercase; }
/* The address under the name: the display name is what an operator recognises,
   the address is what tells two Marias apart. */
.usage-person-email { color: var(--text-muted); display: block; font-size: .72rem; font-weight: 400; }
.usage-person-window { color: var(--text-muted); white-space: nowrap; }
/* The tail is a summary, not a person, and reads as one. */
.usage-person-rest td { color: var(--text-muted); font-style: italic; }

/* --- Corrections journal --------------------------------------------------- */

/* Wide table, narrow phone: the table scrolls inside its card, the page never. */
.usage-table-scroll { overflow-x: auto; }
.correction-action { font-weight: 600; }
.corrections-filters { margin-bottom: 14px; }

/* --- Offline banner -------------------------------------------------------- */

/* Sits on the bottom navigation's shoulder, not over the header: the header
   carries the brand, the clock and the account, and a banner across it hid all
   three. app.js sets the exact bottom offset from the navigation's own height,
   so the two never overlap whatever the safe-area inset adds. */
.offline-banner {
    background: var(--color-important, #F59E0B);
    bottom: 0;
    color: #1a1a1a;
    font: 700 .78rem var(--font-display);
    left: 0;
    letter-spacing: .03em;
    padding: 0.4375rem 0.875rem;
    position: fixed;
    right: 0;
    text-align: center;
    z-index: var(--z-notice);
}

/* --- Country visibility table --------------------------------------------- */

.countries-table-wrap {
    overflow-x: auto;
    margin-top: 1rem;
    margin-bottom: 1.5rem;
}
.countries-table {
    width: 100%;
    border-collapse: collapse;
}
.countries-table th,
.countries-table td {
    padding: 0.75rem 1rem;
    border-bottom: 1px solid var(--border-color, rgba(255, 255, 255, 0.1));
    text-align: left;
}
.countries-table th {
    font-weight: 600;
    color: var(--text-secondary);
    font-size: 0.85rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}
.countries-table .cell-center {
    text-align: center;
}
.countries-actions {
    display: flex;
    justify-content: flex-end;
    margin-top: 1rem;
}

/* --- Expositions country filter and card header --------------------------- */

.country-filter-form {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    margin-left: 0.75rem;
}
.country-filter-label {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-weight: 600;
    color: var(--text-secondary);
    font-size: 0.9rem;
}
.country-select {
    background: var(--bg-card, rgba(255, 255, 255, 0.05));
    border: 1px solid var(--border-color, rgba(255, 255, 255, 0.15));
    border-radius: 6px;
    color: var(--text-primary);
    padding: 0.35rem 0.75rem;
    font-size: 0.9rem;
    cursor: pointer;
}
.country-single-name {
    font-weight: 700;
    font-size: 1.1rem;
    color: var(--text-primary);
}
.season-source-title {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
}
.season-source-external-link {
    display: inline-flex;
    align-items: center;
    color: var(--text-secondary);
    transition: color 0.15s ease;
}
.season-source-external-link:hover {
    color: var(--accent-primary);
}
.season-source-external-link svg {
    width: 1.1rem;
    height: 1.1rem;
}


