/* =====================================================================
   BixConnect — the shell and the design system.

   This file is the implementation of docs/DESIGN.md. It used to live
   inline in templates/base.html (35 KB on every page, never cached); it
   moved here on 2026-08-23. The link in base.html carries a content hash
   (core.context_processors.static_version) so a change here reaches every
   browser on the next load and is cached until the next change.

   Every class name the 100+ page templates use (.card, .page-header,
   .data-table, .metric-grid, .btn-*, .badge-*, .form-*, .flash-*,
   .detail-columns, .mobile-section …) is defined here; keep them.
   ===================================================================== */
/* Inter, the face the direction is drawn in, as bytes in the repo - the rule
   WO-070 set for the letterhead's two. One file: the Google Fonts latin
   subset, variable on the wght axis, so 400 through 700 is one request and
   no page asks a font host in another country for anything. */
@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 400 700;
    font-display: swap;
    src: url('../fonts/Inter-latin.woff2') format('woff2');
}
/* WO-077 item 7: Bricolage Grotesque, the Reports display face - headings
   and the big figures on Rates; Inter stays for data. The Google Fonts latin
   subset, variable 400 to 700 on wght and on the optical size, OFL
   (static/fonts/BricolageGrotesque-OFL.txt). A page that uses it preloads it;
   base preloads only Inter, which every page uses. */
@font-face {
    font-family: 'Bricolage Grotesque';
    font-style: normal;
    font-weight: 400 700;
    font-display: swap;
    src: url('../fonts/BricolageGrotesque-latin.woff2') format('woff2');
}

/* The kit (WO-071 item 1). The approved boards are in
   `Managment_System/ui-direction/`; these are the palette, the scale and the
   spacing they are drawn on, and `core/tests/test_kit.py` pins them.

   The scale is six sizes and no seventh - eyebrow, caption, body, lead, title,
   figure. The rule the old screens broke everywhere was the last one: a title
   at 20px over the number it was about at 15. A figure is the largest thing on
   its card, or the card is a paragraph. */
:root {
    --navy: #14203D;
    --navy-deep: #0E172E;
    --navy-light: #1B2A4E;
    --navy-lighter: #243560;
    /* Two golds where there were three. `--gold` is the brand's: a fill, an
       edge, and gold on navy. `--gold-ink` is the only one that may carry text
       on white - `--gold` is 2.56:1 there, which is the whole reason the old
       `--gold-dark` existed. `--gold-bg` is the ground they sit on. */
    --gold: #C89B3C;
    --gold-ink: #8B6A22;
    --gold-bg: #FBF3E1;
    --ink: #151A24;
    --ink-2: #3B4354;
    --muted: #6B7382;
    --muted-light: #9AA3B2;
    --border: #E6E9EF;
    --border-strong: #D8DDE6;
    --bg: #F5F6F9;
    --surface: #FFFFFF;
    --surface-2: #F9FAFB;
    /* Six status pairs: a colour and the ground it sits on. Status is a
       colour before it is a word, so every one of them needs both. */
    --success: #188A4A;
    --success-bg: #E7F6EC;
    --danger: #D2413F;
    --danger-bg: #FCECEB;
    --warning: #B7791F;
    --warning-bg: #FCF3DC;
    --info: #2A63B3;
    --info-bg: #E9F1FC;
    --neutral: #3B4354;
    --neutral-bg: #EEF0F4;
    /* Type. */
    --fs-eyebrow: 11px;
    --fs-small: 12.5px;
    --fs-body: 13.5px;
    --fs-lead: 15px;
    --fs-title: 24px;
    --fs-figure: 28px;
    --fw-figure: 600;
    --num: tabular-nums;
    /* Spacing - every gap, pad and margin in the kit is one of these six. */
    --sp-1: 4px;
    --sp-2: 8px;
    --sp-3: 12px;
    --sp-4: 16px;
    --sp-5: 22px;
    --sp-6: 30px;
    --radius: 14px;
    --radius-sm: 9px;
    --shadow-sm: 0 1px 2px rgba(20,32,61,0.04), 0 8px 24px rgba(20,32,61,0.05);
    --shadow-md: 0 12px 30px rgba(16,26,51,0.10);
    --shadow-lg: 0 18px 48px rgba(8,15,31,0.22);
    --sidebar-w: 232px;
    --sidebar-rail: 76px;
    --topbar-h: 54px;
    --tabbar-h: 62px;
    --serif: Didot, 'Bodoni MT', 'Playfair Display', 'Palatino Linotype', Georgia, 'Times New Roman', serif;
    --sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
    /* The Reports display face (WO-077 item 7): headings and big figures. */
    --display: 'Bricolage Grotesque', var(--sans);
    /* The kit's easing for a thing arriving (WO-077 item 7b). */
    --motion-ease: cubic-bezier(.2, .8, .2, 1);
}

* { box-sizing: border-box; }
/* The hidden attribute must always win. Any element whose class sets its own
   display (.btn is inline-flex) would otherwise ignore it - which is how a
   "Take a photo" button meant for phones appeared on desktops. */
[hidden] { display: none !important; }
html { -webkit-text-size-adjust: 100%; }

body {
    font-family: var(--sans);
    background: var(--bg);
    margin: 0;
    color: var(--ink);
    line-height: 1.5;
    font-size: var(--fs-body);
    -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 { color: var(--navy); letter-spacing: -0.018em; margin-top: 0; line-height: 1.25; }
h3 { font-size: 1.08rem; }
a { color: var(--info); }
svg { flex-shrink: 0; }
code { font-size: 0.9em; background: var(--neutral-bg); padding: 1px 5px; border-radius: 4px; }

/* ---------------- Layout frame ---------------- */
.app { display: flex; min-height: 100vh; min-height: 100dvh; }
.app-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.container { width: 100%; max-width: 1320px; margin: 0 auto; padding: 28px 32px 48px; }
.app-main > .container { flex: 1; }
/* WO-074 item 1. The skip link sits above the page until a keyboard reaches
   it; the screen's heading and `main` take focus from shell.js after a load,
   which is a place to start reading, not a control, so it draws no ring. */
.skip-link { position: absolute; left: 12px; top: -64px; z-index: 1000; padding: 10px 16px; border-radius: 8px; background: var(--navy); color: #fff; font-weight: 600; text-decoration: none; }
.skip-link:focus { top: 12px; }
#content:focus, #content [tabindex="-1"]:focus { outline: none; }
/* WO-074 item 3. Every screen is its own document, and a menu click painted
   the sidebar and the top bar again from nothing around a new middle - the
   "refresh" the owner sees. A cross-document view transition holds the shell:
   both are named, so each is carried across as itself (the same place on
   both pages, so nothing moves) while the rest cross-fades in 150 ms. The
   phone's tab bar is the same shell at 390. Chrome, Edge and Safari; Firefox
   loads the page as before, and so does anyone who asked for less motion. */
@media (prefers-reduced-motion: no-preference) {
    @view-transition { navigation: auto; }
    .sidebar { view-transition-name: bx-sidebar; }
    .topbar { view-transition-name: bx-topbar; }
    .tabbar { view-transition-name: bx-tabbar; }
    ::view-transition-group(*) { animation-duration: 150ms; }
}

/* ---------------- Sidebar ---------------- */
.sidebar {
    position: sticky; top: 0;
    width: var(--sidebar-w);
    height: 100vh; height: 100dvh;
    flex: 0 0 var(--sidebar-w);
    display: flex; flex-direction: column;
    background: linear-gradient(180deg, #131E3A 0%, var(--navy-deep) 100%);
    color: rgba(255,255,255,0.82);
    border-right: 1px solid rgba(255,255,255,0.06);
    z-index: 30;
    transition: width 0.18s ease, flex-basis 0.18s ease;
}
.sidebar::before {
    /* The login's starfield, very faintly, so the two halves of the
       app feel like one building. */
    content: ''; position: absolute; inset: 0; pointer-events: none;
    background:
        radial-gradient(circle at 18% 12%, rgba(227,194,122,0.10), transparent 28%),
        radial-gradient(circle at 80% 90%, rgba(255,255,255,0.04), transparent 30%);
}
.sidebar > * { position: relative; }

.sidebar-head {
    display: flex; align-items: center; gap: 12px;
    padding: 18px 18px 14px;
}
.brand {
    display: flex; align-items: center; gap: 11px;
    color: #fff; text-decoration: none; min-width: 0; flex: 1;
}
.brand-mark {
    width: 38px; height: 38px; flex: 0 0 38px;
    display: grid; place-items: center;
    border: 1px solid rgba(227,194,122,0.55);
    border-radius: 11px;
    background: radial-gradient(circle at 30% 20%, rgba(227,194,122,0.22), rgba(227,194,122,0.04));
    box-shadow: inset 0 0 0 4px rgba(14,23,46,0.6), 0 0 0 1px rgba(227,194,122,0.18);
    font-family: var(--serif); font-size: 20px; color: var(--gold); line-height: 1;
}
.brand-copy { display: flex; flex-direction: column; line-height: 1.05; min-width: 0; }
.brand-copy strong { font-size: 1.02rem; font-weight: 700; letter-spacing: 0.2px; }
.brand-copy small {
    margin-top: 4px; color: rgba(255,255,255,0.48);
    font-size: 0.6rem; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase;
}
.sidebar-close {
    display: none; background: none; border: none; color: rgba(255,255,255,0.7);
    width: 38px; height: 38px; border-radius: 9px; cursor: pointer; place-items: center;
}
.sidebar-close:hover { background: rgba(255,255,255,0.08); color: #fff; }

/* Hotel switcher */
.hotel-switch { position: relative; margin: 4px 12px 10px; }
.hotel-switch-btn {
    width: 100%; display: flex; align-items: center; gap: 11px;
    padding: 10px 11px; border-radius: 12px; cursor: pointer; text-align: left;
    background: rgba(255,255,255,0.05);
    border: 1px solid rgba(255,255,255,0.09);
    color: #fff; font: inherit;
    transition: background 0.15s ease, border-color 0.15s ease;
}
.hotel-switch-btn:hover, .hotel-switch.open .hotel-switch-btn {
    background: rgba(255,255,255,0.09); border-color: rgba(227,194,122,0.45);
}
.hotel-avatar {
    width: 36px; height: 36px; flex: 0 0 36px; border-radius: 10px;
    display: grid; place-items: center;
    background: linear-gradient(135deg, var(--gold) 0%, var(--gold-ink) 100%);
    color: var(--navy-deep); font-weight: 800; font-size: 0.8rem; letter-spacing: 0.04em;
}
.hotel-switch-copy { flex: 1; min-width: 0; line-height: 1.2; }
.hotel-switch-copy small {
    display: block; font-size: 0.62rem; font-weight: 700; letter-spacing: 0.12em;
    text-transform: uppercase; color: rgba(227,194,122,0.85); margin-bottom: 3px;
}
.hotel-switch-copy span {
    display: block; font-weight: 650; font-size: 0.88rem;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.hotel-switch-btn .caret { color: rgba(255,255,255,0.5); transition: transform 0.15s ease; }
.hotel-switch.open .hotel-switch-btn .caret { transform: rotate(180deg); }
.hotel-menu {
    display: none; position: absolute; left: 0; right: 0; top: calc(100% + 6px); z-index: 40;
    padding: 6px; border-radius: 12px;
    background: #fff; border: 1px solid var(--border); box-shadow: var(--shadow-lg);
    color: var(--ink);
}
.hotel-switch.open .hotel-menu { display: block; }
.hotel-menu-label { padding: 8px 10px 4px; font-size: 0.68rem; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase; color: var(--muted); }
.hotel-menu form { margin: 0; }
.hotel-menu button, .hotel-menu a {
    width: 100%; display: flex; align-items: center; gap: 10px;
    padding: 9px 10px; border-radius: 8px; border: none; background: none;
    font: inherit; font-size: 0.9rem; font-weight: 600; color: var(--ink);
    text-align: left; cursor: pointer; text-decoration: none;
}
.hotel-menu button:hover, .hotel-menu a:hover { background: var(--bg); }
.hotel-menu .hotel-avatar { width: 30px; height: 30px; flex-basis: 30px; border-radius: 8px; font-size: 0.7rem; }
.hotel-menu .hotel-menu-all { color: var(--muted); font-weight: 600; border-top: 1px solid var(--border); border-radius: 0 0 8px 8px; margin-top: 4px; padding-top: 11px; }

/* Navigation tree */
.sidebar-nav {
    flex: 1; overflow-y: auto; overscroll-behavior: contain;
    padding: 4px 12px 12px;
    scrollbar-width: thin; scrollbar-color: rgba(255,255,255,0.18) transparent;
}
.sidebar-nav::-webkit-scrollbar { width: 6px; }
.sidebar-nav::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.16); border-radius: 6px; }

.nav-link, .nav-toggle {
    position: relative;
    display: flex; align-items: center; gap: 10px;
    width: 100%; min-height: 36px; padding: 7px 10px;
    border-radius: var(--radius-sm); border: none; background: none;
    color: rgba(255,255,255,0.74); text-decoration: none;
    font: inherit; font-size: 13px; font-weight: 550; text-align: left;
    cursor: pointer;
    transition: background 0.12s ease, color 0.12s ease;
}
.nav-link:hover, .nav-toggle:hover { background: rgba(255,255,255,0.07); color: #fff; }
.nav-link .nav-ico, .nav-toggle .nav-ico { width: 17px; height: 17px; opacity: 0.9; }
.nav-link span, .nav-toggle span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.nav-link.active {
    background: linear-gradient(90deg, rgba(200,155,60,0.22), rgba(200,155,60,0.08));
    color: #fff; font-weight: 700;
}
.nav-link.active::before, .nav-group.active > .nav-toggle::before {
    content: ''; position: absolute; left: -12px; top: 9px; bottom: 9px; width: 3px;
    border-radius: 0 3px 3px 0; background: var(--gold);
}
.nav-divider { height: 1px; margin: 10px 4px 8px; background: rgba(255,255,255,0.08); }

.nav-group { margin-bottom: 2px; }
.nav-group > .nav-toggle .caret { margin-left: auto; opacity: 0.5; transition: transform 0.15s ease; }
.nav-group.open > .nav-toggle .caret { transform: rotate(90deg); }
.nav-group.active > .nav-toggle { color: #fff; font-weight: 700; }
.nav-menu { display: none; padding: 2px 0 6px 17px; }
.nav-group.open > .nav-menu { display: block; }
.nav-menu a {
    position: relative;
    display: block; padding: 7px 10px 7px 17px; border-radius: 8px;
    color: rgba(255,255,255,0.62); text-decoration: none;
    font-size: 0.86rem; font-weight: 500;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.nav-menu a::before {
    /* A guide line, so the items read as belonging to the header. */
    content: ''; position: absolute; left: 4px; top: 0; bottom: 0; width: 1px;
    background: rgba(255,255,255,0.10);
}
.nav-menu a:first-child::before { top: 6px; }
.nav-menu a:last-child::before { bottom: 6px; }
.nav-menu a:hover { color: #fff; background: rgba(255,255,255,0.06); }
.nav-menu a.active { color: var(--gold); font-weight: 700; }
.nav-menu a.active::after {
    content: ''; position: absolute; left: 2px; top: 50%; width: 5px; height: 5px;
    margin-top: -2.5px; border-radius: 50%; background: var(--gold);
}
.nav-menu-label {
    padding: 10px 10px 3px 17px; font-size: 0.64rem; font-weight: 800;
    letter-spacing: 0.12em; text-transform: uppercase; color: rgba(227,194,122,0.7);
}

/* Footer: the person, help, log out, and the collapse handle */
.sidebar-foot {
    padding: 10px 12px 12px; border-top: 1px solid rgba(255,255,255,0.07);
    display: flex; flex-direction: column; gap: 4px;
}
.user-chip {
    display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: 10px;
}
.user-avatar {
    width: 32px; height: 32px; flex: 0 0 32px; border-radius: 50%;
    display: grid; place-items: center;
    background: rgba(255,255,255,0.1); border: 1px solid rgba(255,255,255,0.14);
    color: #fff; font-weight: 700; font-size: 0.78rem;
}
.user-copy { min-width: 0; flex: 1; line-height: 1.2; }
.user-copy strong { display: block; font-size: 0.86rem; color: #fff; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.user-copy small { display: block; font-size: 0.7rem; color: rgba(255,255,255,0.5); text-transform: capitalize; }
.logout-form { margin: 0; }
.logout-btn {
    width: 38px; height: 38px; flex: 0 0 38px; border-radius: 9px; border: none;
    background: none; color: rgba(255,255,255,0.55); cursor: pointer; display: grid; place-items: center;
}
.logout-btn:hover { background: rgba(214,69,69,0.2); color: #FFB4B4; }
.sidebar-collapse {
    display: flex; align-items: center; gap: 11px; width: 100%;
    padding: 8px 11px; min-height: 36px; border-radius: 10px; border: none; background: none;
    color: rgba(255,255,255,0.45); font: inherit; font-size: 0.8rem; cursor: pointer;
}
.sidebar-collapse:hover { background: rgba(255,255,255,0.07); color: #fff; }
.sidebar-collapse svg { transition: transform 0.18s ease; }

/* Collapsed rail (desktop only): icons, with flyouts for the groups */
@media (min-width: 1024px) {
    body.sidebar-collapsed .sidebar { width: var(--sidebar-rail); flex-basis: var(--sidebar-rail); }
    body.sidebar-collapsed .brand-copy,
    body.sidebar-collapsed .hotel-switch-copy,
    body.sidebar-collapsed .hotel-switch-btn .caret,
    body.sidebar-collapsed .nav-link span,
    body.sidebar-collapsed .nav-toggle span,
    body.sidebar-collapsed .nav-toggle .caret,
    body.sidebar-collapsed .user-copy,
    body.sidebar-collapsed .sidebar-collapse span { display: none; }
    body.sidebar-collapsed .sidebar-head { padding: 18px 0 14px; justify-content: center; }
    body.sidebar-collapsed .hotel-switch { margin: 4px 10px 10px; }
    body.sidebar-collapsed .hotel-switch-btn { padding: 9px; justify-content: center; }
    body.sidebar-collapsed .hotel-menu { left: 100%; right: auto; top: 0; margin-left: 10px; min-width: 260px; }
    body.sidebar-collapsed .sidebar-nav { padding: 4px 10px 12px; }
    body.sidebar-collapsed .nav-link, body.sidebar-collapsed .nav-toggle { justify-content: center; padding: 10px 0; }
    body.sidebar-collapsed .nav-link.active::before, body.sidebar-collapsed .nav-group.active > .nav-toggle::before { left: -10px; }
    body.sidebar-collapsed .nav-group { position: relative; }
    body.sidebar-collapsed .nav-group > .nav-menu {
        display: none; position: absolute; left: calc(100% + 10px); top: -6px; z-index: 45;
        min-width: 240px; padding: 8px; border-radius: 12px;
        background: #fff; border: 1px solid var(--border); box-shadow: var(--shadow-lg);
    }
    body.sidebar-collapsed .nav-group > .nav-menu::before {
        /* Bridges the gap so the pointer can cross to the flyout. */
        content: ''; position: absolute; left: -12px; top: 0; bottom: 0; width: 12px;
    }
    body.sidebar-collapsed .nav-group:hover > .nav-menu,
    body.sidebar-collapsed .nav-group:focus-within > .nav-menu { display: block; }
    body.sidebar-collapsed .nav-group > .nav-menu::after {
        content: attr(data-label); display: block; order: -1;
        padding: 6px 10px 8px; font-size: 0.72rem; font-weight: 800; letter-spacing: 0.08em;
        text-transform: uppercase; color: var(--muted); border-bottom: 1px solid var(--border); margin-bottom: 4px;
    }
    body.sidebar-collapsed .nav-group > .nav-menu { display: none; flex-direction: column; }
    body.sidebar-collapsed .nav-group:hover > .nav-menu,
    body.sidebar-collapsed .nav-group:focus-within > .nav-menu { display: flex; }
    body.sidebar-collapsed .nav-menu a { color: var(--ink); padding: 8px 10px; font-weight: 550; }
    body.sidebar-collapsed .nav-menu a::before { display: none; }
    body.sidebar-collapsed .nav-menu a:hover { background: var(--bg); color: var(--navy); }
    body.sidebar-collapsed .nav-menu a.active { color: var(--gold-ink); background: var(--gold-bg); }
    body.sidebar-collapsed .nav-menu a.active::after { display: none; }
    body.sidebar-collapsed .nav-menu-label { color: var(--muted); padding-left: 10px; }
    body.sidebar-collapsed .sidebar-foot { padding: 10px 10px 12px; align-items: center; }
    body.sidebar-collapsed .user-chip { padding: 6px 0; justify-content: center; flex-direction: column; gap: 6px; }
    body.sidebar-collapsed .sidebar-collapse { justify-content: center; }
    body.sidebar-collapsed .sidebar-collapse svg { transform: rotate(180deg); }
    /* Tooltips on the rail */
    body.sidebar-collapsed .nav-link[data-tip]:hover::after,
    body.sidebar-collapsed .sidebar-collapse:hover::after,
    body.sidebar-collapsed .logout-btn:hover::after {
        content: attr(data-tip); position: absolute; left: calc(100% + 12px); top: 50%; transform: translateY(-50%);
        background: var(--navy); color: #fff; font-size: 0.78rem; font-weight: 600; white-space: nowrap;
        padding: 6px 10px; border-radius: 7px; box-shadow: var(--shadow-md); z-index: 50; pointer-events: none;
    }
    .logout-btn, .sidebar-collapse { position: relative; }
}

/* ---------------- Top bar (phone & tablet) ---------------- */
.topbar {
    display: none;
    position: sticky; top: 0; z-index: 25;
    height: var(--topbar-h);
    align-items: center; gap: 8px;
    padding: 0 10px 0 6px;
    background: linear-gradient(180deg, #131E3A 0%, var(--navy-deep) 100%);
    color: #fff;
    border-bottom: 2px solid var(--gold);
    box-shadow: 0 2px 10px rgba(0,0,0,0.2);
}
.topbar-btn {
    width: 42px; height: 42px; border-radius: 10px; border: none; background: none;
    color: #fff; display: grid; place-items: center; cursor: pointer; flex: 0 0 42px;
}
.topbar-btn:hover { background: rgba(255,255,255,0.1); }
.topbar .brand { flex: 1; }
.topbar .brand-mark { width: 32px; height: 32px; flex-basis: 32px; font-size: 17px; border-radius: 9px; }
.topbar .brand-copy strong { font-size: 0.98rem; }
.topbar .brand-copy small { display: none; }
.topbar-hotel {
    display: inline-flex; align-items: center; gap: 6px; max-width: 46vw;
    padding: 6px 10px 6px 6px; border-radius: 999px; text-decoration: none;
    background: rgba(255,255,255,0.08); border: 1px solid rgba(255,255,255,0.12); color: #fff;
    font-size: 0.78rem; font-weight: 600;
}
.topbar-hotel .hotel-avatar { width: 24px; height: 24px; flex-basis: 24px; border-radius: 7px; font-size: 0.62rem; }
.topbar-hotel span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ---------------- Bottom tab bar (phone) ---------------- */
.tabbar {
    display: none;
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 25;
    height: calc(var(--tabbar-h) + env(safe-area-inset-bottom));
    padding: 0 6px env(safe-area-inset-bottom);
    background: rgba(255,255,255,0.96);
    backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
    border-top: 1px solid var(--border);
    box-shadow: 0 -8px 24px rgba(16,26,51,0.06);
}
.tabbar a, .tabbar button {
    flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
    min-height: var(--tabbar-h); border: none; background: none; font: inherit;
    color: var(--muted); text-decoration: none; font-size: 0.66rem; font-weight: 700; letter-spacing: 0.02em;
    cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.tabbar a svg, .tabbar button svg { width: 22px; height: 22px; }
.tabbar a.active { color: var(--navy); }
.tabbar a.active svg { color: var(--gold-ink); }
.tabbar .tab-ico { display: grid; place-items: center; width: 44px; height: 26px; border-radius: 999px; }
.tabbar a.active .tab-ico { background: var(--gold-bg); }

/* wo071:shell start — the sidebar's two bands and its counts, and the topbar
   as the direction draws it: where you are, jump to a screen, the bell, the
   guide. Before this the topbar existed only on a phone (`display: none` until
   1023.98px) and a desktop had no bar at all, which is why none of these four
   had anywhere to live. */
.nav-band {
    padding: var(--sp-3) 10px var(--sp-1);
    font-size: 10px; font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase;
    color: rgba(255,255,255,0.46);
}
.nav-count {
    margin-left: auto; flex: none;
    min-width: 20px; padding: 1px 7px; border-radius: 999px;
    background: var(--navy-lighter); color: #fff;
    font-size: 10.5px; font-weight: 600; font-variant-numeric: var(--num);
    text-align: center;
}
.nav-link.active .nav-count, .nav-group.active > .nav-toggle .nav-count {
    background: var(--gold); color: var(--navy);
}
.nav-group > .nav-toggle .nav-count { margin-left: auto; }
/* WO-073 item 2: a count on the screen it counts; the group's is their sum. */
.nav-menu a .nav-count { float: right; margin-left: var(--sp-2); }
.nav-group > .nav-toggle .nav-count + .caret { margin-left: var(--sp-1); }
body.sidebar-collapsed .nav-band { text-align: center; padding-left: 0; padding-right: 0; }
body.sidebar-collapsed .nav-count { display: none; }

.tb-crumb { display: flex; align-items: center; gap: 6px; font-size: var(--fs-small); color: var(--muted); }
.tb-crumb a { color: inherit; text-decoration: none; }
.tb-crumb a:hover { color: var(--ink); text-decoration: underline; }
.tb-crumb b { color: var(--ink); font-weight: 600; }
.tb-search {
    margin-left: auto; display: inline-flex; align-items: center; gap: var(--sp-2);
    height: 34px; min-width: 0; padding: 0 var(--sp-3);
    border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
    background: var(--surface-2); color: var(--muted-light);
    font: inherit; font-size: var(--fs-small); cursor: pointer; white-space: nowrap;
}
.tb-search:hover { border-color: var(--muted-light); color: var(--muted); }
.tb-search kbd {
    margin-left: var(--sp-4); padding: 1px 5px;
    border: 1px solid var(--border-strong); border-radius: 5px;
    background: var(--surface); color: var(--muted); font: inherit; font-size: 10.5px;
}
.tb-icon {
    flex: none; width: 32px; height: 32px; display: grid; place-items: center;
    border: 1px solid var(--border); border-radius: var(--radius-sm);
    background: var(--surface); color: var(--muted); text-decoration: none;
}
.tb-icon:hover { color: var(--ink); border-color: var(--border-strong); }

/* Jump to a screen. The list is the menu, already filtered to what this
   person may open, so nothing here asks the server anything. */
.sh-palette {
    position: fixed; inset: 0; z-index: 60;
    display: grid; justify-items: center; align-content: start;
    padding: 12vh 16px 16px;
    background: rgba(8,15,31,0.45);
}
.sh-palette-box {
    width: min(540px, 100%); padding: var(--sp-3);
    background: var(--surface); border-radius: var(--radius); box-shadow: var(--shadow-lg);
}
.sh-results { max-height: 46vh; overflow-y: auto; margin-top: var(--sp-2); }
.sh-result {
    display: flex; align-items: center; gap: var(--sp-3);
    padding: 9px var(--sp-3); border-radius: var(--radius-sm);
    color: var(--ink); text-decoration: none; font-size: var(--fs-body);
}
.sh-result small { margin-left: auto; color: var(--muted); font-size: var(--fs-eyebrow); }
.sh-result.is-picked, .sh-result:hover { background: var(--gold-bg); }
.sh-none { margin: var(--sp-3); color: var(--muted); font-size: var(--fs-small); }

@media (min-width: 1024px) {
    .topbar {
        display: flex;
        padding: 0 var(--sp-5); gap: var(--sp-3);
        background: var(--surface); color: var(--ink);
        border-bottom: 1px solid var(--border); box-shadow: none;
    }
    .topbar .topbar-btn, .topbar .brand, .topbar-hotel { display: none; }
}
@media (max-width: 1023.98px) {
    /* The phone keeps the navy bar it had; the crumb is the drawer's job and
       the search collapses to its icon. The brand goes with them: three icons
       and the hotel's name do not fit beside it at 390, and the drawer the
       hamburger opens carries the brand anyway (found on My Jobs, WO-071
       item 4 - the name and the hotel were printing over each other). */
    .tb-crumb, .tb-search span, .tb-search kbd, .topbar .brand { display: none; }
    .topbar-hotel { min-width: 0; }
    .tb-search { margin-left: auto; width: 36px; padding: 0; justify-content: center; }
    .tb-search, .tb-icon {
        background: rgba(255,255,255,0.1); border-color: rgba(255,255,255,0.18); color: #fff;
    }
    .sh-palette { padding-top: 8vh; }
}
/* wo071:shell end */

.drawer-backdrop {
    display: none; position: fixed; inset: 0; z-index: 29;
    background: rgba(8,15,31,0.55); backdrop-filter: blur(2px);
}

@media (max-width: 1023.98px) {
    .topbar { display: flex; }
    .sidebar {
        position: fixed; top: 0; left: 0; bottom: 0; height: 100%;
        width: min(320px, 86vw); flex-basis: auto;
        transform: translateX(-104%);
        transition: transform 0.22s cubic-bezier(.2,.8,.2,1);
        box-shadow: none;
    }
    body.nav-open .sidebar { transform: none; box-shadow: var(--shadow-lg); }
    body.nav-open .drawer-backdrop { display: block; }
    body.nav-open { overflow: hidden; }
    .sidebar-close { display: grid; }
    .sidebar-collapse { display: none; }
    .nav-link, .nav-toggle { min-height: 46px; font-size: 0.95rem; }
    .nav-menu a { padding: 10px 10px 10px 17px; font-size: 0.92rem; }
    .container { padding: 20px 16px 40px; }
}
@media (max-width: 767.98px) {
    .tabbar { display: flex; }
    body.has-tabbar .app-main > .container { padding-bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom) + 24px); }
    body.has-tabbar .mobile-form-actions { bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom) + 8px); }
}

/* ---------------- Page header ---------------- */
.page-header {
    display: flex; justify-content: space-between; align-items: flex-end;
    margin-bottom: 22px; flex-wrap: wrap; gap: 12px 16px;
}
.page-header h2 {
    margin: 0; font-size: clamp(1.45rem, 1.9vw, 1.75rem); font-weight: 800; letter-spacing: -0.025em;
}
.page-subtitle { max-width: 760px; color: var(--muted); font-size: 0.92em; margin-top: 4px; line-height: 1.5; }
.action-group { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }

/* ---------------- Cards ---------------- */
.card {
    background: var(--surface);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    border: 1px solid var(--border);
    padding: 22px;
}
.card-link { text-decoration: none; color: inherit; display: block; transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease; }
.card-link:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); border-color: var(--border-strong); }

/* ---------------- Buttons ---------------- */
.btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 7px;
    min-height: 38px; padding: 8px 16px;
    border-radius: 9px; text-decoration: none; cursor: pointer; border: 1px solid transparent;
    font-size: 14px; font-weight: 600; font-family: inherit; line-height: 1.2;
    transition: filter 0.15s ease, transform 0.05s ease, box-shadow 0.15s ease, background-color 0.15s ease;
    white-space: nowrap;
}
.btn:disabled { cursor: default; opacity: 0.65; filter: none; transform: none; }
.btn-working::before {
    content: ''; width: 14px; height: 14px; flex: 0 0 auto;
    border: 2px solid currentColor; border-top-color: transparent; border-radius: 50%;
    animation: btn-spin 0.7s linear infinite;
}
@keyframes btn-spin { to { transform: rotate(360deg); } }
.btn:hover { filter: brightness(1.06); }
.btn:active { transform: translateY(1px); }
.btn-primary { background-color: var(--navy); color: white; box-shadow: 0 1px 2px rgba(14,23,46,0.25); }
.btn-primary:hover { filter: none; background-color: var(--navy-light); }
.btn-accent { background-color: var(--gold); color: var(--navy-deep); }
.btn-accent:hover { filter: none; background-color: var(--gold-ink); color: white; }
.btn-secondary { background-color: var(--surface); color: var(--ink); border-color: var(--border-strong); }
.btn-secondary:hover { filter: none; background-color: var(--surface-2); border-color: #C3C8D1; }
.btn-danger { background-color: var(--danger-bg); color: var(--danger); }
.btn-danger:hover { filter: none; background-color: var(--danger); color: white; }
.btn-sm { min-height: 32px; padding: 5px 12px; font-size: 12.5px; border-radius: 8px; }
.btn:focus-visible, .sidebar button:focus-visible, .sidebar a:focus-visible,
.topbar button:focus-visible, .tabbar a:focus-visible, .tabbar button:focus-visible {
    outline: 3px solid rgba(200,155,60,0.45); outline-offset: 2px;
}

/* ---------------- Forms ---------------- */
.form-group { margin-bottom: 16px; }
.form-group label { display: block; margin-bottom: 6px; font-weight: 600; font-size: 0.9em; color: var(--ink); }
.form-control {
    width: 100%; min-height: 40px; padding: 8px 11px;
    border: 1px solid var(--border-strong); border-radius: 8px;
    font-size: 14px; font-family: inherit; background: white; color: var(--ink);
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
select.form-control { padding-right: 30px; appearance: none; -webkit-appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23667085' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
    background-repeat: no-repeat; background-position: right 10px center; }
.form-control:focus { outline: none; border-color: var(--gold); box-shadow: 0 0 0 3px var(--gold-bg); }
.form-control::placeholder { color: var(--muted-light); }
/* An input for a short number - a multiplier, a rate, a count - which would
   otherwise stretch to the full width of its cell and read as a text field.
   A utility rather than an inline `style` on the widget, because a form that
   styles itself puts `style=` on every row it renders and the template gate
   cannot see it there (WO-036 items 3 and 8). */
.form-control.is-narrow { max-width: 110px; }
/* A box somebody pastes columns into - a bank or OTA statement. Proportional
   digits make the columns wander and the reader cannot see where a field ends;
   tabular monospace is the whole point of the box. Here rather than on the
   widget for the same reason as `.is-narrow` above (WO-036 items 5 and 8). */
.form-control.is-monospace { font-family: ui-monospace, Menlo, Consolas, monospace; font-size: .86em; }
/* A colour well - `<input type="color">`. Browsers render it at their own
   small default height, which sits a third of the way up a row of text inputs
   beside it; this matches it to them. (WO-036 items 6 and 8.) */
.form-control.is-swatch { height: 42px; }
/* A single-column form on its own page - one shift, one code, one department.
   Wider than this and the eye has to travel back across empty space to find
   the next label. */
.form-narrow { max-width: 560px; }
.toolbar-card { margin-bottom: 18px; padding: 14px 18px; }
.filter-form { display: flex; gap: 12px; flex-wrap: wrap; align-items: end; }
.filter-form .form-group { margin-bottom: 0; }
.search-field { width: min(100%, 340px); }
.errorlist { color: var(--danger); font-size: 0.85em; margin: 4px 0 0; padding-left: 18px; }

/* ---------------- Badges (status pills) ---------------- */
.badge {
    display: inline-flex; align-items: center; gap: 5px;
    padding: 3px 10px; border-radius: 999px;
    font-size: 0.74em; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
    white-space: nowrap; line-height: 1.5;
}
.badge-success { background: var(--success-bg); color: var(--success); }
.badge-warning { background: var(--warning-bg); color: var(--warning); }
.badge-danger { background: var(--danger-bg); color: var(--danger); }
.badge-info { background: var(--info-bg); color: var(--info); }
.badge-neutral { background: var(--neutral-bg); color: var(--muted); }
.badge-gold { background: var(--gold-bg); color: var(--gold-ink); }

/* ---------------- Tables ---------------- */
.table-card { padding: 0; overflow: hidden; }
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.mobile-table-hint { display: none; }
table.data-table { width: 100%; min-width: 640px; border-collapse: collapse; }
table.data-table th {
    text-align: left; padding: 11px 14px; font-size: 0.72em; font-weight: 750;
    text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted);
    border-bottom: 1px solid var(--border); background: var(--surface-2);
    white-space: nowrap;
}
table.data-table td { padding: 12px 14px; border-bottom: 1px solid #EEF0F3; font-size: 0.92em; vertical-align: middle; }
table.data-table tbody tr:last-child td { border-bottom: none; }
table.data-table tbody tr { transition: background-color 0.12s ease; }
table.data-table tbody tr:hover { background-color: #FBF9F3; }
.data-primary { font-weight: 700; color: var(--navy); }
.data-muted { color: var(--muted); font-size: 0.88em; }
/* `table.data-table th` outranks a bare `th.num`, so a right-aligned column
   heading quietly stayed left while its figures moved right. It never showed
   before because every caller wrote the alignment inline, where nothing could
   outrank it (WO-020 item 6). */
.num,
td.num,
th.num,
table.data-table th.num,
table.data-table td.num {
    text-align: right;
    /* WO-019 C5: four finance screens each redefined `.num` to add this
       and lost the tabular figures doing it. A number that wraps in the
       middle is wrong everywhere, so it belongs here. */
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

/* wo071:kit start — the components of the direction, and nothing else.
   Each one has a partial in `templates/includes/` and an assertion in
   `core/tests/test_kit.py`. A screen reaches for these or it is not on the
   kit; a screen that wants a size or a colour between two of them wants one
   of them. */

/* The header row: title, one line of context, the controls and one primary. */
.pg-head { display: flex; align-items: flex-end; gap: var(--sp-4); margin-bottom: var(--sp-5); flex-wrap: wrap; }
.pg-head-main { min-width: 0; }
.pg-title {
    display: flex; align-items: center; gap: var(--sp-2);
    margin: 0; font-size: var(--fs-title); font-weight: 600;
    letter-spacing: -0.01em; line-height: 1.15; color: var(--ink);
}
.pg-help {
    flex: none; width: 18px; height: 18px; padding: 0;
    border: 1px solid var(--border-strong); border-radius: 50%;
    background: var(--surface); color: var(--muted);
    font: inherit; font-size: 11px; font-weight: 600; line-height: 1; cursor: help;
}
.pg-help:hover { color: var(--ink); border-color: var(--muted-light); }
.pg-context { margin-top: 5px; max-width: 520px; color: var(--muted); font-size: var(--fs-small); }
.pg-head-tools { margin-left: auto; display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.pg-date { display: flex; gap: var(--sp-2); }
.pg-date .form-control { width: auto; }
.btn-text {
    height: 34px; padding: 0 var(--sp-2); border: none; background: none;
    color: var(--info); font-weight: 500; text-decoration: none;
    display: inline-flex; align-items: center;
}
.btn-text:hover { text-decoration: underline; }

/* A figure on a card - `templates/includes/_tile.html`, the only tile there is.
   The number is the largest text on it, which is the rule the old reports broke
   on every screen: a 20px title over the 15px number it was about. The classes
   keep the `rp-` prefix they were born with; the partial says why. */
.kt-tiles, .rp-kpis { display: grid; gap: var(--sp-4); grid-template-columns: repeat(auto-fit, minmax(min(100%, 170px), 1fr)); }
.rp-kpi {
    display: flex; flex-direction: column; gap: 6px;
    padding: var(--sp-4) 18px var(--sp-3);
    /* The figure is `--fs-figure` where there is room for it and shrinks with
       the card where there is not: `RM 400,678.51` at 28px is 210px wide and a
       phone gives a tile about 170 (WO-071 item 8, found at 390 on Reports
       home - the page ran 40px wide). */
    container-type: inline-size;
}
.rp-kpi.is-lead { border-color: var(--gold); }
.rp-kpi-label {
    display: flex; align-items: center; gap: 6px;
    font-size: var(--fs-eyebrow); font-weight: 600; letter-spacing: 0.09em;
    text-transform: uppercase; color: var(--muted);
}
.rp-kpi-label a { color: inherit; text-decoration: none; }
.rp-kpi-value {
    font-size: clamp(1.15rem, 13cqi, var(--fs-figure)); font-weight: var(--fw-figure);
    letter-spacing: -0.02em; line-height: 1.1; font-variant-numeric: var(--num);
    white-space: nowrap; color: var(--ink);
}
.rp-kpi-value.is-unknown { color: var(--muted-light); }
.rp-kpi-foot { font-size: var(--fs-small); line-height: 1.4; color: var(--muted); }
/* An arrow on the change, so its direction is not carried by colour alone. */
.rp-delta strong { font-weight: 600; color: var(--ink); }
.rp-delta.is-good strong { color: var(--success); }
.rp-delta.is-bad strong { color: var(--danger); }
.rp-delta.is-up strong::before { content: "\25B2\00A0"; font-size: .72em; }
.rp-delta.is-down strong::before { content: "\25BC\00A0"; font-size: .72em; }
.rp-kpi-spark { margin-top: auto; padding-top: var(--sp-1); }
/* The exports sit under the header row, not in it: on every report but one
   there is a single file to take away, and a lone menu handle in the row read
   as the page's action. */
.rp-head-exports { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin: calc(var(--sp-5) * -1) 0 var(--sp-4); }

/* A status, as a colour before it is a word. Six tones and no seventh. */
.pill {
    display: inline-flex; align-items: center; gap: 5px;
    height: 20px; padding: 0 var(--sp-2); border-radius: 999px;
    font-size: var(--fs-eyebrow); font-weight: 600; letter-spacing: 0.02em;
    white-space: nowrap;
}
.pill::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: none; }
.pill.is-ok { background: var(--success-bg); color: var(--success); }
.pill.is-warn { background: var(--warning-bg); color: var(--warning); }
.pill.is-bad { background: var(--danger-bg); color: var(--danger); }
.pill.is-info { background: var(--info-bg); color: var(--info); }
.pill.is-neutral { background: var(--neutral-bg); color: var(--neutral); }
.pill.is-gold { background: var(--gold-bg); color: var(--gold-ink); }

/* A few choices, one of them on. */
.seg { display: inline-flex; padding: 3px; gap: 2px; border: 1px solid var(--border-strong); border-radius: var(--radius-sm); background: var(--surface); }
.seg-opt {
    padding: 5px 11px; border-radius: 7px;
    color: var(--muted); font-size: var(--fs-small); font-weight: 500;
    text-decoration: none; white-space: nowrap;
}
.seg-opt.is-on { background: var(--navy); color: #fff; font-weight: 600; }

/* Nothing here yet: one line, and at most one thing to do about it. */
.kt-empty { padding: var(--sp-6) var(--sp-4); text-align: center; color: var(--muted); font-size: var(--fs-body); }
.kt-empty p { margin: 0 0 var(--sp-3); }

/* Work in stages. Three columns on a laptop, one on a phone. */
.kt-board { display: grid; gap: var(--sp-4); grid-template-columns: repeat(3, minmax(0, 1fr)); }
.kt-col { min-width: 0; display: flex; flex-direction: column; gap: var(--sp-3); }
.kt-col-head {
    display: flex; align-items: center; gap: var(--sp-2); margin: 0;
    font-size: var(--fs-body); font-weight: 600; color: var(--ink-2);
}
.kt-col-count {
    padding: 1px var(--sp-2); border-radius: 999px;
    background: var(--neutral-bg); color: var(--muted);
    font-size: var(--fs-eyebrow); font-weight: 600; font-variant-numeric: var(--num);
}
.kt-col-empty { margin: 0; color: var(--muted-light); font-size: var(--fs-small); }

/* A person, or anything else small enough to sit in a row of them. */
.kt-chip {
    display: inline-flex; align-items: center; gap: 7px;
    padding: 4px 10px; border: 1px solid var(--border-strong); border-radius: 999px;
    background: var(--surface); color: var(--ink);
    font-size: var(--fs-small); font-weight: 500; white-space: nowrap;
}
.kt-chip.is-off { color: var(--muted); border-style: dashed; }

/* A row of figures over a card or a board: how many rooms, how many clean. */
.kt-stat { display: flex; gap: var(--sp-6); align-items: center; padding: var(--sp-3) 18px; flex-wrap: wrap; }
.kt-stat-one b { display: block; font-size: 22px; font-weight: var(--fw-figure); letter-spacing: -0.02em; font-variant-numeric: var(--num); }
.kt-stat-one span { font-size: var(--fs-eyebrow); font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); }

@media (max-width: 900px) {
    .kt-board { grid-template-columns: minmax(0, 1fr); }
    .pg-head-tools { margin-left: 0; width: 100%; }
}
/* wo071:kit end */

/* The desk sheet's "Count it again" summary. It was an inline style naming
   `var(--link, #2f5fd0)`; `--link` is not a token in this system, so that
   fallback was the colour - a blue nobody chose (WO-071 item 3). */
.cb-again { display: inline; cursor: pointer; color: var(--info); text-decoration: underline; }

/* wo071:table start — one set of rules for every table on a screen: a 44px
   row so a thumb can hit it, numbers right and tabular so a column adds up by
   eye, a head that stays put over a long list, and a dash where a nought would
   be noise. `.table-scroll` remains the one wrapper a wide table sits in
   (docs/DESIGN.md §6).

   Written as `table.data-table`, not `.data-table`: the rules above are on the
   element plus the class, which outranks a bare class whatever the order, and
   a right-aligned heading quietly stayed left for a year the last time that
   was forgotten (the note on `.num`). */
/* The head sticks inside whatever scrolls it. On most screens that is nothing:
   `.table-card` is `overflow: hidden` and `.table-scroll` is a scroll container,
   so a table in one of them scrolls with the page and the head goes with it.
   Where a list is bounded - `.table-scroll.is-bounded`, the Inbox's open bills -
   it does stick. Since WO-072 item 7 every table over fifteen rows is bounded
   at 1024px and up (`shell.js` marks it `is-bounded is-long`), so there the
   head sticks too; a phone scrolls the page and the head goes with it. */
table.data-table th {
    position: sticky; top: 0; z-index: 1;
    padding: 10px 14px;
    font-size: var(--fs-eyebrow); font-weight: 600; letter-spacing: 0.08em;
    background: var(--surface);
}
/* A section heading inside a table card, which has no padding of its own. */
.table-card > .kt-col-head { padding: var(--sp-3) 14px var(--sp-1); }
table.data-table td { height: 44px; padding: 10px 14px; font-size: var(--fs-body); }
table.data-table td.num, table.data-table th.num {
    text-align: right; font-variant-numeric: var(--num);
}
/* A nought that is not a figure - an empty cell - reads as grey, so a column
   of them stops shouting. The Day per Floor prints 84 of them. */
table.data-table td .zero, table.data-table td.is-zero { color: var(--muted-light); }
/* wo071:table end */

.table-pager {
    display: flex; align-items: center; justify-content: space-between;
    gap: 10px; flex-wrap: wrap; padding: 12px 14px; border-top: 1px solid var(--border);
}
.table-pager-controls { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }

/* ---------------- Dashboard metrics ---------------- */
.metric-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 14px; margin-bottom: 24px; }
.metric-card { position: relative; min-height: 108px; overflow: hidden; padding: 18px 20px; }
.metric-card::before {
    content: ''; position: absolute; left: 0; top: 16px; bottom: 16px; width: 3px;
    border-radius: 0 3px 3px 0; background: var(--gold);
    opacity: 0.9;
}
.metric-label { color: var(--muted); font-size: 0.7rem; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase; }
.metric-value {
    margin-top: 8px; color: var(--navy); font-size: 1.85rem; font-weight: 800; line-height: 1;
    letter-spacing: -0.035em; font-variant-numeric: tabular-nums;
}
.metric-value.success { color: var(--success); }
.metric-value.warning { color: var(--warning); }
.form-card { margin-bottom: 24px; }
.form-card > h3 { margin-bottom: 16px; }
details.mobile-section > summary {
    display: block; pointer-events: none; list-style: none; margin-bottom: 14px;
    color: var(--navy); font-size: 1.1em; font-weight: 700; letter-spacing: -0.018em;
}
details.mobile-section > summary::-webkit-details-marker { display: none; }
.mobile-form-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 18px; }

/* ---------------- Detail page two-column layout ---------------- */
.detail-columns { display: flex; gap: 20px; align-items: flex-start; }
@media (max-width: 768px) {
    .detail-columns { flex-direction: column; }
    .detail-columns > * { max-width: 100% !important; width: 100% !important; }
}

/* ---------------- Empty states ---------------- */
.empty-state { text-align: center; padding: 50px 20px; color: var(--muted); }
.empty-state svg { color: var(--muted-light); margin-bottom: 12px; }
.empty-state p { margin: 0; font-size: 0.95em; }

/* ---------------- Flash messages ---------------- */
.flash-message {
    display: flex; align-items: flex-start; gap: 10px;
    margin-bottom: 18px; padding: 12px 16px;
    border: 1px solid transparent; border-radius: 11px;
    font-size: 0.9rem; font-weight: 600; box-shadow: var(--shadow-sm);
}
.flash-message::before {
    content: ''; width: 8px; height: 8px; border-radius: 50%; margin-top: 7px; flex: 0 0 8px; background: currentColor; opacity: 0.75;
}
.flash-success { border-color: #BDE5CC; background: var(--success-bg); color: #187744; }
.flash-error { border-color: #F0C5C5; background: var(--danger-bg); color: #A62F2F; }
.flash-warning { border-color: #EBD9A8; background: var(--warning-bg); color: #8A6100; }

/* ---------------- Phone density ---------------- */
@media (max-width: 768px) {
    body { padding-bottom: max(20px, env(safe-area-inset-bottom)); }
    .card { padding: 16px; }
    .table-card { padding: 0; }
    .page-header { align-items: flex-start; margin-bottom: 18px; }
    .page-header h2 { font-size: 1.4rem; line-height: 1.2; }
    .page-header > .action-group,
    .page-header > .btn { width: 100%; }
    .page-header > .action-group,
    .page-header > div:last-child:not(:first-child) {
        display: grid !important;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        width: 100%;
        gap: 8px !important;
    }
    .page-header > .action-group .btn,
    .page-header > div:last-child:not(:first-child) .btn,
    .page-header > div:last-child:not(:first-child) form { width: 100%; }
    .page-header > .action-group > :last-child:nth-child(odd),
    .page-header > div:last-child:not(:first-child) > :last-child:nth-child(odd) { grid-column: 1 / -1; }
    .page-header > div:last-child:not(:first-child) form .btn { width: 100%; }
    .page-header > .btn { min-height: 44px; }
    .btn { min-height: 44px; padding: 10px 15px; white-space: normal; }
    .btn-sm { min-height: 36px; }
    .form-control { min-height: 46px; font-size: 16px; }
    input[type="checkbox"], input[type="radio"] { width: 18px; height: 18px; flex: 0 0 auto; }
    .filter-form > * { flex: 1 1 150px; }
    .filter-form > .btn { flex: 0 0 auto; }
    .metric-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
    .metric-card { min-height: 96px; padding: 14px 16px; }
    .metric-value { font-size: 1.45rem; }
    .empty-state { padding: 38px 16px; }
    table.data-table th { padding: 10px 12px; }
    table.data-table td { padding: 11px 12px; }
    .table-scroll { scrollbar-width: thin; scrollbar-color: #A9AFBA transparent; }
    .mobile-table-hint {
        display: flex; align-items: center; justify-content: space-between; gap: 8px;
        min-height: 36px; padding: 8px 12px;
        border-bottom: 1px solid #EADFBF;
        background: linear-gradient(90deg, var(--gold-bg), #FFFDF8);
        color: var(--gold-ink); font-size: .78rem; font-weight: 700;
    }
    .mobile-table-hint[hidden] { display: none; }
    .mobile-table-hint svg { flex: 0 0 auto; }
    details.mobile-section > summary {
        cursor: pointer; pointer-events: auto; list-style: none;
        display: flex; align-items: center; justify-content: space-between; gap: 12px;
        color: var(--navy); font-size: 1.02rem; font-weight: 750;
    }
    details.mobile-section > summary::-webkit-details-marker { display: none; }
    details.mobile-section > summary::after { content: '+'; color: var(--gold); font-size: 1.35rem; }
    details.mobile-section[open] > summary::after { content: '\2212'; }
    details.mobile-section[open] > summary { margin-bottom: 16px; padding-bottom: 12px; border-bottom: 1px solid var(--border); }
    .mobile-form-actions {
        position: sticky; bottom: 8px; z-index: 5;
        padding: 10px; border: 1px solid var(--border); border-radius: var(--radius);
        background: rgba(255,255,255,.96); box-shadow: 0 10px 30px rgba(20,31,52,.14);
        backdrop-filter: blur(8px);
    }
    .mobile-form-actions .btn { flex: 1; }
}
@media (max-width: 430px) {
    .page-header > .action-group:has(> :only-child),
    .page-header > div:last-child:not(:first-child):has(> :only-child) { grid-template-columns: 1fr; }
}

@media print {
    .sidebar, .topbar, .tabbar, .drawer-backdrop, .mobile-table-hint { display: none !important; }
    body { background: #fff; }
    .container { max-width: none; padding: 0; }
    .card { box-shadow: none; }
}

.text-center { text-align: center; }
/* 3px, like every other `.mt-N` in this file is N pixels. It was 15px - a name
   from an older scale that nothing had used since, and a class called `mt-3`
   that moves something fifteen pixels is a trap with a friendly name. Found by
   the computed-style diff on WO-044's sweep, which is what that diff is for. */
.mt-3 { margin-top: 3px; }

/* ---------------- accounting: supplier statement ----------------
   Lifted from accounting/templates/accounting/supplier_statement.html on
   2026-09-05 (WO-019 B1); the rules are unchanged. */
.ss-summary { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; margin-bottom: 18px; }
@media (max-width: 900px) { .ss-summary { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.ss-summary .card { padding: 14px 16px; }
.ss-summary .lbl { font-size: 0.66rem; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase; color: var(--muted); }
.ss-summary .val { margin-top: 6px; font-size: 1.35rem; font-weight: 800; color: var(--navy); letter-spacing: -0.03em; font-variant-numeric: tabular-nums; }
.ss-summary .val.danger { color: var(--danger); }
.ss-summary .sub { font-size: 0.74rem; color: var(--muted); margin-top: 2px; }
.ss-two { display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); gap: 18px; align-items: start; }
@media (max-width: 1023.98px) { .ss-two { grid-template-columns: minmax(0, 1fr); } }
@media print { .ss-header .action-group { display: none; } }
.ss-both { display: flex; gap: 12px; align-items: flex-start; justify-content: space-between; flex-wrap: wrap; }
.ss-both > div { min-width: 0; }
.ss-net { margin-top: 14px; padding: 12px 14px; border-radius: var(--radius-sm);
          background: var(--surface-2); border: 1px solid var(--border); }
.ss-net .lbl { font-size: .7rem; font-weight: 800; letter-spacing: .09em;
               text-transform: uppercase; color: var(--muted); }
.ss-net .val { font-size: 1.25em; font-weight: 800; color: var(--navy); margin-top: 2px; }
.ss-net .val.danger { color: var(--danger); }
.ss-net .sub { font-size: .84em; color: var(--muted); margin-top: 6px; }

/* ---------------- invoices: MyInvois fields ----------------
   Lifted from invoices/templates/invoices/myinvois.html on 2026-09-05
   (WO-019 B2); the rules are unchanged. */
.mi-missing { border-left: 4px solid var(--warning); }
.mi-ready { border-left: 4px solid var(--success); }
.mi-list { margin: 8px 0 0 18px; color: var(--muted); font-size: .88em; }
.mi-line { padding: 14px 0; border-bottom: 1px solid var(--border); }
.mi-line:last-child { border-bottom: none; }
.mi-line-head { display: flex; gap: 12px; justify-content: space-between; align-items: baseline; }
.mi-line-head strong { font-weight: 700; }
.mi-grid {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 12px; margin-top: 10px;
}
.mi-grid .form-group { margin-bottom: 0; }
.mi-gap { color: var(--warning-text, #8a6d00); font-size: .82em; margin-top: 6px; }

/* ---------------- integrations: Inbox queue ----------------
   Lifted from integrations/templates/integrations/drop.html on 2026-09-05
   (WO-019 B3); the rules are unchanged. */
.inbox-tabs { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 12px; }
.inbox-tab { display: inline-flex; align-items: center; gap: 6px; padding: 8px 12px; border: 1px solid var(--border); border-radius: 999px; font-size: .88em; font-weight: 600; color: var(--navy); text-decoration: none; min-height: 44px; }
.inbox-tab.active { background: var(--navy); color: #fff; border-color: var(--navy); }
.inbox-tab .badge { font-size: .82em; }
.upload-report { margin-top: 12px; padding: 12px 14px; border: 1px solid var(--gold);
                 border-left-width: 4px; border-radius: var(--radius-sm); background: var(--gold-bg); }
.upload-report .upload-report-head { margin: 0 0 6px; font-weight: 700; font-size: .92em; color: var(--navy); }
.upload-report .upload-report-head.bad { color: var(--danger); }
.upload-report ul { margin: 0 0 10px; padding-left: 20px; font-size: .88em; color: var(--ink); }
.upload-report li { margin-bottom: 4px; }
.doc-thumb { width: 44px; height: 56px; object-fit: cover; border: 1px solid var(--border); border-radius: 6px; background: var(--neutral-bg); display: block; }
.doc-name { font-weight: 700; color: var(--navy); word-break: break-word; }
.doc-sub { color: var(--muted); font-size: .82em; margin-top: 2px; }
.conf-chip { font-size: .78em; color: var(--muted); white-space: nowrap; }
.conf-low { color: var(--gold-ink, #8a6d1a); font-weight: 600; }
.repeat-warn { font-size: .78em; color: var(--gold-ink, #8a6d1a); font-weight: 600; white-space: nowrap; }
/* The bulk "read again" picker (WO-032). The cell is the same 52px the
   thumbnail column already uses, and the box itself is 20px so a thumb can
   land on it at phone width without a miss. */
.bulk-cell { width: 52px; text-align: center; vertical-align: middle; }
.bulk-cell input[type="checkbox"] { width: 20px; height: 20px; margin: 0; cursor: pointer; }
.bulk-bar { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; margin-bottom: 12px; }
.bulk-hint { color: var(--muted); font-size: .84em; }
@media (max-width: 600px) { .bulk-hint { flex-basis: 100%; } }
/* The Failed tab's empty state carries two sentences of explanation rather
   than a shrug, so it needs a readable measure. */
.empty-note { color: var(--muted); font-size: .88em; max-width: 62ch; margin: 8px auto 0; }

/* ---------------- night_audit: the gross-sales grid (WO-033) ----------------
   A month is 31 columns plus a label and a total, so it scrolls sideways
   inside .table-scroll by design - `docs/DESIGN.md` §6 allows exactly that for
   a wide table, and never hides a money column to avoid it. */
.grid-table { font-size: .84em; white-space: nowrap; }
.grid-table th, .grid-table td { padding: 5px 8px; }
.grid-table .grid-head { position: sticky; left: 0; background: var(--surface); z-index: 1; }
/* A day nobody read: its column is greyed so a blank cell reads as "not read"
   rather than as nothing having happened. */
.grid-unread { background: var(--neutral-bg); color: var(--muted); }

/* ---------------- integrations: review workspace ----------------
   Lifted from integrations/templates/integrations/review.html on 2026-09-05
   (WO-019 B3); the rules are unchanged. */
.review-columns { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr); gap: 18px; align-items: start; }
@media (max-width: 900px) { .review-columns { grid-template-columns: minmax(0, 1fr); } }
.review-columns.preview-wide { grid-template-columns: minmax(0, 1fr); }
.preview-card { position: sticky; top: 12px; padding: 12px; }
@media (max-width: 900px) { .preview-card { position: static; } }

/* The viewer. One stage for both kinds of file, so "how tall is the
   preview" and "widen it" are answered once rather than per file type. */
.pv-tools { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; margin-bottom: 8px; }
.pv-tools .spacer { flex: 1 1 auto; min-width: 0; }
.pv-level { font-size: .78em; color: var(--muted); font-variant-numeric: tabular-nums; min-width: 42px; text-align: center; }
.pv-stage { height: var(--pv-h, 72vh); overflow: auto; border: 1px solid var(--border);
            border-radius: var(--radius-sm); background: var(--neutral-bg);
            overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }
.pv-stage.tall { --pv-h: calc(100vh - 150px); }
@media (max-width: 900px) { .pv-stage { --pv-h: 58vh; } .pv-stage.tall { --pv-h: 78vh; } }
.preview-frame { width: 100%; height: 100%; border: 0; display: block; background: var(--neutral-bg); }
/* `width: max-content` is what makes the LEFT edge of a zoomed image
   reachable. Measured while building this: with the inner box left at its
   default width, a 1800px image centred inside a 458px stage reported
   `scrollWidth` 1129 - 229px of overflow on the right and 671px on the
   left that no scroll position can reach, because a scroll container has
   no negative side. Sizing the inner box to its content puts the whole
   overflow on the right, where scrolling can get to it; `min-width: 100%`
   keeps a small image centred. `text-align: center` has the same defect
   and was what the first version used. */
.pv-inner { width: max-content; min-width: 100%; min-height: 100%;
            display: flex; align-items: center; justify-content: center; }
.pv-img { display: block; max-width: none; height: auto; user-select: none; -webkit-user-drag: none; }
.pv-stage.grabbing { cursor: grabbing; }
.pv-stage.pannable { cursor: grab; }
.rv-row { display: flex; gap: 10px; align-items: baseline; justify-content: space-between; flex-wrap: wrap; }

/* The reading, scored. One banding vocabulary - high / fair / low, from
   `review.band_for` - used by the meter, the tally and every field chip,
   so the three never make different claims about the same number. */
.rv-reading { margin-top: 12px; }
.rv-reading-top { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.rv-reading-kind { font-weight: 800; font-size: 1.05em; color: var(--navy); }
.rv-pct { font-variant-numeric: tabular-nums; font-weight: 800; font-size: 1.05em; }
.rv-pct.high { color: var(--success); } .rv-pct.fair { color: var(--warning); } .rv-pct.low { color: var(--danger); }
.rv-meter { margin-top: 6px; height: 8px; border-radius: 999px; background: var(--neutral-bg); overflow: hidden; }
.rv-meter > span { display: block; height: 100%; border-radius: 999px; background: var(--muted); }
.rv-meter.high > span { background: var(--success); }
.rv-meter.fair > span { background: var(--gold); }
.rv-meter.low > span { background: var(--danger); }
.rv-tally { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; }
.rv-tally-bit { font-size: .72rem; font-weight: 800; letter-spacing: .03em;
                padding: 3px 8px; border-radius: 999px; background: var(--neutral-bg); color: var(--muted); }
.rv-tally-bit.high { background: var(--success-bg); color: var(--success); }
.rv-tally-bit.fair { background: var(--gold-bg); color: var(--warning); }
.rv-tally-bit.low { background: var(--danger-bg); color: var(--danger); }

/* The chooser. Three doors, one open - the workspace used to draw every
   panel at once and ran to ~2,900px on a phone. */
.rv-chooser-label { font-size: .7rem; font-weight: 800; letter-spacing: .09em;
                    text-transform: uppercase; color: var(--muted); margin-bottom: 8px; }
/* The three doors on the review screen. `_panel_payment.html` wrote this same
   grid inline as well, which did nothing on a laptop and defeated the phone
   collapse below it - an inline style outranks a media query, so the three
   destinations stayed in three squeezed columns on a 390px screen
   (WO-036 item 4). The bottom margin came inline with it and belongs here. */
.rv-choices { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; margin-bottom: 14px; }
@media (max-width: 560px) { .rv-choices { grid-template-columns: minmax(0, 1fr); } }
.rv-choice { text-align: left; padding: 10px 12px; min-height: 44px; cursor: pointer;
             border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
             background: var(--surface); color: var(--ink); font: inherit; display: block; }
.rv-choice:hover { border-color: var(--navy-lighter); }
.rv-choice.active { border-color: var(--navy); background: var(--gold-bg); box-shadow: inset 0 0 0 1px var(--navy); }
.rv-choice-title { display: block; font-weight: 800; font-size: .92em; color: var(--navy); }
.rv-choice-note { display: block; font-size: .76em; color: var(--muted); margin-top: 2px; }
.rv-suggested { font-size: .62rem; font-weight: 800; letter-spacing: .05em; text-transform: uppercase;
                background: var(--navy); color: #fff; border-radius: 999px; padding: 2px 6px; margin-left: 4px; }
.rv-label { font-weight: 600; font-size: .9em; }
.rv-conf { font-size: .7rem; font-weight: 800; letter-spacing: .03em; white-space: nowrap;
           padding: 2px 7px; border-radius: 999px; background: var(--neutral-bg); color: var(--muted); }
.rv-conf.high { background: var(--success-bg); color: var(--success); }
.rv-conf.fair { background: var(--gold-bg); color: var(--warning); }
.rv-conf.low { background: var(--danger-bg); color: var(--danger); }
/* A badge carrying a list (the reports a night is missing): it wraps, or on a phone the page scrolls sideways (WO-058). */
.rv-conf.is-wrapping { white-space: normal; }
.form-control.missing { border-color: var(--danger); }
/* A value this system supplied rather than read off the paper. Marked on
   the box itself, not only in the chip beside it: a prefilled date that
   looks like a read one is the one prefill nothing on the document
   supports. */
.form-control.supplied { border-color: var(--gold); background: var(--gold-bg); }
.form-control.edited { border-color: var(--navy); box-shadow: 0 0 0 2px var(--gold-bg); }
.edited-chip { display: none; font-size: .75em; color: var(--navy); font-weight: 700; }
.form-group.was-edited .edited-chip { display: inline; }
.rv-warnings li { margin-bottom: 4px; }
.rv-worth > summary { cursor: pointer; list-style-position: outside; padding: 2px 0; }
.rv-worth > summary > .rv-meta { display: block; margin-top: 2px; }
.rv-worth[open] > summary { margin-bottom: 8px; }
.rv-meta { color: var(--muted); font-size: .86em; }
.payer-box[hidden] { display: none; }

/* ib:start ---------------- integrations: the Inbox as a workbench (WO-063) ----------------
   Review is one slim bar over three panes - the queue, the paper, the
   decision - that fill the window, each scrolling on its own, so the page
   itself never does and the paper never leaves the screen while its figures
   are being checked. Below 1024px the panes stack and the page scrolls. */
.ib-bench-page .app-main > .container { max-width: none; padding: 0; }
.ib-bench {
    display: grid;
    grid-template-columns: var(--ib-rail-w) minmax(0, 1fr) var(--ib-panel-w);
    grid-template-rows: auto minmax(0, 1fr);
    grid-template-areas: "bar bar bar" "rail paper panel";
    --ib-rail-w: 216px; --ib-panel-w: minmax(360px, 430px);
    background: var(--bg);
}
.ib-bench.rail-hidden { --ib-rail-w: 0px; }
.ib-bench.rail-hidden .ib-rail { display: none; }
@media (min-width: 1024px) {
    .ib-bench-page .app-main { height: 100vh; height: 100dvh; }
    .ib-bench-page .app-main > .container { display: flex; flex-direction: column; min-height: 0; overflow: hidden; }
    .ib-bench-page .app-main > .container > .flash-message { margin: 8px 12px 0; }
    .ib-bench { flex: 1 1 auto; min-height: 0; }
}
@media (min-width: 1500px) { .ib-bench { --ib-rail-w: 240px; --ib-panel-w: minmax(400px, 480px); } }

.ib-bar {
    grid-area: bar; display: flex; align-items: center; gap: 10px; min-width: 0;
    padding: 8px 14px; min-height: 52px;
    background: var(--surface); border-bottom: 1px solid var(--border);
}
.ib-bar-btn {
    width: 36px; height: 36px; flex: 0 0 36px; display: grid; place-items: center;
    border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface);
    color: var(--navy); cursor: pointer;
}
.ib-bar-btn:hover { border-color: var(--navy-lighter); }
.ib-bar-btn[aria-expanded="true"] { background: var(--neutral-bg); }
.ib-bar-back { font-size: .86em; font-weight: 700; color: var(--navy); text-decoration: none; white-space: nowrap; }
.ib-bar-back:hover { text-decoration: underline; }
.ib-bar-title { flex: 1 1 auto; min-width: 0; }
.ib-title { margin: 0; font-size: 1rem; line-height: 1.3; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ib-bar-meta { color: var(--muted); font-size: .78em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ib-bar-nav { display: flex; align-items: center; gap: 6px; flex: 0 0 auto; }
.ib-count { color: var(--muted); font-size: .8em; font-variant-numeric: tabular-nums; white-space: nowrap; margin-right: 2px; }

.ib-rail { grid-area: rail; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
           background: var(--surface); border-right: 1px solid var(--border); }
.ib-rail-head { position: sticky; top: 0; z-index: 1; display: flex; align-items: center; justify-content: space-between;
                padding: 10px 12px 8px; background: var(--surface); border-bottom: 1px solid var(--border);
                font-size: .7rem; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.ib-rail-list { list-style: none; margin: 0; padding: 4px 0; }
.ib-rail-item { display: block; padding: 7px 12px 7px 10px; border-left: 3px solid transparent;
                text-decoration: none; color: var(--ink); }
.ib-rail-item:hover { background: var(--neutral-bg); }
.ib-rail-item[aria-current="page"] { background: var(--gold-bg); border-left-color: var(--navy); }
.ib-rail-amt { display: block; font-weight: 800; font-size: .88em; color: var(--navy); font-variant-numeric: tabular-nums; }
.ib-rail-none { font-weight: 600; color: var(--muted); }
.ib-rail-name { display: block; font-size: .8em; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ib-rail-foot { padding: 8px 12px 12px; color: var(--muted); font-size: .8em; }

.ib-paper { grid-area: paper; min-width: 0; min-height: 0; display: flex; flex-direction: column; padding: 10px 12px; }
/* The paper (item 3): the pages as images at the pane's width, a strip of
   pages down the side, zoom by width and a quarter turn. `--ib-zoom` is set
   by integrations.js; 1 is the pane's width. The inner box takes its width
   from the zoom, not from its content, so a zoomed page overflows to the
   right and the bottom - the sides a scroll container can reach. */
.ib-paper-tools { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-bottom: 8px; }
.ib-paper-count { font-size: .8em; font-weight: 700; color: var(--navy); margin-right: 4px; }
.ib-zoom-group { display: inline-flex; }
.ib-zoom-group .btn { border-radius: 0; margin-left: -1px; }
.ib-zoom-group .btn:first-child { border-radius: var(--radius-sm) 0 0 var(--radius-sm); margin-left: 0; }
.ib-zoom-group .btn:last-child { border-radius: 0 var(--radius-sm) var(--radius-sm) 0; }
.ib-zoom { min-width: 52px; font-variant-numeric: tabular-nums; }
.ib-spacer { flex: 1 1 auto; min-width: 0; }
.ib-paper-body { flex: 1 1 auto; min-height: 0; display: flex; gap: 10px; }
.ib-sheet { flex: 1 1 auto; min-width: 0; min-height: 0; overflow: auto; overscroll-behavior: contain;
            border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--neutral-bg);
            -webkit-overflow-scrolling: touch; }
.ib-sheet:focus-visible { outline: 2px solid var(--navy); outline-offset: 2px; }
.ib-sheet.pannable { cursor: grab; }
.ib-sheet.grabbing { cursor: grabbing; user-select: none; }
.ib-sheet-inner { width: calc(100% * var(--ib-zoom, 1)); min-width: 0; margin: 0 auto; padding: 10px; }
.ib-page { margin: 0 0 10px; background: #fff; box-shadow: 0 1px 4px rgba(20,31,52,.18); }
.ib-page:last-child { margin-bottom: 0; }
.ib-page-img { display: block; width: 100%; height: auto; -webkit-user-drag: none; user-select: none; }
.ib-page.unreadable { padding: 24px; color: var(--muted); font-size: .88em; text-align: center; }
.ib-sheet-more { margin: 10px 0 0; color: var(--muted); font-size: .86em; text-align: center; }
.ib-strip { list-style: none; margin: 0; padding: 0 2px 0 0; flex: 0 0 112px; min-height: 0; overflow-y: auto;
            overscroll-behavior: contain; display: flex; flex-direction: column; gap: 10px; }
.ib-strip-page { display: flex; flex-direction: column; gap: 4px; }
.ib-strip-thumb { position: relative; display: block; width: 100%; padding: 0; cursor: pointer;
                  border: 2px solid var(--border); border-radius: 6px; background: #fff; overflow: hidden; }
.ib-strip-thumb img { display: block; width: 100%; height: auto; min-height: 60px; }
.ib-strip-page.is-current .ib-strip-thumb { border-color: var(--navy); }
.ib-strip-no { position: absolute; left: 4px; bottom: 4px; padding: 0 6px; border-radius: 999px;
               background: var(--navy); color: #fff; font-size: .7rem; font-weight: 800; }
.ib-strip-label { font-size: .72rem; color: var(--muted); line-height: 1.25; overflow-wrap: anywhere; }
.ib-strip-note { font-size: .72rem; font-weight: 700; color: var(--success); line-height: 1.25; }
.ib-strip-door { width: 100%; white-space: normal; line-height: 1.2; font-size: .72rem; padding: 5px 6px; }
.ib-paper-foot { margin-top: 6px; color: var(--muted); font-size: .76em; }

.ib-panel { grid-area: panel; min-width: 0; min-height: 0; display: flex; flex-direction: column;
            background: var(--surface); border-left: 1px solid var(--border); }
.ib-panel-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 12px 14px 16px; }
.ib-panel-body > .card, .ib-panel-body .rv-panel > .card { box-shadow: none; }

/* The decision panel (item 4). The head: the status, what it was read as
   and how sure, in one line. */
.ib-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.ib-head .badge { font-size: .72rem; }
.ib-read { font-weight: 800; color: var(--navy); font-size: .95em; }
.ib-read-pct { font-variant-numeric: tabular-nums; font-weight: 800; font-size: .82em; }
.ib-read-pct.high { color: var(--success); } .ib-read-pct.fair { color: var(--warning); } .ib-read-pct.low { color: var(--danger); }
.ib-head-why { margin-top: 2px; }
.ib-block { margin-top: 10px; }

/* Warnings that matter, as chips. A chip with more to say is a <details>
   whose summary is the chip. */
.ib-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.ib-chip { display: inline-flex; align-items: center; gap: 5px; padding: 3px 10px; border-radius: 999px;
           font-size: .74rem; font-weight: 800; line-height: 1.5; text-decoration: none;
           background: var(--gold-bg); color: var(--warning); border: 1px solid var(--gold); cursor: pointer; }
.ib-chip.is-bad { background: var(--danger-bg); color: var(--danger); border-color: var(--danger); }
.ib-chip-d > summary { list-style: none; }
.ib-chip-d > summary::-webkit-details-marker { display: none; }
.ib-chip-d[open] { flex: 1 0 100%; }
.ib-chip-body { margin-top: 6px; padding: 8px 10px; border: 1px solid var(--gold); border-radius: var(--radius-sm);
                background: var(--gold-bg); font-size: .84em; color: var(--ink); }
.ib-chip-body ul { margin: 4px 0 0; padding-left: 18px; }

/* The kind: one segmented line, 1 2 3 on the keyboard. */
.ib-seg { display: flex; margin-top: 12px; border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
          overflow: hidden; background: var(--surface); }
.ib-seg-btn { flex: 1 1 0; min-width: 0; min-height: 38px; padding: 6px 8px; border: 0; border-left: 1px solid var(--border-strong);
              background: none; font: inherit; font-size: .84em; font-weight: 700; color: var(--ink); cursor: pointer; }
.ib-seg-btn:first-child { border-left: 0; }
.ib-seg-btn:hover { background: var(--neutral-bg); }
.ib-seg-btn.active { background: var(--navy); color: #fff; }
.ib-seg-sug { display: inline-block; width: 7px; height: 7px; margin-left: 5px; border-radius: 50%;
              background: var(--gold); vertical-align: middle; }
.ib-seg-key { display: inline-block; margin-right: 5px; font-size: .72em; opacity: .6; font-variant-numeric: tabular-nums; }

/* A door: its title, and how many boxes to check. */
.ib-door { margin-top: 12px; }
.ib-door-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; flex-wrap: wrap; margin-bottom: 4px; }
.ib-door-title { margin: 0; font-size: 1rem; }
.ib-check-line { font-size: .8em; color: var(--warning); }
.ib-check-line.is-clear { color: var(--success); }

/* The boxes, two to a row. Quiet: read confidently, a tick and nothing
   else. Check: amber, and first in the tab order. Plain: never scored. */
.ib-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px 12px; }
.ib-grid > .ib-field { margin: 0; min-width: 0; }
.ib-grid > .ib-field.is-wide { grid-column: 1 / -1; }
.ib-field .form-group { margin: 0; }
.form-group.ib-field .ib-field-label, .ib-field .form-group label { margin-bottom: 4px; font-size: .78em; font-weight: 700; color: var(--muted); }
.ib-field .form-control { min-height: 36px; padding: 6px 10px; }
.ib-field.is-quiet .form-control { border-color: var(--border); background: var(--surface); }
.ib-field.is-check .form-control { border-color: var(--gold); background: var(--gold-bg); }
.ib-field.is-check .ib-field-label, .ib-field.is-check .form-group label { color: var(--warning); }
.ib-field .form-control:focus { border-color: var(--navy); box-shadow: 0 0 0 3px rgba(20,31,52,.12); background: var(--surface); }
.ib-field .form-control.edited { border-color: var(--navy); background: var(--surface); box-shadow: 0 0 0 2px var(--gold-bg); }
.ib-tick { color: var(--success); font-weight: 800; margin-left: 2px; }
.ib-field-hint { margin-top: 3px; font-size: .74em; color: var(--muted); }
.ib-field.is-check .ib-field-hint { color: var(--warning); }
.ib-counter { margin-top: 12px; }

/* The notes and the history, one line each until opened. */
.ib-fold { margin-top: 12px; border-top: 1px solid var(--border); padding-top: 8px; }
.ib-fold > summary { cursor: pointer; font-size: .84em; font-weight: 700; color: var(--navy); }
.ib-fold[open] > summary { margin-bottom: 6px; }
.ib-fold ul { margin: 0; }

/* The payment door's three destinations and Something else's doors (item 6). */
.ib-seg.is-sub { margin-top: 8px; }
.ib-seg.is-sub .ib-seg-btn { font-size: .78em; min-height: 34px; }
.ib-seg.is-sub .ib-seg-btn.active { background: var(--gold-bg); color: var(--navy); box-shadow: inset 0 -2px 0 var(--navy); }
.ib-door-section { padding: 12px 0; border-top: 1px solid var(--border); }
.ib-door-section:first-child { border-top: 0; padding-top: 4px; }
.ib-door-section.is-lead { padding: 12px; border: 1px solid var(--gold); border-radius: var(--radius-sm); background: var(--gold-bg); }
.ib-door-section.is-lead + .ib-door-section { border-top: 0; }
.ib-door-section.is-danger .ib-section-title { color: var(--danger); }
.ib-section-title { margin: 0 0 6px; font-size: .92rem; color: var(--navy); }

/* The pinned bar (item 5): under the panel's scrolling body, never inside
   it, so File is on the screen whatever has been scrolled. It wraps: with no
   script (or a stale one) every door's buttons are in it at once, and a
   door that could shrink under its nowrap buttons laid them on top of one
   another (2026-09-18). */
.ib-actionbar { position: relative; flex: 0 0 auto; display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 10px 14px;
                background: var(--surface); border-top: 1px solid var(--border);
                box-shadow: 0 -6px 16px rgba(20,31,52,.06); }
.ib-bar-door { display: flex; flex-wrap: wrap; gap: 8px; }
.ib-actionbar .btn { white-space: nowrap; }
.ib-bar-door[hidden] { display: none; }
.ib-keys-btn { min-width: 32px; font-weight: 800; }
.ib-more { position: relative; }
.ib-more > summary { list-style: none; }
.ib-more > summary::-webkit-details-marker { display: none; }
.ib-more-menu { position: absolute; right: 0; bottom: calc(100% + 6px); z-index: 20; min-width: 190px;
                display: flex; flex-direction: column; padding: 6px; background: var(--surface);
                border: 1px solid var(--border); border-radius: var(--radius-sm); box-shadow: var(--shadow-md); }
.ib-more-item { display: block; width: 100%; padding: 8px 10px; border: 0; border-radius: 6px; background: none;
                font: inherit; font-size: .88em; color: var(--ink); text-align: left; text-decoration: none; cursor: pointer; }
.ib-more-item:hover, .ib-more-item:focus-visible { background: var(--neutral-bg); }

/* The keys, behind `?`. */
.ib-keys { width: min(440px, calc(100vw - 32px)); padding: 18px 20px; border: 1px solid var(--border);
           border-radius: var(--radius); background: var(--surface); color: var(--ink); box-shadow: var(--shadow-md); }
.ib-keys::backdrop { background: rgba(14,23,46,.45); }
.ib-keys h3 { margin: 0 0 10px; }
.ib-keys-list { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 8px 14px; margin: 0; font-size: .88em; }
.ib-keys-list dt { white-space: nowrap; }
.ib-keys-list dd { margin: 0; color: var(--muted); }
.ib-keys kbd, .ib-actionbar kbd { display: inline-block; min-width: 22px; padding: 1px 6px; border: 1px solid var(--border-strong);
                                  border-bottom-width: 2px; border-radius: 5px; background: var(--neutral-bg);
                                  font: 700 .82rem/1.4 inherit; text-align: center; color: var(--navy); }
.ib-keys-foot { margin-top: 14px; text-align: right; }
.ib-hint-toast { position: absolute; right: 14px; bottom: calc(100% + 8px); padding: 6px 10px; border-radius: var(--radius-sm);
                 background: var(--navy); color: #fff; font-size: .8em; pointer-events: none; }

/* The Inbox as a worklist (item 8): one 52px line a document - what it is in
   words over the file's name, the amount, and how long it has waited. */
.ib-list { list-style: none; margin: 0; padding: 0; }
.ib-list-head { display: flex; align-items: center; gap: 10px; padding: 6px 12px 6px 0;
                border-bottom: 1px solid var(--border); font-size: .76em; color: var(--muted); }
.ib-row { display: flex; align-items: center; min-height: 52px; border-bottom: 1px solid var(--border); }
.ib-row:last-child { border-bottom: 0; }
.ib-row:hover { background: var(--neutral-bg); }
.ib-row-tick { flex: 0 0 40px; display: grid; place-items: center; align-self: stretch; }
.ib-row-tick input { width: 18px; height: 18px; margin: 0; cursor: pointer; }
.ib-row-link { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; gap: 12px;
               padding: 6px 14px; color: inherit; text-decoration: none; }
.ib-row.has-tick .ib-row-link { padding-left: 0; }
.ib-row-thumb { flex: 0 0 30px; width: 30px; height: 38px; object-fit: cover; object-position: top;
                border: 1px solid var(--border); border-radius: 4px; background: var(--neutral-bg); }
.ib-row-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.ib-row-what { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: .9em; font-weight: 700; color: var(--navy); }
.ib-row-file { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: .76em; color: var(--muted); }
.ib-row-amt { flex: 0 0 auto; min-width: 100px; text-align: right; font-size: .9em; font-weight: 700;
              font-variant-numeric: tabular-nums; color: var(--ink); white-space: nowrap; }
.ib-row-amt.is-none { font-weight: 400; color: var(--muted); }
.ib-row .badge { flex: 0 0 auto; }
.ib-row > .ib-row-amt, .ib-row > .badge { margin-left: 12px; }
.ib-row > .age-chip { margin: 0 14px 0 12px; }
.ib-row-went { flex: 0 1 auto; min-width: 0; max-width: 30%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
               font-size: .8em; font-weight: 700; }
.age-chip { flex: 0 0 auto; min-width: 60px; padding: 2px 8px; border-radius: 999px; text-align: center;
            font-size: .72rem; font-weight: 800; font-variant-numeric: tabular-nums; white-space: nowrap; }
.age-chip.is-fresh { background: var(--neutral-bg); color: var(--muted); }
.age-chip.is-warm { background: var(--gold-bg); color: var(--warning); }
.age-chip.is-old { background: var(--danger-bg); color: var(--danger); }
.age-chip.is-settled { background: none; color: var(--muted); font-weight: 600; }
/* The groups on Needs you (item 9): a head that says what to do, how many
   and how much, and the rows under it. eZee's reports start folded. */
.ib-group { border-bottom: 1px solid var(--border); }
.ib-group:last-of-type { border-bottom: 0; }
.ib-group-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; padding: 10px 14px;
                 background: var(--neutral-bg); cursor: pointer; list-style: none; }
.ib-group-head::-webkit-details-marker { display: none; }
.ib-group-head::before { content: '\25B8'; color: var(--muted); font-size: .8em; transition: transform .15s ease; }
.ib-group[open] > .ib-group-head::before { transform: rotate(90deg); }
.ib-group-title { font-weight: 800; color: var(--navy); font-size: .92em; }
.ib-group-count { padding: 0 8px; border-radius: 999px; background: var(--surface); border: 1px solid var(--border);
                  font-size: .76rem; font-weight: 800; color: var(--navy); font-variant-numeric: tabular-nums; }
.ib-group-total { font-size: .86em; font-weight: 800; color: var(--ink); font-variant-numeric: tabular-nums; }
.ib-group-note { font-size: .78em; color: var(--muted); }
/* The drop (item 10): one slim line, the explanation behind How this works,
   and the whole page as the target - the overlay shows while a file is
   dragged over the window. */
.ib-drop { margin-bottom: 16px; padding: 10px 14px; border: 1px dashed var(--border-strong);
           border-radius: var(--radius); background: var(--surface); }
.ib-drop-line { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.ib-drop-icon { display: grid; place-items: center; width: 34px; height: 34px; flex: 0 0 34px;
                border-radius: 50%; background: var(--gold-bg); color: var(--navy); }
.ib-drop-zone { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.ib-drop-zone[hidden] { display: none; }
.ib-drop-text { font-size: .9em; font-weight: 600; color: var(--navy); }
.ib-drop-input { flex: 1 1 220px; width: auto; }
.ib-how { margin-left: auto; }
.ib-how > summary { cursor: pointer; font-size: .84em; font-weight: 700; color: var(--info); }
.ib-how[open] { flex: 1 0 100%; margin-left: 0; }
.ib-how-body { margin-top: 8px; padding-top: 10px; border-top: 1px solid var(--border); font-size: .88em; color: var(--ink); }
.ib-up-queue { margin-top: 8px; }
.ib-up-row { display: flex; align-items: center; gap: 10px; padding: 8px 0; border-bottom: 1px solid var(--border); }
.ib-up-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
              font-size: .88em; font-weight: 600; color: var(--navy); }
.ib-up-note { font-size: .78em; color: var(--muted); white-space: nowrap; }
.ib-up-bar { flex: 0 0 110px; width: 110px; height: 6px; border-radius: 999px; background: var(--neutral-bg); overflow: hidden; }
.ib-up-fill { height: 100%; width: 0%; background: var(--gold); transition: width .2s ease; }
.ib-drop-overlay { position: fixed; inset: 0; z-index: 60; display: grid; place-items: center; padding: 24px;
                   background: rgba(14,23,46,.55); pointer-events: none; }
.ib-drop-overlay[hidden] { display: none; }
.ib-drop-overlay-box { padding: 28px 36px; border: 3px dashed var(--gold); border-radius: var(--radius);
                       background: var(--surface); color: var(--navy); font-size: 1.15rem; font-weight: 800; }
/* The filters and the bulk bar (item 11). */
.ib-inbox-head { margin-bottom: 12px; align-items: center; }
.ib-inbox-head h2 { margin-bottom: 2px; }
.ib-inbox-head + .ib-drop, .ib-drop { margin-bottom: 12px; }
.ib-filters { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 12px 0; }
.ib-search { flex: 1 1 220px; max-width: 360px; min-height: 36px; border-radius: 999px; padding: 6px 14px; }
.ib-chip-select { min-height: 36px; padding: 6px 30px 6px 14px; border: 1px solid var(--border-strong); border-radius: 999px;
                  background-color: var(--surface); font: inherit; font-size: .84em; font-weight: 600; color: var(--ink);
                  max-width: 220px; cursor: pointer; }
.ib-chip-select.is-on { border-color: var(--navy); background-color: var(--navy); color: #fff; }
.ib-chip-clear { font-size: .84em; font-weight: 700; }
.ib-export { position: relative; }
.ib-export > summary { list-style: none; }
.ib-export > summary::-webkit-details-marker { display: none; }
.ib-export-menu { position: absolute; right: 0; top: calc(100% + 6px); z-index: 20; display: flex; flex-direction: column; gap: 6px;
                  padding: 8px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-sm);
                  box-shadow: var(--shadow-md); white-space: nowrap; }
.ib-list-head .btn { margin-left: auto; }
.ib-bulk { position: sticky; bottom: 12px; z-index: 5; display: flex; align-items: center; gap: 12px; margin: 8px;
           padding: 10px 14px; border-radius: var(--radius); background: var(--navy); color: #fff; box-shadow: var(--shadow-md); }
.ib-bulk[hidden] { display: none; }
.ib-bulk .bulk-hint { flex: 1 1 auto; color: rgba(255,255,255,.85); }
@media (max-width: 600px) {
    .ib-row-link { gap: 8px; padding-right: 6px; }
    .ib-row > .ib-row-amt, .ib-row > .badge { margin-left: 6px; }
    .ib-row > .age-chip { margin: 0 10px 0 6px; }
    .ib-row-went { display: none; }
    .ib-up-bar { flex-basis: 60px; width: 60px; }
    .ib-up-note { display: none; }
    .ib-search { max-width: none; flex-basis: 100%; }
    .ib-bulk { bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom) + 8px); }
    .ib-row-amt { min-width: 0; font-size: .84em; }
    .age-chip { min-width: 0; padding: 2px 6px; }
    .ib-row .badge { display: none; }
}

@media (max-width: 1023.98px) {
    .ib-bench { grid-template-columns: minmax(0, 1fr); grid-template-areas: "bar" "rail" "paper" "panel"; }
    .ib-rail { max-height: 40vh; border-right: 0; border-bottom: 1px solid var(--border); }
    .ib-bench:not(.rail-shown) .ib-rail { display: none; }
    .ib-paper-body { flex-direction: column; }
    .ib-sheet { height: 62vh; flex: none; }
    .ib-strip { flex: none; flex-direction: row; overflow-x: auto; overflow-y: hidden; padding: 0 0 4px; }
    .ib-strip-page { flex: 0 0 84px; }
    .ib-panel { border-left: 0; }
    .ib-panel-body { overflow: visible; }
    .ib-bar { flex-wrap: wrap; gap: 8px; padding: 8px 12px; min-height: 0; }
    .ib-bar-title { flex-basis: calc(100% - 140px); }
    .ib-bar-meta, .ib-bar-download, .ib-nav-word, .ib-keys-btn { display: none; }
    .ib-bar-nav { margin-left: auto; }

    /* Item 7: Paper and Details as two tabs, the bar under both. */
    .ib-bench { grid-template-areas: "bar" "tabs" "rail" "paper" "panel"; }
    .ib-bench.has-tabs .ib-tabs { grid-area: tabs; display: flex; position: sticky; top: var(--topbar-h); z-index: 6;
                                  background: var(--surface); border-bottom: 1px solid var(--border); }
    .ib-tab { flex: 1 1 0; min-height: 44px; padding: 6px 8px; border: 0; border-bottom: 3px solid transparent;
              background: none; font: inherit; font-weight: 800; font-size: .9em; color: var(--muted); cursor: pointer; }
    .ib-tab[aria-selected="true"] { color: var(--navy); border-bottom-color: var(--navy); }
    .ib-tab-count { font-weight: 600; font-size: .82em; color: var(--warning); }
    .ib-bench.has-tabs[data-view="details"] .ib-paper { display: none; }
    .ib-bench.has-tabs[data-view="paper"] .ib-panel-body { display: none; }
    .ib-bench.has-tabs .ib-sheet { height: calc(100vh - 290px); height: calc(100dvh - 290px); min-height: 300px; }
    /* Fixed, not sticky: on the Paper tab the panel holds nothing but the
       bar, and a sticky element cannot leave its own container. */
    .ib-actionbar { position: fixed; left: 0; right: 0; bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom));
                    z-index: 24; padding: 8px 12px; }
    .ib-bench-page .app-main > .container { padding-bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom) + 84px); }
    .ib-actionbar .btn { flex: 1 1 auto; }
    .ib-bar-door { flex: 1 1 auto; }
}
.ib-tabs { display: none; }
/* ib:end */

/* dk:start ---------------- cashbook: the desk sheet as the drawer (WO-065) ----------------
   /cash/desk/. The seven days (dk-day), the drawer strip (dk-strip), the quick
   entry (dk-entry), the rows (dk-row), the foot and the count. docs/DESIGN.md
   §5 names each; keep both markers. */
.dk-days { display: flex; flex-wrap: wrap; align-items: stretch; gap: 8px; margin: 0 0 16px; }
.dk-day { display: inline-flex; flex-direction: column; justify-content: center; gap: 2px; min-width: 96px;
          padding: 8px 12px; border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
          background: var(--surface); color: var(--ink); line-height: 1.25; text-decoration: none; }
.dk-day:hover { border-color: var(--navy-lighter); text-decoration: none; }
.dk-day-name { font-size: .78em; font-weight: 700; color: var(--muted); }
.dk-day-total { font-size: .92em; font-weight: 700; color: var(--navy); font-variant-numeric: tabular-nums; white-space: nowrap; }
.dk-day-total.is-empty { font-weight: 500; color: var(--muted-light); }
.dk-day.is-today .dk-day-name { color: var(--gold-ink); }
.dk-day.is-on { border-color: var(--navy); background: var(--navy); }
.dk-day.is-on .dk-day-name, .dk-day.is-on .dk-day-total { color: #fff; }
.dk-day.is-on.is-today .dk-day-name { color: var(--gold); }
.dk-day-other { display: flex; align-items: center; gap: 6px; margin-left: auto; }
.dk-day-other .form-control { width: auto; min-width: 0; }
@media (max-width: 600px) {
    .dk-days { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; }
    .dk-day { min-width: 0; padding: 6px 8px; }
    .dk-day-other { grid-column: 1 / -1; margin-left: 0; }
    .dk-day-other .form-control { flex: 1 1 auto; }
}
/* The drawer strip (item 2): four cells, the last one what should be there. */
.dk-strip { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); margin: 0 0 16px; overflow: hidden;
            border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); box-shadow: var(--shadow-sm); }
.dk-cell { display: flex; flex-direction: column; gap: 4px; min-width: 0; padding: 14px 16px; border-left: 1px solid var(--border); }
.dk-cell:first-child { border-left: 0; }
.dk-cell-label { font-size: .74em; font-weight: 700; letter-spacing: .03em; text-transform: uppercase; color: var(--muted); }
.dk-cell-value { font-size: 1.35rem; font-weight: 800; line-height: 1.15; color: var(--navy); font-variant-numeric: tabular-nums; }
.dk-cell-value.is-unknown { font-weight: 600; color: var(--muted-light); }
.dk-cell-note { font-size: .8em; line-height: 1.35; color: var(--muted); }
.dk-strip { margin-bottom: 0; border-radius: var(--radius) var(--radius) 0 0; }
.dk-cell-lead { background: var(--gold-bg); }
/* Count the drawer (item 6): the day's last count and its difference, under
   the strip and joined to it, with the button that opens the count. */
.dk-count-line { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px; margin: 0 0 16px; padding: 10px 16px;
                 border: 1px solid var(--border); border-top: 0; border-radius: 0 0 var(--radius) var(--radius); background: var(--surface-2); }
.dk-count-said { font-size: .88em; color: var(--ink); }
.dk-count-gap { padding: 2px 10px; border-radius: 999px; font-size: .8em; font-weight: 700; white-space: nowrap; }
.dk-count-gap.is-short { background: var(--danger-bg); color: var(--danger); }
.dk-count-gap.is-over { background: var(--warning-bg); color: var(--warning); }
.dk-count-gap.is-exact { background: var(--success-bg); color: var(--success); }
.dk-count-gap.is-unknown { padding: 0; font-weight: 500; white-space: normal; color: var(--muted); }
.dk-count { position: relative; margin-left: auto; }
.dk-count > summary { list-style: none; }
.dk-count > summary::-webkit-details-marker { display: none; }
.dk-count-pop { position: absolute; top: calc(100% + 6px); right: 0; z-index: 20; display: flex; flex-direction: column; gap: 10px; width: 300px;
                max-width: calc(100vw - 32px); padding: 14px; border: 1px solid var(--border); border-radius: var(--radius-sm);
                background: var(--surface); box-shadow: var(--shadow-md); }
.dk-count-says { margin: 0; font-size: .82em; color: var(--muted); }
.dk-cell-lead .dk-cell-value { color: var(--ink); }
@media (max-width: 600px) {
    /* Item 9: the strip scrolls sideways, what should be there first. */
    .dk-strip { display: flex; overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x mandatory; }
    .dk-cell { flex: 0 0 58%; padding: 10px 12px; scroll-snap-align: start; }
    .dk-cell:first-child { border-left: 1px solid var(--border); }
    .dk-cell-lead { order: -1; border-left: 0; }
    .dk-cell-value { font-size: 1.1rem; }
}
/* The quick entry (item 3): chips, four fields and Save on one line; the
   near-name question inside it; the saved row flashing where it lands. */
.dk-entry { margin: 0 0 16px; padding: 16px 18px; }
.dk-question { margin: 0 0 14px; padding: 12px 14px; border: 1px solid var(--gold); border-radius: var(--radius-sm); background: var(--warning-bg); }
.dk-question-title { margin: 0 0 4px; font-size: 1rem; color: var(--ink); }
.dk-question-why { margin: 0 0 10px; font-size: .9em; color: var(--ink); }
.dk-chips { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 0 0 12px; }
.dk-chips[hidden] { display: none; }
.dk-chips-label { margin-right: 4px; font-size: .74em; font-weight: 700; letter-spacing: .03em; text-transform: uppercase; color: var(--muted); }
.dk-chip { min-height: 32px; max-width: 220px; padding: 4px 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
           border: 1px solid var(--border-strong); border-radius: 999px; background: var(--surface); color: var(--ink);
           font: inherit; font-size: .85em; font-weight: 600; cursor: pointer; }
.dk-chip:hover { border-color: var(--navy-lighter); }
.dk-chip.is-on { border-color: var(--navy); background: var(--navy); color: #fff; }
.dk-entry-fields { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, 1.6fr) minmax(0, .8fr) auto auto; align-items: end; gap: 10px; }
.dk-field { display: flex; flex-direction: column; gap: 4px; min-width: 0; margin: 0; }
.dk-field-label { font-size: .76em; font-weight: 700; color: var(--muted); }
.dk-amount { text-align: right; font-weight: 700; font-variant-numeric: tabular-nums; }
.dk-camera { position: relative; display: inline-flex; align-items: center; justify-content: center; min-height: 40px; margin: 0; padding: 0 16px;
             border: 1px dashed var(--border-strong); border-radius: 999px; background: var(--surface-2); color: var(--navy);
             font-size: .88em; font-weight: 700; white-space: nowrap; cursor: pointer; }
.dk-camera:hover, .dk-camera:focus-within { border-color: var(--navy); }
.dk-camera.is-on { border-style: solid; border-color: var(--success); background: var(--success-bg); color: var(--success); }
.dk-camera-input { position: absolute; width: 1px; height: 1px; overflow: hidden; opacity: 0; }
.dk-save { min-height: 40px; }
.dk-entry-note { margin: 10px 0 0; font-size: .8em; color: var(--muted); }
@keyframes dk-arrive { from { background-color: var(--gold-bg); } to { background-color: transparent; } }
.dk-row.is-new { animation: dk-arrive 2.4s ease-out; }
@media (prefers-reduced-motion: reduce) { .dk-row.is-new { animation: none; background-color: var(--gold-bg); } }
/* Item 9: the day is one column; on a phone the entry comes first, the
   amount leads it, large, and Save and the camera share the last line. */
.dk-day-page { display: flex; flex-direction: column; min-width: 0; }
@media (max-width: 600px) {
    .dk-entry { order: -1; padding: 12px; }
    .dk-entry-form { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 10px;
                     grid-template-areas: "amount amount" "chips chips" "payee payee" "what what" "save camera" "note note"; }
    .dk-entry-fields { display: contents; }
    .dk-field-amount { grid-area: amount; }
    .dk-chips { grid-area: chips; margin: 0; }
    .dk-field-payee { grid-area: payee; }
    .dk-field-what { grid-area: what; }
    .dk-save { grid-area: save; min-height: 48px; }
    .dk-camera { grid-area: camera; min-height: 48px; }
    .dk-entry-note { grid-area: note; margin: 0; }
    .dk-amount { min-height: 60px; font-size: 1.75rem; }
}
/* The rows (item 4): a grid a row - number, payee over what for, the voucher
   chip and receipt mark, the amount over its running total, the menu. */
.dk-sheet { margin: 0 0 16px; padding: 0; }
.dk-rows { margin: 0; padding: 0; list-style: none; }
.dk-row { display: grid; grid-template-columns: 28px minmax(0, 1fr) auto 112px 36px; align-items: center; gap: 12px;
          padding: 12px 16px; border-bottom: 1px solid var(--border); }
.dk-rows > .dk-row:last-child { border-bottom: 0; }
.dk-no { font-size: .82em; font-weight: 700; text-align: right; color: var(--muted-light); font-variant-numeric: tabular-nums; }
.dk-what { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.dk-payee { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 700; color: var(--navy); }
.dk-for { font-size: .88em; color: var(--ink); overflow-wrap: anywhere; }
.dk-marks { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 6px; }
.dk-voucher { display: inline-flex; align-items: center; padding: 2px 10px; border-radius: 999px; background: var(--success-bg);
              color: var(--success); font-size: .78em; font-weight: 700; white-space: nowrap; }
.dk-voucher.is-missing { background: var(--neutral-bg); color: var(--muted); font-weight: 600; }
.dk-receipt { font-size: .78em; font-weight: 600; white-space: nowrap; color: var(--muted-light); }
.dk-receipt.is-on { font-weight: 700; color: var(--info); }
.dk-row-amount { display: flex; flex-direction: column; align-items: flex-end; gap: 1px; }
.dk-amount-value { font-size: 1.02rem; font-weight: 800; color: var(--ink); font-variant-numeric: tabular-nums; }
.dk-running { font-size: .74em; white-space: nowrap; color: var(--muted); font-variant-numeric: tabular-nums; }
.dk-menu { position: relative; justify-self: end; }
.dk-menu > summary { display: grid; place-items: center; width: 32px; height: 32px; border-radius: var(--radius-sm); list-style: none;
                     font-size: 1.2rem; line-height: 1; color: var(--muted); cursor: pointer; }
.dk-menu > summary::-webkit-details-marker { display: none; }
.dk-menu > summary:hover, .dk-menu[open] > summary { background: var(--neutral-bg); color: var(--navy); }
.dk-menu-pop { position: absolute; top: calc(100% + 6px); right: 0; z-index: 20; display: flex; flex-direction: column; gap: 8px; width: 260px;
               padding: 12px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface); box-shadow: var(--shadow-md); }
.dk-withdrawn { border-top: 1px solid var(--border); }
.dk-withdrawn > summary { padding: 10px 16px; font-size: .84em; font-weight: 700; color: var(--muted); cursor: pointer; }
.dk-row.is-withdrawn { grid-template-columns: minmax(0, 1fr); gap: 2px; color: var(--muted); }
.dk-why { font-size: .82em; }
/* The foot (item 5): rows, receipts n of m and the total on one line, then
   eZee's vouchers with no row, each with its amount. */
.dk-foot { display: flex; flex-direction: column; gap: 10px; padding: 12px 16px; border-top: 1px solid var(--border);
           border-radius: 0 0 var(--radius) var(--radius); background: var(--surface-2); }
.dk-foot-line { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 16px; }
.dk-foot-count { font-weight: 700; color: var(--ink); }
.dk-foot-receipts { font-size: .84em; font-weight: 600; color: var(--warning); }
.dk-foot-receipts.is-all { color: var(--success); }
.dk-foot-sum { display: inline-flex; align-items: baseline; gap: 8px; margin-left: auto; }
.dk-foot-label { font-size: .78em; font-weight: 700; letter-spacing: .03em; text-transform: uppercase; color: var(--muted); }
.dk-foot-total { font-size: 1.05rem; font-weight: 800; color: var(--navy); font-variant-numeric: tabular-nums; }
.dk-foot-vouchers { display: flex; flex-direction: column; gap: 6px; padding-top: 10px; border-top: 1px dashed var(--border-strong); }
.dk-foot-list { display: flex; flex-direction: column; gap: 4px; margin: 0; padding: 0; list-style: none; font-size: .88em; overflow-wrap: anywhere; }
.dk-voucher.is-open { background: var(--warning-bg); color: var(--warning); }
@media (max-width: 600px) {
    .dk-row { grid-template-columns: 20px minmax(0, 1fr) auto 32px; grid-template-areas: "no what amount menu" ". marks marks ."; gap: 4px 10px; padding: 10px 12px; }
    .dk-no { grid-area: no; }
    .dk-what { grid-area: what; }
    .dk-row-amount { grid-area: amount; }
    .dk-menu { grid-area: menu; }
    .dk-marks { grid-area: marks; justify-content: flex-start; }
    .dk-row.is-withdrawn { grid-template-areas: none; }
}
/* dk:end */

/* ---------------- payroll: employee form ----------------
   Lifted from payroll/templates/payroll/employee_form.html on 2026-09-05
   (WO-019 B6); the rules are unchanged. */
details.editor-section > summary {
    cursor: pointer; list-style: none; display: flex; align-items: center; justify-content: space-between;
    gap: 12px; color: var(--navy); font-size: 1.05rem; font-weight: 700;
}
details.editor-section > summary::-webkit-details-marker { display: none; }
details.editor-section > summary::after { content: '+'; color: var(--gold); font-size: 1.35rem; }
details.editor-section[open] > summary::after { content: '\2212'; }
details.editor-section[open] > summary { margin-bottom: 16px; padding-bottom: 12px; border-bottom: 1px solid var(--border); }
.employee-savebar {
    position: sticky; bottom: 12px; z-index: 5; margin-top: 18px; padding: 12px 14px;
    display: flex; justify-content: flex-end; align-items: center; gap: 10px;
    border: 1px solid var(--border); border-radius: var(--radius); background: rgba(255,255,255,.96);
    box-shadow: 0 10px 30px rgba(20,31,52,.14); backdrop-filter: blur(8px);
}
@media (max-width: 620px) {
    .employee-savebar { bottom: 8px; }
    .employee-savebar .btn { flex: 1; }
}

/* ---------------- payroll: people (WO-081) ----------------
   The employee list: tiles and department chips that filter, a find box, a
   Needs column. The page scrolls and the head row stays - `.ppl-list-card` is
   not `overflow: hidden`, so the head sticks to the window, under the top bar
   where there is one. On a phone each row is a card and nothing scrolls
   sideways. Not a `data-table`: that one sits in `.table-scroll` and holds
   640px, which are the two things this list must not do; it keeps the look. */
.ppl-tiles { display: grid; gap: var(--sp-3); grid-template-columns: repeat(auto-fit, minmax(min(100%, 150px), 1fr)); margin-bottom: var(--sp-4); }
.ppl-tile {
    display: flex; flex-direction: column; gap: 2px; min-width: 0;
    padding: var(--sp-3) var(--sp-4); border: 1px solid var(--border); border-radius: var(--radius-sm);
    background: var(--surface); box-shadow: var(--shadow-sm); color: var(--ink); text-decoration: none;
}
.ppl-tile b { font-size: 22px; font-weight: var(--fw-figure); letter-spacing: -0.02em; line-height: 1.15; font-variant-numeric: var(--num); }
.ppl-tile span { font-size: var(--fs-eyebrow); font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); }
.ppl-tile.is-on, .ppl-split a.is-on { box-shadow: inset 0 0 0 2px var(--navy); }
.ppl-tile.is-warn b { color: var(--warning); }
.ppl-tile.is-bad b { color: var(--danger); }
a.ppl-tile:hover { border-color: var(--border-strong); }
.ppl-split { flex-direction: row; align-items: stretch; gap: var(--sp-1); padding: var(--sp-1); }
.ppl-split a { flex: 1; display: flex; flex-direction: column; gap: 2px; padding: var(--sp-2) var(--sp-3); border-radius: 7px; color: var(--ink); text-decoration: none; }
.ppl-split a:hover { background: var(--surface-2); }
.ppl-bar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3); margin-bottom: var(--sp-3); }
.ppl-find { flex: 0 1 320px; min-width: 0; }
.ppl-find .form-control { width: 100%; }
.ppl-chips { display: flex; flex-wrap: wrap; gap: var(--sp-2); min-width: 0; }
.ppl-chips .kt-chip { min-height: 32px; text-decoration: none; }
.ppl-chips .kt-chip:hover { border-color: var(--navy-light); }
.ppl-chips .kt-chip.is-on { background: var(--navy); border-color: var(--navy); color: #fff; }
.ppl-count { font-variant-numeric: var(--num); color: var(--muted); }
.kt-chip.is-on .ppl-count { color: rgba(255,255,255,0.75); }
.ppl-list-card { padding: 0; }
table.ppl-table { width: 100%; border-collapse: collapse; }
table.ppl-table th {
    position: sticky; top: 0; z-index: 3;
    padding: 10px 14px; text-align: left; white-space: nowrap;
    font-size: var(--fs-eyebrow); font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase;
    color: var(--muted); background: var(--surface); border-bottom: 1px solid var(--border);
}
table.ppl-table th:first-child { border-top-left-radius: var(--radius); }
table.ppl-table th:last-child { border-top-right-radius: var(--radius); }
table.ppl-table td { height: 52px; padding: 8px 14px; border-bottom: 1px solid #EEF0F3; font-size: var(--fs-body); vertical-align: middle; }
table.ppl-table tbody tr:last-child td { border-bottom: none; }
table.ppl-table .num { text-align: right; font-variant-numeric: var(--num); }
table.ppl-table th a { color: inherit; text-decoration: none; }
table.ppl-table th a:hover { color: var(--ink); }
.ppl-row { position: relative; }
.ppl-row:hover { background: var(--surface-2); }
.ppl-row[hidden] { display: none; }
.ppl-who-in { display: flex; align-items: center; gap: var(--sp-3); min-width: 0; }
.ppl-name { display: flex; flex-wrap: wrap; align-items: center; gap: 2px var(--sp-2); min-width: 0; }
.ppl-name small, .ppl-pay small, .ppl-col-since small { flex-basis: 100%; display: block; color: var(--muted); font-size: var(--fs-small); }
.ppl-open, .ppl-name strong { color: var(--ink); font-weight: 600; text-decoration: none; }
/* The whole row opens the person; the menu sits above the stretched link. */
.ppl-open::after { content: ''; position: absolute; inset: 0; }
.ppl-open:focus-visible { outline: none; }
.ppl-row:has(.ppl-open:focus-visible) { box-shadow: inset 0 0 0 2px var(--info); }
.ppl-needs-in { display: flex; flex-wrap: wrap; gap: var(--sp-1); }
.ppl-actions { width: 52px; text-align: right; }
.ppl-menu { position: relative; z-index: 2; display: inline-block; }
.ppl-menu > summary {
    list-style: none; display: inline-grid; place-items: center; width: 44px; height: 36px;
    border-radius: var(--radius-sm); cursor: pointer; color: var(--muted); font-weight: 700;
}
.ppl-menu > summary::-webkit-details-marker { display: none; }
.ppl-menu > summary:hover, .ppl-menu[open] > summary { background: var(--neutral-bg); color: var(--ink); }
.ppl-menu-list {
    position: absolute; right: 0; top: calc(100% + 4px); z-index: 5; min-width: 190px;
    display: flex; flex-direction: column; padding: 6px; text-align: left;
    background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-sm); box-shadow: var(--shadow-md);
}
.ppl-menu-list a { padding: 10px 12px; border-radius: 7px; color: var(--ink); text-decoration: none; white-space: nowrap; }
.ppl-menu-list a:hover { background: var(--bg); }
/* Adding (WO-081 item 4): seven boxes on the left, what they make on the
   right, one screen at 1366x768. Choices are chips: a radio under each, so
   the keys and a screen reader still see a radio group. */
.ppl-add { display: grid; grid-template-columns: minmax(0, 1fr) minmax(260px, 320px); gap: var(--sp-4); align-items: start; }
.ppl-add-form { display: flex; flex-direction: column; gap: var(--sp-3); padding: var(--sp-4) var(--sp-5); }
.ppl-field { display: grid; grid-template-columns: 150px minmax(0, 1fr); gap: var(--sp-3); align-items: start; margin: 0; padding: 0; border: 0; min-width: 0; }
.ppl-field > label, .ppl-field > legend { float: left; padding-top: 9px; font-weight: 600; font-size: var(--fs-body); color: var(--ink-2); }
fieldset.ppl-field > legend { width: 150px; margin-right: var(--sp-3); }
fieldset.ppl-field { display: block; }
fieldset.ppl-field > div { margin-left: calc(150px + var(--sp-3)); }
.ppl-field .form-control { max-width: 360px; }
.ppl-choices { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.ppl-choice { position: relative; display: inline-flex; cursor: pointer; }
.ppl-choice input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.ppl-choice span {
    display: inline-flex; align-items: center; min-height: 36px; padding: 0 var(--sp-3);
    border: 1px solid var(--border-strong); border-radius: 999px; background: var(--surface);
    font-size: var(--fs-body); font-weight: 500; color: var(--ink); white-space: nowrap;
    transition: background .15s ease, border-color .15s ease, color .15s ease;
}
.ppl-choice:hover span { border-color: var(--navy-light); }
.ppl-choice input:checked + span { background: var(--navy); border-color: var(--navy); color: #fff; }
.ppl-choice input:focus-visible + span { outline: 2px solid var(--info); outline-offset: 2px; }
.ppl-paid { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-3); }
.ppl-figure { display: inline-flex; align-items: center; gap: var(--sp-2); font-weight: 600; color: var(--muted); }
.ppl-figure .form-control { width: 130px; }
.ppl-not-agreed { margin: 0; }
.ppl-namesake { padding: var(--sp-3) var(--sp-4); border-radius: var(--radius-sm); background: var(--warning-bg); color: var(--ink); }
.ppl-namesake ul { margin: var(--sp-2) 0; padding-left: 18px; }
.ppl-makes { position: sticky; top: var(--sp-4); display: flex; flex-direction: column; gap: var(--sp-3); padding: var(--sp-4) var(--sp-5); }
.ppl-makes h3 { margin: 0; font-size: var(--fs-eyebrow); font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); }
.ppl-makes-text { font-size: var(--fs-lead); line-height: 1.5; color: var(--ink); }
.ppl-makes-still { font-size: var(--fs-small); color: var(--muted); }
.ppl-makes-still:empty { display: none; }
.ppl-add-actions { display: flex; flex-direction: column; gap: var(--sp-2); }
.ppl-add-actions .btn { width: 100%; min-height: 44px; }
/* The person's page (WO-081 item 6): a head, the views as links, and cards
   in two columns - one on a phone. A card is read as a list of facts; its
   boxes replace it in place. */
.ppl-back { display: inline-block; margin-bottom: var(--sp-2); color: var(--muted); font-size: var(--fs-small); text-decoration: none; }
.ppl-back:hover { color: var(--ink); }
.ppl-head { display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--sp-4); padding: var(--sp-4) var(--sp-5); margin-bottom: var(--sp-3); }
.ppl-head-who { display: flex; gap: var(--sp-4); align-items: flex-start; min-width: 0; flex: 1 1 420px; }
.ppl-avatar { width: 56px; height: 56px; border-radius: 50%; flex: none; object-fit: cover; font-size: 1.05rem; }
.ppl-head-text { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.ppl-head-text h2 { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin: 0; font-size: 1.45rem; font-weight: 800; letter-spacing: -0.02em; overflow-wrap: anywhere; }
.ppl-head-line { color: var(--muted); font-size: var(--fs-body); overflow-wrap: anywhere; }
.ppl-head-actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: flex-start; }
.ppl-views { display: flex; gap: 2px; margin-bottom: var(--sp-4); border-bottom: 1px solid var(--border); flex-wrap: wrap; }
.ppl-views a { padding: 10px var(--sp-3); border-bottom: 2px solid transparent; margin-bottom: -1px; color: var(--muted); font-weight: 600; font-size: var(--fs-body); text-decoration: none; white-space: nowrap; }
.ppl-views a:hover { color: var(--ink); }
.ppl-views a.is-on { color: var(--ink); border-bottom-color: var(--gold); }
.ppl-cards { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-4); align-items: start; }
.ppl-card { padding: var(--sp-4) var(--sp-5); min-width: 0; scroll-margin-top: calc(var(--topbar-h) + var(--sp-3)); }
.ppl-card.ppl-wide { grid-column: 1 / -1; }
.ppl-card-head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); margin-bottom: var(--sp-3); }
.ppl-card-head h3 { margin: 0; font-size: var(--fs-eyebrow); font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); }
.ppl-facts { display: grid; grid-template-columns: minmax(0, 150px) minmax(0, 1fr); gap: var(--sp-2) var(--sp-3); margin: 0; }
.ppl-facts dt { color: var(--muted); font-size: var(--fs-body); }
.ppl-facts dd { margin: 0; font-size: var(--fs-body); color: var(--ink); overflow-wrap: anywhere; }
.ppl-card-form .form-group { margin-bottom: var(--sp-3); }
.ppl-card-actions { display: flex; gap: var(--sp-2); }
.ppl-card-actions .btn { min-height: 40px; }
.ppl-card.is-editing { box-shadow: 0 0 0 2px var(--navy-light), var(--shadow-sm); }
.ppl-timeline { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.ppl-timeline li { position: relative; padding: var(--sp-2) 0 var(--sp-3) var(--sp-5); border-left: 2px solid var(--border); }
.ppl-timeline li::before { content: ''; position: absolute; left: -6px; top: 12px; width: 10px; height: 10px; border-radius: 50%; background: var(--surface); border: 2px solid var(--border-strong); }
.ppl-timeline li.is-current::before { background: var(--success); border-color: var(--success); }
.ppl-timeline li.is-withdrawn .ppl-what { text-decoration: line-through; color: var(--muted); }
.ppl-when { font-size: var(--fs-small); color: var(--muted); }
.ppl-what { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1) var(--sp-2); font-size: var(--fs-body); }
.ppl-who { font-size: var(--fs-small); color: var(--muted); }
.ppl-list { margin: 0; padding-left: 18px; font-size: var(--fs-body); }
.ppl-list li { margin: 2px 0; }
.ppl-list li.is-withdrawn { color: var(--muted); text-decoration: line-through; }
.ppl-side-forms { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-5); margin-top: var(--sp-4); padding-top: var(--sp-4); border-top: 1px solid var(--border); }
.ppl-needs-in .pill.is-resolved { opacity: 0; transform: scale(.9); }
/* Change pay and Correct a mistake (WO-081 item 7). */
.ppl-card-links { display: inline-flex; flex-wrap: wrap; gap: var(--sp-2); }
.ppl-label { display: block; margin-bottom: 6px; font-weight: 600; font-size: var(--fs-body); color: var(--ink-2); }
.ppl-act-says { margin-bottom: var(--sp-3); padding: var(--sp-3); border-radius: var(--radius-sm); background: var(--info-bg); font-size: var(--fs-body); }
.ppl-act-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0 var(--sp-4); }
.ppl-act-grid [hidden] { display: none; }
/* ---------------- payroll: the slip (WO-082) ----------------
   The attendance block on the snapshot's page, the same classes the slip and
   its PDF read from payroll/_slip_days_style.html: 18px cells, one colour,
   absent alone red. The strip scrolls on its own at a phone's width. */
.sd-block { margin: 0; }
.sd-label { font-size: var(--fs-eyebrow); font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); margin-bottom: var(--sp-2); }
.sd-scroll { overflow-x: auto; padding-bottom: 2px; }
.sd-grid { display: flex; gap: 1px; }
.sd-cell { width: 18px; flex: 0 0 18px; display: flex; flex-direction: column; align-items: center; line-height: 1.2; font-size: 10px; font-variant-numeric: var(--num); color: var(--ink); }
.sd-wd { color: var(--muted); }
.sd-d { font-weight: 600; }
.sd-m { font-size: 12px; }
.sd-cell.is-absent .sd-m, .sd-key.is-absent b { color: var(--danger); }
.sd-counts { margin-top: var(--sp-2); font-weight: 600; font-size: var(--fs-body); }
.sd-legend { display: flex; flex-wrap: wrap; gap: 2px var(--sp-3); font-size: var(--fs-small); color: var(--muted); }
.sd-key b { color: var(--ink); }
/* Fill a column (WO-081 item 9): a bar that stays over the list while the
   boxes are filled, and one box a row. */
.ppl-fill-menu > summary.btn { display: inline-flex; width: auto; height: auto; color: var(--ink); }
.ppl-fill-bar .btn-primary { background: #fff; border-color: #fff; color: var(--navy); }
.ppl-fill-bar {
    position: sticky; top: 0; z-index: 4; display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-3);
    margin-bottom: var(--sp-3); padding: var(--sp-3) var(--sp-4); border-radius: var(--radius-sm);
    background: var(--navy); color: #fff; box-shadow: var(--shadow-md);
}
.ppl-fill-bar span { flex: 1 1 280px; }
.ppl-fill-cell .form-control { max-width: 280px; }
@media (max-width: 1023.98px) { .ppl-fill-bar { top: var(--topbar-h); } }
/* Papers (WO-081 item 8): the list, and a box to drop a file on. */
.ppl-papers { list-style: none; margin: 0 0 var(--sp-4); padding: 0; display: flex; flex-direction: column; }
.ppl-papers li { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1) var(--sp-3); padding: var(--sp-2) 0; border-bottom: 1px solid var(--border); font-size: var(--fs-body); }
.ppl-papers li:last-child { border-bottom: 0; }
.ppl-inline-form { display: inline; margin-left: auto; }
.ppl-drop {
    display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin-bottom: var(--sp-3);
    padding: var(--sp-4); border: 2px dashed var(--border-strong); border-radius: var(--radius-sm); background: var(--surface-2);
}
.ppl-drop.is-over { border-color: var(--navy); background: var(--info-bg); }
.ppl-drop-says { color: var(--muted); font-size: var(--fs-body); }
.ppl-camera { position: relative; }
@media (prefers-reduced-motion: no-preference) {
    /* A card opens by growing, a saved one settles with one highlight, and a
       chip its save resolved fades (WO-081 item 6). Nothing loops. */
    .ppl-card.is-opening { animation: ppl-grow .2s var(--motion-ease); }
    .ppl-card.is-saved { animation: ppl-settle 1s ease-out; }
    .ppl-needs-in .pill { transition: opacity .25s ease, transform .25s ease; }
}
@keyframes ppl-grow { from { opacity: .4; transform: scale(.985); } to { opacity: 1; transform: none; } }
@keyframes ppl-settle { from { box-shadow: 0 0 0 3px var(--success-bg), var(--shadow-sm); background: var(--success-bg); } to { box-shadow: var(--shadow-sm); background: var(--surface); } }
@media (max-width: 1180px) {
    .ppl-add { grid-template-columns: minmax(0, 1fr); }
    .ppl-makes { position: static; }
}
@media (max-width: 1023.98px) {
    table.ppl-table th { top: var(--topbar-h); }
    .ppl-col-day { display: none; }
}
@media (max-width: 700px) {
    .ppl-col-since { display: none; }
    table.ppl-table thead { display: none; }
    table.ppl-table, table.ppl-table tbody { display: block; }
    table.ppl-table tr.ppl-row {
        display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 4px var(--sp-3);
        padding: var(--sp-3) 14px; border-bottom: 1px solid var(--border);
    }
    table.ppl-table tr.ppl-row td { display: block; height: auto; padding: 0; border: 0; text-align: left; }
    table.ppl-table tr.ppl-row td.ppl-who { grid-column: 1; }
    table.ppl-table tr.ppl-row td.ppl-actions { grid-column: 2; grid-row: 1; }
    table.ppl-table tr.ppl-row td.ppl-dept,
    table.ppl-table tr.ppl-row td.ppl-pay,
    table.ppl-table tr.ppl-row td.ppl-needs { grid-column: 1 / -1; padding-left: 42px; }
    table.ppl-table tr.ppl-row td.ppl-dept { color: var(--muted); font-size: var(--fs-small); }
    /* The day and the start date are on the person's page; a card keeps to
       who, where, pay and what is missing. Nothing missing says nothing. */
    table.ppl-table tr.ppl-row td.ppl-col-day,
    table.ppl-table tr.ppl-row td.ppl-col-since,
    table.ppl-table tr.ppl-row td.ppl-needs:not(:has(.pill)) { display: none; }
    .ppl-find { flex-basis: 100%; }
    .ppl-add-form, .ppl-makes { padding: var(--sp-4); }
    .ppl-field { grid-template-columns: minmax(0, 1fr); gap: var(--sp-1); }
    .ppl-field > label, .ppl-field > legend { padding-top: 0; }
    fieldset.ppl-field > legend { float: none; width: auto; margin: 0 0 var(--sp-1); }
    fieldset.ppl-field > div { margin-left: 0; }
    .ppl-field .form-control { max-width: none; font-size: 16px; }
    .ppl-head, .ppl-card { padding: var(--sp-4); }
    .ppl-cards, .ppl-side-forms, .ppl-act-grid { grid-template-columns: minmax(0, 1fr); }
    .ppl-facts { grid-template-columns: minmax(0, 1fr); gap: 0; }
    .ppl-facts dd { margin-bottom: var(--sp-2); }
    .ppl-card-form .form-control { font-size: 16px; }
}

/* ---------------- payroll: overtime request ----------------
   Lifted from payroll/templates/payroll/overtime_request.html on 2026-09-05
   (WO-019 B6); the rules are unchanged. */
.ot-layout { display: grid; grid-template-columns: minmax(300px, 380px) minmax(0, 1fr); gap: 16px; align-items: start; }
.ot-note { color: var(--muted); font-size: 0.86rem; margin: 10px 0 0; }
.ot-month { display: flex; gap: 10px; align-items: end; flex-wrap: wrap; }
.ot-month .form-group { margin: 0; }
.logged-badge { background: var(--gold-bg); color: var(--gold-ink); }
.decide-form { display: inline; }
@media (max-width: 900px) { .ot-layout { grid-template-columns: minmax(0, 1fr); } }

/* ---------------- payroll: snapshot list ----------------
   Lifted from payroll/templates/payroll/snapshot_list.html on 2026-09-05
   (WO-019 B6); the rules are unchanged. */
.register-filters { display: grid; grid-template-columns: minmax(220px, 1.25fr) repeat(3, minmax(170px, .9fr)) auto; gap: 12px; align-items: end; }
.register-summary { display: grid; grid-template-columns: repeat(4, minmax(150px, 1fr)); gap: 12px; margin-bottom: 18px; }
.register-stat { padding: 16px 18px; }
.register-stat span { display: block; color: var(--muted); font-size: .8em; text-transform: uppercase; letter-spacing: .04em; }
.register-stat strong { display: block; color: var(--navy); font-size: 1.2rem; margin-top: 5px; }
.register-table thead th { position: sticky; top: 0; z-index: 1; }
@media (max-width: 980px) { .register-filters, .register-summary { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 620px) { .register-filters, .register-summary { grid-template-columns: 1fr; } }

/* ---------------- payroll: attendance upload detail ----------------
   Lifted from payroll/templates/payroll/upload_detail.html on 2026-09-05
   (WO-019 B6); the rules are unchanged. */
/* ---------------- Progress strip ---------------- */
.month-status {
    display: grid;
    grid-template-columns: minmax(240px, 1fr) minmax(0, 1.5fr);
    gap: 22px;
    align-items: center;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    padding: 18px 20px;
    margin-bottom: 14px;
}
.month-progress .headline { font-size: 1.5rem; font-weight: 700; color: var(--navy); line-height: 1.15; }
.month-progress .headline small { font-size: 0.95rem; font-weight: 600; color: var(--muted); }
.month-progress .caption { color: var(--muted); font-size: 0.84rem; margin-top: 4px; }
.progress-track {
    height: 8px; border-radius: 999px; background: var(--neutral-bg);
    margin-top: 11px; overflow: hidden;
}
.progress-fill { height: 100%; border-radius: 999px; background: var(--success); }

.status-chips { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
.status-chip {
    appearance: none; font: inherit; text-align: left; cursor: pointer;
    background: var(--bg); border: 1px solid var(--border); border-radius: 9px;
    padding: 11px 13px; color: var(--ink);
    transition: border-color 0.15s ease, background 0.15s ease;
}
.status-chip:hover { border-color: var(--gold); background: var(--gold-bg); }
.status-chip:focus-visible { outline: 3px solid rgba(200,155,60,0.38); outline-offset: 2px; }
.status-chip strong { display: block; font-size: 1.4rem; line-height: 1.1; color: var(--navy); }
.status-chip span { display: block; font-size: 0.79rem; color: var(--muted); margin-top: 3px; }
.status-chip.is-clear strong { color: var(--success); }
.status-chip.needs-action { background: var(--warning-bg); border-color: #E9D9A8; }
.status-chip.needs-action strong { color: var(--warning); }

/* ---------------- Next step ---------------- */
.next-step {
    display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
    border-radius: var(--radius); padding: 14px 18px; margin-bottom: 18px;
    background: var(--info-bg); border: 1px solid #CADCF5;
}
.next-step.is-blocked { background: var(--danger-bg); border-color: #F0CFCF; }
.next-step.is-ready { background: var(--success-bg); border-color: #C4E6D3; }
.next-step .step-copy { flex: 1; min-width: 240px; }
.next-step h3 { font-size: 0.98rem; margin: 0 0 3px; }
.next-step p { margin: 0; font-size: 0.88rem; color: var(--ink); opacity: 0.85; }
.next-step ul { margin: 6px 0 0; padding-left: 18px; font-size: 0.88rem; line-height: 1.6; }

/* ---------------- Filter ---------------- */
.review-filter {
    display: grid;
    grid-template-columns: minmax(170px, 1fr) minmax(170px, 1fr) auto;
    gap: 12px; align-items: end; margin-bottom: 16px; padding: 14px 18px;
}
.review-filter .form-group { margin: 0; }
.review-filter .form-group label { font-size: 0.8em; }
.review-filter-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.filter-note { color: var(--muted); font-size: 0.8rem; margin: 10px 0 0; grid-column: 1 / -1; }

/* ---------------- Tabs ---------------- */
/* Wraps, never scrolls (WO-029 item 3). This was `overflow-x: auto`, so on a
   phone the state tabs became a little bar with a scrollbar of its own inside
   a page that also scrolled - the counts past the third tab were reachable
   only by dragging a strip most people do not know is draggable. Tabs wrap to
   a second line instead, which costs a few pixels of height and hides nothing.
   The buttons and links keep `white-space: nowrap`, so a tab wraps whole. */
.tabs-nav {
    display: flex; gap: 4px; flex-wrap: wrap;
    border-bottom: 1px solid var(--border); margin-bottom: 18px;
}
.tabs-nav button {
    appearance: none; font: inherit; font-weight: 600; font-size: 0.9rem;
    background: none; border: none; border-bottom: 2px solid transparent;
    color: var(--muted); cursor: pointer; white-space: nowrap;
    padding: 11px 15px; margin-bottom: -1px;
    display: inline-flex; align-items: center; gap: 8px;
}
.tabs-nav button:hover { color: var(--navy); }
.tabs-nav button[aria-selected="true"] { color: var(--navy); border-bottom-color: var(--gold); }
.tabs-nav button:focus-visible { outline: 3px solid rgba(200,155,60,0.38); outline-offset: -3px; }
.tab-count {
    background: var(--neutral-bg); color: var(--muted);
    border-radius: 999px; font-size: 0.74rem; font-weight: 700; padding: 2px 8px;
}
.tabs-nav button[aria-selected="true"] .tab-count { background: var(--navy); color: #fff; }
.tab-count.is-warning { background: var(--warning-bg); color: var(--warning); }
.tabs-nav button[aria-selected="true"] .tab-count.is-warning { background: var(--warning); color: #fff; }

/* Hidden only once the tab script has taken over, so a browser with no
   JavaScript still shows every panel rather than an empty page. */
[data-tabs="on"] .tab-panel[hidden] { display: none; }
.tab-panel[hidden] { display: block; }
[data-tabs="on"] .tab-panel > .panel-title { display: none; }
.panel-title { font-size: 1.05rem; margin: 26px 0 10px; }

/* ---------------- Panel furniture ---------------- */
.panel-block { margin-bottom: 20px; }
.panel-block:last-child { margin-bottom: 0; }
.panel-intro { color: var(--muted); font-size: 0.89rem; margin: 0 0 14px; max-width: 76ch; }
.block-heading { font-size: 0.98rem; margin: 0 0 4px; }
.block-heading .badge { vertical-align: middle; margin-left: 6px; }

.employee-meta { color: var(--muted); font-size: 0.82rem; margin-top: 2px; }
.employee-meta .meta-dot + .meta-dot::before { content: '\00b7'; margin: 0 5px; }
.employee-link { font-weight: 700; color: var(--navy); text-decoration: none; }
.employee-link:hover { text-decoration: underline; }

.row-flags > summary {
    color: var(--info); cursor: pointer; font-size: 0.82rem; font-weight: 700;
    list-style: none; white-space: nowrap;
}
.row-flags > summary::-webkit-details-marker { display: none; }
.row-flags > summary::before { content: '+'; display: inline-block; margin-right: 5px; }
.row-flags[open] > summary::before { content: '\2212'; }
.row-flag-list { color: var(--muted); font-size: 0.84rem; line-height: 1.45; margin-top: 7px; min-width: 260px; max-width: 340px; }
.row-flag-list > div + div { margin-top: 5px; }

.punch-form { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.subcard { background: var(--bg); border: 1px solid var(--border); border-radius: 9px; padding: 16px; }
.subcard h4 { margin: 0 0 4px; font-size: 0.95rem; }
.subcard-gold { background: var(--gold-bg); border-color: #EBDCB6; }
.subcard-danger { background: var(--danger-bg); border-color: #F0CFCF; }
.subcard-danger h4 { color: var(--danger); }
.field-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(155px, 1fr)); gap: 12px; align-items: end; }
.field-grid .form-group { margin-bottom: 0; }
.field-hint { color: var(--muted); font-size: 0.82em; margin-top: 3px; }
.field-error { color: var(--danger); font-size: 0.84em; }

@media (max-width: 900px) {
    .month-status { grid-template-columns: 1fr; gap: 16px; }
    .review-filter { grid-template-columns: 1fr 1fr; }
    .review-filter-actions { grid-column: 1 / -1; }
}
@media (max-width: 620px) {
    .status-chips { grid-template-columns: 1fr; }
    .review-filter { grid-template-columns: 1fr; }
    .review-filter-actions { grid-column: auto; }
    .tabs-nav button { padding: 11px 12px; font-size: 0.86rem; }
}

/* ---------------- hotels: action queue ----------------
   Lifted from hotels/templates/hotels/action_queue.html on 2026-09-05
   (WO-019 B7); the rules are unchanged. */
/* ---- Greeting strip ---- */
.home-hero {
    display: flex; justify-content: space-between; align-items: flex-end; gap: 16px 24px; flex-wrap: wrap;
    margin-bottom: 22px;
}
.home-eyebrow {
    display: inline-flex; align-items: center; gap: 8px;
    font-size: 0.7rem; font-weight: 800; letter-spacing: 0.12em; text-transform: uppercase; color: var(--gold-ink);
}
.home-eyebrow::before { content: ''; width: 22px; height: 1px; background: var(--gold); }
.home-hero h1 {
    margin: 6px 0 4px; font-family: var(--serif); font-weight: 500; font-size: clamp(1.7rem, 2.6vw, 2.25rem);
    letter-spacing: 0.005em; color: var(--navy);
}
.home-hero p { margin: 0; color: var(--muted); font-size: 0.95rem; max-width: 640px; }
.home-hero p strong { color: var(--ink); }
.home-date {
    display: flex; flex-direction: column; align-items: flex-end; gap: 2px;
    color: var(--muted); font-size: 0.82rem; text-align: right;
}
.home-date strong { color: var(--navy); font-size: 1.05rem; font-weight: 750; letter-spacing: -0.01em; }

/* ---- Tiles ---- */
.tiles { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px; margin-bottom: 26px; }
@media (max-width: 1180px) { .tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .tiles { grid-template-columns: minmax(0, 1fr); } }
.tile { position: relative; display: flex; flex-direction: column; gap: 10px; padding: 18px 20px 16px; min-height: 150px; }
.tile-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; flex-wrap: wrap; }
.tile-title { font-size: 0.7rem; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase; color: var(--muted); }
.tile-asof { font-size: 0.72rem; color: var(--muted-light); white-space: nowrap; }
.tile-asof.stale { color: var(--warning); font-weight: 700; }
.tile-big { font-size: clamp(1.35rem, 1.6vw, 1.7rem); white-space: nowrap; font-weight: 800; color: var(--navy); letter-spacing: -0.035em; line-height: 1; font-variant-numeric: tabular-nums; }
.tile-big small { font-size: 0.85rem; font-weight: 650; color: var(--muted); letter-spacing: 0; margin-left: 4px; }
.tile-big.danger { color: var(--danger); }
.tile-big.success { color: var(--success); }
.tile-big.muted { color: var(--muted-light); font-weight: 700; }
.tile-facts { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; margin-top: auto; }
.tile-fact { min-width: 0; }
.tile-fact span { display: block; font-size: 0.64rem; font-weight: 750; letter-spacing: 0.04em; text-transform: uppercase; color: var(--muted-light); }
.tile-fact strong { display: block; font-size: 0.9rem; font-weight: 700; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-variant-numeric: tabular-nums; }
.tile-note { margin-top: auto; font-size: 0.8rem; color: var(--muted); line-height: 1.4; }
.tile-note.warn { color: var(--warning); }
.tile-link { position: absolute; inset: 0; border-radius: inherit; }
.tile-link:focus-visible { outline: 3px solid rgba(200,155,60,0.45); outline-offset: 2px; }
.tile:hover { border-color: var(--border-strong); box-shadow: var(--shadow-md); }

/* ---- Two columns: queue + launcher ---- */
.home-grid { display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: 22px; align-items: start; }
@media (max-width: 1023.98px) { .home-grid { grid-template-columns: minmax(0, 1fr); } }
.section-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin-bottom: 12px; }
.section-head h2 { margin: 0; font-size: 1.08rem; font-weight: 800; }
.section-head span { font-size: 0.82rem; color: var(--muted); }

.queue-list { display: flex; flex-direction: column; gap: 8px; }
.queue-row {
    display: flex; align-items: center; gap: 14px; padding: 14px 16px;
    border-left: 4px solid var(--border); text-decoration: none; color: inherit;
    transition: transform 0.12s ease, box-shadow 0.12s ease;
}
.queue-row:hover { transform: translateX(2px); box-shadow: var(--shadow-md); }
.queue-row.is-overdue { border-left-color: var(--danger); }
.queue-row.is-waiting { border-left-color: var(--gold); }
.queue-row.is-noted { border-left-color: var(--border-strong); }
.queue-row__body { flex: 1; min-width: 0; }
.queue-row__title { font-weight: 700; color: var(--navy); }
.queue-row__detail { color: var(--muted); font-size: 0.86em; margin-top: 2px; }
.queue-row__module { font-size: 0.68em; text-transform: uppercase; letter-spacing: .08em; color: var(--muted); margin-bottom: 3px; font-weight: 750; }
.queue-row__count {
    min-width: 34px; height: 34px; padding: 0 10px; border-radius: 999px; display: grid; place-items: center;
    font-weight: 800; font-size: 0.9rem; font-variant-numeric: tabular-nums;
}
.queue-row__go { color: var(--muted-light); }
.queue-empty { text-align: center; padding: 40px 20px; }
.queue-empty h3 { margin: 12px 0 4px; }
.queue-empty p { color: var(--muted); margin: 0; font-size: 0.92rem; }

/* ---- Launcher ---- */
.launcher { display: flex; flex-direction: column; gap: 10px; }
.launch-card { padding: 14px 16px; }
.launch-head { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.launch-ico {
    width: 34px; height: 34px; flex: 0 0 34px; border-radius: 9px; display: grid; place-items: center;
    background: var(--navy); color: var(--gold);
}
.launch-ico svg { width: 17px; height: 17px; }
.launch-head h3 { margin: 0; font-size: 0.98rem; font-weight: 750; }
.launch-head p { margin: 1px 0 0; font-size: 0.78rem; color: var(--muted); }
.launch-links { display: flex; flex-wrap: wrap; gap: 6px; }
.launch-links a {
    display: inline-flex; align-items: center; min-height: 30px; padding: 4px 11px; border-radius: 999px;
    background: var(--surface-2); border: 1px solid var(--border); color: var(--ink);
    text-decoration: none; font-size: 0.8rem; font-weight: 600;
    transition: background 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}
.launch-links a:hover { background: var(--gold-bg); border-color: #E6D3A3; color: var(--navy); }
@media (max-width: 768px) {
    .home-hero { margin-bottom: 16px; }
    .home-date { align-items: flex-start; text-align: left; }
    .tile { min-height: 0; padding: 16px; }
    .tile-big { font-size: 1.55rem; }
    .launch-links a { min-height: 36px; }
}

/* ---------------- hotels: portfolio ----------------
   Lifted from hotels/templates/hotels/portfolio.html on 2026-09-05
   (WO-019 B7); the rules are unchanged. */
.pf-hero { display: flex; justify-content: space-between; align-items: flex-end; gap: 16px 24px; flex-wrap: wrap; margin-bottom: 22px; }
/* WO-062 item 14: the fortnight under a hotel's last night, and the ranked
   bars under the rows. Both are the kit's own marks inside this screen's
   look - the cards, the hero and the row grid are untouched. */
.pf-trend { margin-top: 6px; max-width: 180px; }
.pf-ranks { margin-top: 18px; }
.pf-eyebrow { display: inline-flex; align-items: center; gap: 8px; font-size: 0.7rem; font-weight: 800; letter-spacing: 0.12em; text-transform: uppercase; color: var(--gold-ink); }
.pf-eyebrow::before { content: ''; width: 22px; height: 1px; background: var(--gold); }
.pf-hero h1 { margin: 6px 0 4px; font-family: var(--serif); font-weight: 500; font-size: clamp(1.7rem, 2.6vw, 2.25rem); color: var(--navy); }
.pf-hero p { margin: 0; color: var(--muted); font-size: 0.95rem; max-width: 640px; }
.pf-date { color: var(--muted); font-size: 0.82rem; text-align: right; }
.pf-date strong { display: block; color: var(--navy); font-size: 1.05rem; font-weight: 750; }

/* Group totals */
.pf-totals { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 12px; margin-bottom: 22px; }
@media (max-width: 1180px) { .pf-totals { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 640px) { .pf-totals { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.pf-total { padding: 14px 16px; }
.pf-total .lbl { font-size: 0.66rem; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase; color: var(--muted); }
.pf-total .val { margin-top: 6px; font-size: 1.35rem; font-weight: 800; color: var(--navy); letter-spacing: -0.03em; font-variant-numeric: tabular-nums; white-space: nowrap; }
.pf-total .val.muted { color: var(--muted-light); font-weight: 700; font-size: 1.05rem; }
.pf-total .val.danger { color: var(--danger); }
.pf-total .cov { font-size: 0.72rem; color: var(--muted); margin-top: 2px; }
.pf-total .cov.warn { color: var(--warning); font-weight: 700; }

/* One row per hotel */
.pf-rows { display: flex; flex-direction: column; gap: 12px; }
.pf-row { display: grid; grid-template-columns: minmax(200px, 1.2fr) repeat(4, minmax(0, 1fr)) minmax(120px, 0.8fr); gap: 0; padding: 0; overflow: hidden; }
.pf-row.is-current { border-color: var(--gold); box-shadow: 0 0 0 3px var(--gold-bg); }
.pf-cell { padding: 16px 18px; border-left: 1px solid var(--border); min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.pf-cell:first-child { border-left: none; background: linear-gradient(180deg, #fff, var(--surface-2)); }
.pf-cell .lbl { font-size: 0.64rem; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase; color: var(--muted); }
.pf-cell .big { font-size: 1.3rem; font-weight: 800; color: var(--navy); letter-spacing: -0.03em; font-variant-numeric: tabular-nums; white-space: nowrap; line-height: 1.1; }
.pf-cell .big.muted { color: var(--muted-light); font-weight: 700; font-size: 1rem; }
.pf-cell .big.danger { color: var(--danger); }
.pf-cell .big.success { color: var(--success); }
.pf-cell .sub { font-size: 0.76rem; color: var(--muted); line-height: 1.35; }
.pf-cell .sub.warn { color: var(--warning); font-weight: 700; }
.pf-hotel { display: flex; align-items: center; gap: 12px; }
.pf-hotel .hotel-avatar { width: 40px; height: 40px; flex: 0 0 40px; border-radius: 11px; }
.pf-hotel strong { display: block; font-size: 1rem; font-weight: 750; color: var(--navy); line-height: 1.2; }
.pf-hotel small { color: var(--muted); font-size: 0.74rem; letter-spacing: 0.06em; text-transform: uppercase; font-weight: 700; }
.pf-enter { margin-top: auto; }
.pf-enter form { margin: 0; }
.pf-queue { align-items: flex-start; }
.pf-queue .big { display: inline-flex; align-items: center; gap: 8px; }
@media (max-width: 1023.98px) {
    .pf-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .pf-cell { border-left: none; border-top: 1px solid var(--border); }
    .pf-cell:first-child { grid-column: 1 / -1; border-top: none; }
    .pf-date { text-align: left; }
}

/* ---------------- hotels: room types ----------------
   Lifted from hotels/templates/hotels/room_types.html on 2026-09-05
   (WO-019 B7); the rules are unchanged. */
.room-toolbar { display: grid; grid-template-columns: minmax(240px, 1fr) minmax(180px, .45fr) auto; gap: 12px; align-items: end; }
.room-table { min-width: 900px; }
.room-table thead th { position: sticky; top: 0; z-index: 1; }
details.room-create > summary { cursor: pointer; list-style: none; display: flex; justify-content: space-between; gap: 12px; color: var(--navy); font-weight: 700; }
details.room-create > summary::-webkit-details-marker { display: none; }
details.room-create > summary::after { content: '+'; color: var(--gold); font-size: 1.35rem; }
details.room-create[open] > summary::after { content: '\2212'; }
details.room-create[open] > summary { margin-bottom: 16px; padding-bottom: 12px; border-bottom: 1px solid var(--border); }
.room-dialog { width: min(860px, calc(100vw - 28px)); max-height: calc(100vh - 28px); border: 0; border-radius: 16px; padding: 0; box-shadow: 0 24px 70px rgba(16,24,40,.3); }
.room-dialog::backdrop { background: rgba(9,18,36,.58); backdrop-filter: blur(3px); }
.room-dialog__head { position: sticky; top: 0; z-index: 2; display: flex; justify-content: space-between; align-items: center; gap: 12px; padding: 18px 20px; background: #fff; border-bottom: 1px solid var(--border); }
.room-dialog__body { padding: 20px; }
.room-dialog__actions { position: sticky; bottom: 0; display: flex; justify-content: flex-end; gap: 10px; padding: 14px 20px; background: #fff; border-top: 1px solid var(--border); }
.room-form-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; }
@media (max-width: 850px) { .room-form-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 620px) {
    .room-toolbar, .room-form-grid { grid-template-columns: 1fr; }
    .room-dialog__actions .btn { flex: 1; }
}

/* ---------------- finance: dashboard ----------------
   Lifted from finance/templates/finance/dashboard.html on 2026-09-06 (WO-019 C5); the
   rules are unchanged. */
.fin-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 14px; }
.fin-headline {
display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; margin-bottom: 16px;
}
.fin-stat {
background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
box-shadow: var(--shadow-sm); padding: 16px 18px;
}
.fin-stat .label { color: var(--muted); font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.4px; font-weight: 700; }
.fin-stat .value { font-size: 1.5rem; font-weight: 700; color: var(--navy); line-height: 1.15; margin-top: 6px; }
.fin-stat .value.pos { color: var(--success); }
.fin-stat .value.neg { color: var(--danger); }
.fin-stat .sub { color: var(--muted); font-size: 0.82rem; margin-top: 4px; }
.fin-stat.alert { border-left: 4px solid var(--danger); }
.fin-stat.warn { border-left: 4px solid var(--warning); }
.fin-columns { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); gap: 14px; }
.fin-section {
background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
box-shadow: var(--shadow-sm); overflow: hidden; margin-bottom: 14px;
}
.fin-section-head {
display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
padding: 15px 18px; border-bottom: 1px solid var(--border); flex-wrap: wrap;
}
.fin-section-head h3 { font-size: 1rem; margin: 0; }
.fin-section-head .figure { font-weight: 700; color: var(--navy); }
.fin-section-head .note { color: var(--muted); font-size: 0.82rem; width: 100%; margin-top: 2px; }
.fin-section-body { padding: 16px 18px; }
.fin-section-body.flush { padding: 0; }
.fin-line { display: flex; justify-content: space-between; gap: 12px; padding: 8px 0; }
.fin-line + .fin-line { border-top: 1px solid var(--border); }
.fin-line .k { color: var(--muted); }
.fin-line .v { font-weight: 600; white-space: nowrap; }
.fin-line.total { border-top: 2px solid var(--border); font-weight: 700; }
.fin-line.total .k { color: var(--ink); }
.caveats { margin: 0; padding-left: 18px; color: var(--muted); font-size: 0.85rem; line-height: 1.6; }
.period-form { display: flex; gap: 10px; align-items: end; flex-wrap: wrap; }
.period-form select { min-width: 160px; }
@media (max-width: 1000px) {
.fin-headline { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.fin-columns { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 560px) {
.fin-headline { grid-template-columns: 1fr; }
}

/* ---------------- finance: insights ----------------
   Lifted from finance/templates/finance/insights.html on 2026-09-06 (WO-019 C5); the
   rules are unchanged. */
.ins-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 18px; }
.ins-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 14px; }
.ins-tile {
background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
padding: 16px 18px; box-shadow: var(--shadow-sm);
}
.ins-tile .t-label { color: var(--muted); font-size: 0.74rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.07em; }
.ins-tile .t-value { margin-top: 6px; color: var(--navy); font-size: 1.55rem; font-weight: 700; letter-spacing: -0.02em; }
.ins-tile .t-sub { margin-top: 3px; color: var(--muted); font-size: 0.79rem; }
.ins-tile.t-alert .t-value { color: var(--danger); }
/* Two across on a phone rather than one. `minmax(190px, 1fr)` gives a
single column at 390px, so seven one-number tiles filled the whole screen
before any content began. The figure steps down with the column, because
a narrower tile at 1.55rem breaks "RM 50,159.38" across two lines. */
@media (max-width: 560px) {
.ins-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.ins-tile { padding: 13px 14px; }
.ins-tile .t-value { font-size: 1.2rem; }
}
.ins-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 20px 22px; box-shadow: var(--shadow-sm); }
.ins-card h3 { margin: 0 0 2px; font-size: 1.05rem; }
.ins-card .c-sub { margin: 0 0 16px; color: var(--muted); font-size: 0.82rem; }
/* What the table above it does not show, in the table's own card. */
.ins-card .c-foot { margin: 12px 0 0; color: var(--muted); font-size: 0.8rem; }
/* The qualifications that belong to a figure but not inside its tile. */
.ins-note {
border-left: 3px solid var(--border); padding: 2px 0 2px 12px;
color: var(--muted); font-size: 0.8rem; line-height: 1.55;
}
.ins-note strong { display: block; margin-bottom: 3px; color: var(--navy); font-weight: 700; }
/* Bar chart: single series, thin marks, rounded data ends, 2px gaps */
.rev-chart { display: flex; align-items: flex-end; gap: 2px; height: 180px; padding-top: 18px; border-bottom: 1px solid var(--border); }
.rev-col { position: relative; flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: flex-end; height: 100%; min-width: 0; }
.rev-bar { width: 62%; max-width: 34px; min-height: 2px; background: var(--navy); border-radius: 4px 4px 0 0; }
.rev-col:hover .rev-bar { background: var(--navy-lighter); }
.rev-label { position: absolute; top: -4px; left: 50%; transform: translateX(-50%); color: #344054; font-size: 0.7rem; font-weight: 700; white-space: nowrap; }
.rev-x { display: flex; gap: 2px; margin-top: 6px; }
.rev-x span { flex: 1; text-align: center; color: var(--muted-light); font-size: 0.68rem; white-space: nowrap; overflow: hidden; }
.rev-tip {
position: absolute; bottom: calc(100% + 8px); left: 50%; transform: translateX(-50%);
display: none; z-index: 5; padding: 8px 11px; border-radius: 8px; white-space: nowrap;
background: var(--navy); color: #fff; font-size: 0.76rem; line-height: 1.5;
box-shadow: 0 6px 18px rgba(16,28,58,0.3); pointer-events: none;
}
.rev-col:hover .rev-tip { display: block; }
.rev-empty { padding: 28px 0; color: var(--muted); font-size: 0.9rem; }
.ins-two { display: grid; grid-template-columns: 1.4fr 1fr; gap: 18px; align-items: start; }
@media (max-width: 980px) { .ins-two { grid-template-columns: minmax(0, 1fr); } }
.ins-table { width: 100%; border-collapse: collapse; font-size: 0.86rem; }
.ins-table th { text-align: left; padding: 7px 10px; color: var(--muted); font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.06em; border-bottom: 1px solid var(--border); }
.ins-table td { padding: 7px 10px; border-bottom: 1px solid var(--border); }
.ins-table tr:last-child td { border-bottom: none; }
.ins-table .num { text-align: right; font-variant-numeric: tabular-nums; }

/* ---------------- finance: payable_detail ----------------
   Lifted from finance/templates/finance/payable_detail.html on 2026-09-06 (WO-019 C5); the
   rules are unchanged. */
.pd-columns { display: grid; grid-template-columns: minmax(0, 1.3fr) minmax(300px, 0.8fr); gap: 16px; }
.pd-figure { font-size: 2rem; font-weight: 700; color: var(--navy); line-height: 1.1; }
.pd-line { display: flex; justify-content: space-between; gap: 12px; padding: 9px 0; }
.pd-line + .pd-line { border-top: 1px solid var(--border); }
.pd-line .k { color: var(--muted); }
.pd-line .v { font-weight: 600; text-align: right; }
.pd-block { margin-bottom: 16px; }
.pd-block h3 { font-size: 1rem; margin-bottom: 4px; }
.pd-intro { color: var(--muted); font-size: 0.87rem; margin: 0 0 14px; }
.field-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 12px; align-items: end; }
.field-grid .form-group { margin-bottom: 0; }
.field-error { color: var(--danger); font-size: 0.84em; }
.ack-box {
background: var(--warning-bg); border: 1px solid #E9D9A8; border-radius: var(--radius);
padding: 16px 18px; margin-bottom: 16px;
}
.ack-link {
display: block; width: 100%; font-family: ui-monospace, Menlo, Consolas, monospace;
font-size: 0.84rem; padding: 10px 12px; border-radius: 7px; border: 1px solid var(--border);
background: #fff; margin: 10px 0;
}
.event-row { padding: 11px 0; border-bottom: 1px solid var(--border); }
.event-row:last-child { border-bottom: none; }
.event-row .meta { color: var(--muted); font-size: 0.8rem; }
.event-row .detail { font-size: 0.88rem; margin-top: 3px; }
@media (max-width: 900px) { .pd-columns { grid-template-columns: minmax(0, 1fr); } }

/* ---------------- finance: payable_list ----------------
   Lifted from finance/templates/finance/payable_list.html on 2026-09-06 (WO-019 C5); the
   rules are unchanged. */
.pay-filter { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)) auto; gap: 12px; align-items: end; }
.pay-filter .form-group { margin: 0; }
.pay-filter .form-group label { font-size: 0.8em; }
.pay-summary { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; margin-bottom: 16px; }
.pay-summary div {
background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
box-shadow: var(--shadow-sm); padding: 14px 16px;
}
.pay-summary strong { display: block; font-size: 1.3rem; color: var(--navy); line-height: 1.15; }
.pay-summary span { display: block; color: var(--muted); font-size: 0.8rem; margin-top: 4px; }
@media (max-width: 800px) { .pay-summary { grid-template-columns: 1fr 1fr; } }

/* ---------------- finance: city_ledger ----------------
   Lifted from finance/templates/finance/city_ledger.html on 2026-09-06 (WO-019 C5); the
   rules are unchanged. */
.cl-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; margin-bottom: 18px; }
.cl-tile { padding: 16px 18px; }
.cl-tile span { display: block; color: var(--muted); font-size: .78em; text-transform: uppercase; letter-spacing: .05em; }
.cl-tile strong { display: block; color: var(--navy); font-size: 1.24rem; margin-top: 5px; }
.cl-bar { height: 6px; border-radius: 3px; background: var(--border); overflow: hidden; min-width: 60px; }
.cl-bar > i { display: block; height: 100%; background: var(--gold); }
.cl-trend { display: flex; align-items: flex-end; gap: 3px; height: 90px; }
.cl-trend > div { flex: 1; background: var(--gold); border-radius: 2px 2px 0 0; min-height: 2px; }
.cl-period { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)) auto; gap: 12px; align-items: end; }
.cl-period .form-group { margin: 0; }
.cl-period .form-group label { font-size: 0.8em; }

/* ---------------- finance: source_mix ----------------
   Lifted from finance/templates/finance/source_mix.html on 2026-09-06 (WO-019 C5); the
   rules are unchanged. */
.sm-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; margin-bottom: 18px; }
.sm-tile { padding: 16px 18px; }
.sm-tile span { display: block; color: var(--muted); font-size: .78em; text-transform: uppercase; letter-spacing: .05em; }
.sm-tile strong { display: block; color: var(--navy); font-size: 1.24rem; margin-top: 5px; }
.sm-bar { height: 6px; border-radius: 3px; background: var(--border); overflow: hidden; min-width: 60px; }
.sm-bar > i { display: block; height: 100%; background: var(--gold); }
.sm-period { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)) auto; gap: 12px; align-items: end; }
.sm-period .form-group { margin: 0; }
.sm-period .form-group label { font-size: 0.8em; }

/* ---------------- finance: remittance_list ----------------
   Lifted from finance/templates/finance/remittance_list.html on 2026-09-06 (WO-019 C5); the
   rules are unchanged. */
.pm-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; margin-bottom: 18px; }
.pm-tile { padding: 16px 18px; }
.pm-tile span { display: block; color: var(--muted); font-size: .78em; text-transform: uppercase; letter-spacing: .05em; }
.pm-tile strong { display: block; color: var(--navy); font-size: 1.24rem; margin-top: 5px; }

/* ---------------- finance: remittance_detail ----------------
   Lifted from finance/templates/finance/remittance_detail.html on 2026-09-06 (WO-019 C5); the
   rules are unchanged. */
.pm-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; margin-bottom: 18px; }
.pm-tile { padding: 16px 18px; }
.pm-tile span { display: block; color: var(--muted); font-size: .78em; text-transform: uppercase; letter-spacing: .05em; }
.pm-tile strong { display: block; color: var(--navy); font-size: 1.24rem; margin-top: 5px; }
.pm-res { color: var(--muted); font-size: .84em; }
.pm-reason { color: var(--muted); font-size: .84em; display: block; }

/* ---------------- accounts: login ----------------
   Lifted from accounts/templates/accounts/login.html on 2026-09-06 (WO-019 C5);
   the rules are unchanged.
   Its `body` rules are scoped to `body.is-login`, set through
   base.html's `body_class` block: lifted bare they would repaint every page. */
body.is-login {
background: #070C1C;
}
body.is-login > .container {
max-width: none;
min-height: 100vh;
margin: 0;
padding: 0;
}
.login-shell {
--serif: Didot, 'Bodoni MT', 'Playfair Display', 'Palatino Linotype', Georgia, 'Times New Roman', serif;
--gold-line: #D5AE63;
--gold-soft: rgba(213, 174, 99, 0.55);
--gold-faint: rgba(213, 174, 99, 0.22);
--paper: #F5F1E8;
--paper-dim: rgba(245, 241, 232, 0.62);
position: relative;
min-height: 100vh;
display: grid;
grid-template-columns: minmax(0, 1.12fr) minmax(430px, 0.88fr);
background: #070C1C;
overflow: hidden;
}
/* Film grain over everything, very faint */
.login-shell::after {
content: '';
position: absolute;
inset: 0;
z-index: 40;
pointer-events: none;
opacity: 0.05;
mix-blend-mode: overlay;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.72' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23n)'/%3E%3C/svg%3E");
}
/* ================= Left: the scene ================= */
.login-scene {
position: relative;
display: flex;
flex-direction: column;
min-height: 100vh;
padding: clamp(32px, 4vw, 60px);
overflow: hidden;
isolation: isolate;
transition: background 1.4s ease;
}
.login-scene.t-night { background: linear-gradient(180deg, #070C1C 0%, #0C1530 58%, #17224A 100%); }
.login-scene.t-dusk  { background: linear-gradient(180deg, #0B1026 0%, #221B44 55%, #533353 82%, #7A4632 100%); }
.login-scene.t-dawn  { background: linear-gradient(180deg, #0D1330 0%, #2C2C5C 55%, #7A4A63 82%, #A2653F 100%); }
.login-scene.t-day   { background: linear-gradient(180deg, #10254A 0%, #1E3E71 55%, #3D639C 100%); }
/* Slow aurora blobs */
.aurora {
position: absolute;
z-index: 0;
border-radius: 50%;
filter: blur(90px);
pointer-events: none;
}
.aurora.a1 {
width: 520px; height: 520px;
left: -140px; top: 8%;
background: rgba(200, 155, 60, 0.07);
animation: auroraDrift 38s ease-in-out infinite alternate;
}
.aurora.a2 {
width: 620px; height: 620px;
right: -180px; bottom: -10%;
background: rgba(46, 65, 114, 0.22);
animation: auroraDrift 46s ease-in-out infinite alternate-reverse;
}
@keyframes auroraDrift {
from { transform: translate(0, 0) scale(1); }
to   { transform: translate(90px, -60px) scale(1.15); }
}
/* Star / dust canvas */
#scene-canvas {
position: absolute;
inset: 0;
z-index: 1;
width: 100%;
height: 100%;
pointer-events: none;
}
/* Vignette to focus the composition */
.scene-vignette {
position: absolute;
inset: 0;
z-index: 3;
pointer-events: none;
background: radial-gradient(ellipse at 50% 45%, transparent 55%, rgba(2, 5, 14, 0.5) 100%);
}
/* ---- The engraved facade ---- */
.facade-wrap {
position: absolute;
z-index: 2;
left: 50%;
bottom: 0;
width: min(560px, 78%);
transform: translateX(-50%);
will-change: transform;
pointer-events: none;
}
.facade-wrap svg { display: block; width: 100%; height: auto; }
.facade .ln {
fill: none;
stroke: var(--gold-line);
stroke-width: 1.4;
stroke-linecap: round;
stroke-linejoin: round;
opacity: 0.92;
}
.facade .ln.dim { opacity: 0.4; stroke-width: 1.1; }
.facade .ln.faint { opacity: 0.2; stroke-width: 1; }
/* one-shot self-drawing */
.facade .draw {
stroke-dasharray: 1;
stroke-dashoffset: 1;
animation: drawIn 1.7s cubic-bezier(0.4, 0, 0.2, 1) forwards;
animation-delay: var(--d, 0s);
}
@keyframes drawIn { to { stroke-dashoffset: 0; } }
.facade .win {
fill: none;
stroke: var(--gold-line);
stroke-width: 1;
opacity: 0;
animation: winAppear 0.9s ease forwards;
animation-delay: var(--d, 2.2s);
}
@keyframes winAppear { to { opacity: 0.55; } }
.facade .win.lit {
fill: rgba(243, 203, 126, 0.85);
stroke: rgba(243, 203, 126, 0.9);
animation: winLight 1.2s ease forwards;
animation-delay: var(--d, 2.6s);
}
@keyframes winLight { to { opacity: 0.9; } }
.t-day .facade .win.lit { fill: rgba(243, 203, 126, 0.3); }
.facade .beacon-core { fill: var(--gold-line); }
.facade .beacon-halo {
fill: rgba(243, 203, 126, 0.35);
animation: beaconPulse 4s ease-in-out infinite;
animation-delay: 3s;
opacity: 0;
}
@keyframes beaconPulse {
0%, 100% { opacity: 0.15; transform: scale(1); }
50% { opacity: 0.5; transform: scale(1.5); }
}
.facade .beacon-halo, .facade .beacon-core { transform-box: fill-box; transform-origin: center; }
.facade .beacon-core { opacity: 0; animation: winLight 1s ease forwards; animation-delay: 2.4s; }
.facade .doorglow {
opacity: 0;
animation: doorGlowIn 2s ease forwards;
animation-delay: 2.8s;
}
@keyframes doorGlowIn { to { opacity: 0.5; } }
/* ---- Copy over the scene ---- */
.scene-top {
position: relative;
z-index: 4;
display: flex;
align-items: center;
justify-content: space-between;
gap: 20px;
}
.login-wordmark {
display: inline-flex;
align-items: center;
gap: 14px;
color: var(--paper);
text-decoration: none;
}
.login-wordmark svg { display: block; }
.login-wordmark strong {
display: block;
font-family: var(--serif);
font-weight: 400;
font-size: 1.22rem;
letter-spacing: 0.14em;
text-transform: uppercase;
}
.login-wordmark small {
display: block;
margin-top: 3px;
color: var(--gold-soft);
font-size: 0.6rem;
font-weight: 600;
letter-spacing: 0.34em;
text-transform: uppercase;
}
.scene-clock {
text-align: right;
color: var(--paper-dim);
font-size: 0.78rem;
letter-spacing: 0.08em;
font-variant-numeric: tabular-nums;
white-space: nowrap;
}
.scene-clock strong {
display: block;
color: var(--paper);
font-family: var(--serif);
font-weight: 400;
font-size: 1.3rem;
letter-spacing: 0.1em;
}
.scene-message {
position: relative;
z-index: 4;
max-width: 520px;
margin-top: clamp(22px, 4.5vh, 52px);
}
.scene-eyebrow {
display: inline-flex;
align-items: center;
gap: 12px;
margin-bottom: 18px;
color: var(--gold-soft);
font-size: 0.68rem;
font-weight: 600;
letter-spacing: 0.32em;
text-transform: uppercase;
}
.scene-eyebrow::before,
.scene-eyebrow::after {
content: '';
width: 30px;
height: 1px;
background: var(--gold-faint);
}
.scene-message h1 {
margin: 0 0 14px;
color: var(--paper);
font-family: var(--serif);
font-weight: 400;
font-size: clamp(2.1rem, 3.6vw, 3.2rem);
line-height: 1.12;
letter-spacing: 0.012em;
text-shadow: 0 2px 24px rgba(2, 6, 16, 0.55);
}
.scene-message p {
max-width: 430px;
margin: 0;
color: var(--paper-dim);
font-size: clamp(0.94rem, 1.1vw, 1.02rem);
line-height: 1.75;
}
.scene-foot {
position: relative;
z-index: 4;
margin-top: auto;
display: flex;
align-items: center;
gap: 14px;
color: rgba(245, 241, 232, 0.4);
font-size: 0.64rem;
font-weight: 600;
letter-spacing: 0.26em;
text-transform: uppercase;
white-space: nowrap;
}
.scene-foot .tick {
transition: color 0.6s ease, text-shadow 0.6s ease;
}
.scene-foot .tick.on {
color: var(--gold-line);
text-shadow: 0 0 14px rgba(213, 174, 99, 0.45);
}
.scene-foot .dot { color: rgba(213, 174, 99, 0.4); font-size: 0.5rem; }
/* ================= Right: the desk ================= */
.login-panel {
position: relative;
z-index: 5;
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
padding: clamp(26px, 4.5vw, 64px);
background:
radial-gradient(ellipse 90% 40% at 50% 0%, rgba(200, 155, 60, 0.07), transparent),
linear-gradient(180deg, #0A1122 0%, #080E1D 100%);
border-left: 1px solid rgba(213, 174, 99, 0.16);
box-shadow: -30px 0 80px rgba(2, 5, 14, 0.55);
}
.login-card {
width: 100%;
max-width: 420px;
padding: clamp(30px, 3.4vw, 44px) clamp(26px, 3vw, 40px);
border: 1px solid rgba(213, 174, 99, 0.26);
border-radius: 18px;
background: rgba(20, 30, 58, 0.42);
backdrop-filter: blur(14px);
-webkit-backdrop-filter: blur(14px);
box-shadow:
inset 0 1px 0 rgba(230, 196, 116, 0.12),
0 1px 2px rgba(0, 0, 0, 0.4),
0 30px 70px rgba(2, 5, 14, 0.5);
animation: cardArrive 0.8s cubic-bezier(0.16, 1, 0.3, 1) both;
animation-delay: 0.15s;
}
.login-card.shake { animation: cardShake 0.45s ease both; }
@keyframes cardArrive {
from { opacity: 0; transform: translateY(16px); }
to   { opacity: 1; transform: translateY(0); }
}
@keyframes cardShake {
0% { transform: translateX(0); }
18% { transform: translateX(-7px); }
38% { transform: translateX(6px); }
58% { transform: translateX(-4px); }
78% { transform: translateX(2px); }
100% { transform: translateX(0); }
}
.login-card > * {
animation: riseIn 0.7s cubic-bezier(0.16, 1, 0.3, 1) both;
}
.login-card > *:nth-child(1) { animation-delay: 0.25s; }
.login-card > *:nth-child(2) { animation-delay: 0.33s; }
.login-card > *:nth-child(3) { animation-delay: 0.41s; }
.login-card > *:nth-child(4) { animation-delay: 0.49s; }
@keyframes riseIn {
from { opacity: 0; transform: translateY(10px); }
to   { opacity: 1; transform: translateY(0); }
}
/* Monogram seal */
.seal-wrap { display: flex; justify-content: center; margin-bottom: 18px; }
.seal { display: block; }
.seal .ring-dash {
transform-box: fill-box;
transform-origin: center;
animation: sealTurn 70s linear infinite;
}
@keyframes sealTurn { to { transform: rotate(360deg); } }
.seal text {
font-family: var(--serif);
font-size: 34px;
fill: var(--gold-line);
font-weight: 400;
}
.login-card-header { text-align: center; margin-bottom: 24px; }
.login-card-header h2 {
margin: 0 0 8px;
color: var(--paper);
font-family: var(--serif);
font-weight: 400;
font-size: 1.85rem;
letter-spacing: 0.02em;
}
.login-card-header p {
margin: 0;
color: var(--paper-dim);
font-size: 0.9rem;
}
.ornament {
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
margin: 16px 0 0;
color: var(--gold-faint);
}
.ornament::before, .ornament::after {
content: '';
width: 52px;
height: 1px;
background: var(--gold-faint);
}
.ornament svg { display: block; }
/* Fields */
.login-card .form-group { margin-bottom: 18px; }
.login-card .form-group label {
display: block;
margin-bottom: 9px;
color: var(--paper-dim);
font-size: 0.68rem;
font-weight: 600;
letter-spacing: 0.22em;
text-transform: uppercase;
}
.login-input-wrap { position: relative; }
.login-input-wrap > svg {
position: absolute;
left: 15px;
top: 50%;
width: 17px;
height: 17px;
color: rgba(245, 241, 232, 0.35);
pointer-events: none;
transform: translateY(-50%);
transition: color 0.25s ease;
}
.login-input-wrap:focus-within > svg { color: var(--gold-line); }
/* underline sweep */
.login-input-wrap::after {
content: '';
position: absolute;
left: 10%;
right: 10%;
bottom: -1px;
height: 1px;
background: linear-gradient(90deg, transparent, var(--gold-line), transparent);
transform: scaleX(0);
transition: transform 0.35s cubic-bezier(0.16, 1, 0.3, 1);
pointer-events: none;
}
.login-input-wrap:focus-within::after { transform: scaleX(1); }
.login-card .form-control {
width: 100%;
height: 51px;
padding: 12px 15px 12px 44px;
border: 1px solid rgba(255, 255, 255, 0.13);
border-radius: 11px;
background: rgba(255, 255, 255, 0.045);
color: var(--paper);
font-size: 0.95rem;
transition: border-color 0.25s ease, box-shadow 0.25s ease, background 0.25s ease;
}
.login-card .form-control::placeholder { color: rgba(245, 241, 232, 0.28); }
.login-card .form-control:focus {
outline: none;
border-color: rgba(213, 174, 99, 0.6);
background: rgba(255, 255, 255, 0.06);
box-shadow: 0 0 0 4px rgba(200, 155, 60, 0.1);
}
/* Dark-theme autofill */
.login-card .form-control:-webkit-autofill {
-webkit-text-fill-color: var(--paper);
-webkit-box-shadow: 0 0 0 60px #131C36 inset;
caret-color: var(--paper);
}
.pw-toggle {
position: absolute;
right: 7px;
top: 50%;
transform: translateY(-50%);
display: inline-flex;
align-items: center;
justify-content: center;
width: 37px;
height: 37px;
border: none;
border-radius: 9px;
background: transparent;
color: rgba(245, 241, 232, 0.4);
cursor: pointer;
transition: color 0.2s ease, background 0.2s ease;
}
.pw-toggle:hover { color: var(--gold-line); background: rgba(213, 174, 99, 0.08); }
.pw-toggle svg { width: 18px; height: 18px; }
.pw-toggle .eye-off { display: none; }
.pw-toggle.showing .eye-on { display: none; }
.pw-toggle.showing .eye-off { display: inline; }
#id_password { padding-right: 48px; }
.caps-hint {
display: none;
align-items: center;
gap: 6px;
margin-top: 8px;
color: #E0B15C;
font-size: 0.76rem;
font-weight: 600;
}
.caps-hint.on { display: inline-flex; }
.login-error {
display: flex;
gap: 10px;
margin-bottom: 18px;
padding: 12px 14px;
border: 1px solid rgba(214, 69, 69, 0.45);
border-radius: 11px;
background: rgba(214, 69, 69, 0.12);
color: #EFB6B6;
font-size: 0.85rem;
line-height: 1.5;
}
.login-error svg { flex-shrink: 0; margin-top: 1px; }
/* The one gold object on the page */
.login-submit {
position: relative;
overflow: hidden;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 10px;
width: 100%;
min-height: 52px;
margin-top: 6px;
border: none;
border-radius: 12px;
background: linear-gradient(180deg, #E9CA80 0%, #C89B3C 100%);
color: #14203E;
font-size: 0.92rem;
font-weight: 700;
letter-spacing: 0.04em;
cursor: pointer;
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.35),
0 12px 28px rgba(200, 155, 60, 0.22);
transition: transform 0.18s ease, box-shadow 0.18s ease, filter 0.18s ease;
}
.login-submit:hover {
transform: translateY(-1px);
filter: brightness(1.04);
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.35),
0 16px 34px rgba(200, 155, 60, 0.3);
}
.login-submit:active { transform: translateY(1px); }
.login-submit:hover .go-arrow { transform: translateX(3px); }
.login-submit .go-arrow { transition: transform 0.18s ease; }
.login-submit.busy { pointer-events: none; filter: saturate(0.85); }
.login-submit.busy .go-arrow { display: none; }
.login-submit .spin {
display: none;
width: 16px;
height: 16px;
border: 2px solid rgba(20, 32, 62, 0.25);
border-top-color: #14203E;
border-radius: 50%;
animation: spinTurn 0.8s linear infinite;
}
.login-submit.busy .spin { display: inline-block; }
@keyframes spinTurn { to { transform: rotate(360deg); } }
.login-security {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
margin-top: 24px;
color: rgba(245, 241, 232, 0.38);
font-size: 0.72rem;
letter-spacing: 0.04em;
}
/* ================= Responsive ================= */
@media (max-width: 980px) {
.login-shell {
grid-template-columns: 1fr;
grid-template-rows: min(42vh, 380px) 1fr;
}
.login-scene { min-height: 0; padding: 22px 24px; }
.scene-message, .scene-foot { display: none; }
.facade-wrap { width: min(420px, 74%); }
.login-panel {
min-height: 0;
align-items: flex-start;
margin-top: -30px;
padding: 34px 22px 44px;
border-left: none;
border-top: 1px solid rgba(213, 174, 99, 0.2);
border-radius: 26px 26px 0 0;
box-shadow: 0 -24px 60px rgba(2, 5, 14, 0.6);
}
}
@media (max-width: 520px) {
.login-shell { grid-template-rows: min(36vh, 300px) 1fr; }
.scene-clock strong { font-size: 1.1rem; }
.login-card { padding: 26px 20px; }
.login-card-header h2 { font-size: 1.6rem; }
}
@media (prefers-reduced-motion: reduce) {
.aurora, .seal .ring-dash, .login-submit .spin,
.facade .beacon-halo { animation: none !important; }
.facade .draw { animation-duration: 0.01s; animation-delay: 0s !important; }
.facade .win, .facade .win.lit, .facade .beacon-core, .facade .doorglow {
animation-duration: 0.01s; animation-delay: 0s !important;
}
.login-card, .login-card > * { animation-duration: 0.01s; animation-delay: 0s !important; }
.login-card.shake { animation: none !important; }
.facade-wrap { transform: translateX(-50%) !important; }
}

/* ---------------- hotels: dashboard ----------------
   Lifted from hotels/templates/hotels/dashboard.html on 2026-09-06 (WO-019 C5);
   the rules are unchanged.
   Its `body` rules are scoped to `body.is-hotel-picker`, set through
   base.html's `body_class` block: lifted bare they would repaint every page. */
body.is-hotel-picker { background: #F4F6FA; }
.hotel-dashboard {
--serif: Didot, 'Bodoni MT', 'Playfair Display', 'Palatino Linotype', Georgia, 'Times New Roman', serif;
--gold-line: #D5AE63;
--gold-soft: rgba(213, 174, 99, 0.55);
--gold-faint: rgba(213, 174, 99, 0.22);
--paper: #F5F1E8;
--paper-dim: rgba(245, 241, 232, 0.62);
--ink-deep: #0A1122;
padding: 12px 0 60px;
}
/* ================= Hero ================= */
.property-hero {
position: relative;
isolation: isolate;
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
align-items: start;
gap: 36px;
min-height: 320px;
padding: clamp(32px, 4.5vw, 56px);
padding-bottom: clamp(120px, 16vw, 170px);
overflow: hidden;
border-radius: 24px;
border: 1px solid rgba(213, 174, 99, 0.25);
color: var(--paper);
background: linear-gradient(180deg, #070C1C 0%, #0C1530 58%, #17224A 100%);
box-shadow: 0 24px 60px rgba(10, 17, 34, 0.35);
transition: background 1.4s ease;
}
.property-hero.t-dusk { background: linear-gradient(180deg, #0B1026 0%, #221B44 55%, #533353 85%, #7A4632 100%); }
.property-hero.t-dawn { background: linear-gradient(180deg, #0D1330 0%, #2C2C5C 55%, #7A4A63 85%, #A2653F 100%); }
.property-hero.t-day  { background: linear-gradient(180deg, #10254A 0%, #1E3E71 60%, #3D639C 100%); }
/* film grain */
.property-hero::after {
content: '';
position: absolute;
inset: 0;
z-index: 3;
pointer-events: none;
opacity: 0.05;
mix-blend-mode: overlay;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.72' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23n)'/%3E%3C/svg%3E");
}
.hero-aurora {
position: absolute;
z-index: 0;
width: 480px;
height: 480px;
left: -120px;
top: -40%;
border-radius: 50%;
background: rgba(200, 155, 60, 0.08);
filter: blur(90px);
animation: heroAurora 40s ease-in-out infinite alternate;
pointer-events: none;
}
@keyframes heroAurora {
from { transform: translate(0, 0) scale(1); }
to   { transform: translate(120px, 40px) scale(1.15); }
}
/* stars */
.hero-stars { position: absolute; inset: 0; z-index: 0; pointer-events: none; overflow: hidden; }
.hero-stars svg { width: 100%; height: 100%; display: block; overflow: hidden; }
.hero-star { fill: #EDE8DB; animation: starTwinkle 3.8s ease-in-out infinite; }
.hero-star:nth-child(3n)   { animation-delay: 1.3s; }
.hero-star:nth-child(3n+1) { animation-delay: 2.4s; }
.t-day .hero-stars, .t-dawn .hero-stars { opacity: 0.15; }
@keyframes starTwinkle {
0%, 100% { opacity: 0.25; }
50% { opacity: 0.9; }
}
/* engraved skyline along the bottom */
.hero-skyline {
position: absolute;
left: 0; right: 0; bottom: 0;
z-index: 1;
pointer-events: none;
}
.hero-skyline svg { display: block; width: 100%; height: auto; }
.hero-skyline .ln {
fill: none;
stroke: var(--gold-line);
stroke-width: 1.4;
stroke-linecap: round;
stroke-linejoin: round;
opacity: 0.75;
}
.hero-skyline .ln.dim { opacity: 0.3; stroke-width: 1.1; }
.hero-skyline .draw {
stroke-dasharray: 1;
stroke-dashoffset: 1;
animation: drawIn 1.8s cubic-bezier(0.4, 0, 0.2, 1) forwards;
animation-delay: var(--d, 0.2s);
}
@keyframes drawIn { to { stroke-dashoffset: 0; } }
.hero-skyline .glim {
fill: #F3CB7E;
opacity: 0;
animation: glimIn 1s ease forwards;
animation-delay: var(--d, 2.2s);
}
@keyframes glimIn { to { opacity: 0.75; } }
.hero-skyline .beacon {
fill: #F3CB7E;
opacity: 0;
animation: beaconPulse 4s ease-in-out infinite;
animation-delay: 2.6s;
}
@keyframes beaconPulse {
0%, 100% { opacity: 0.35; }
50% { opacity: 0.95; }
}
.hero-copy { position: relative; z-index: 2; max-width: 640px; }
.hero-eyebrow {
display: inline-flex;
align-items: center;
gap: 12px;
margin-bottom: 18px;
color: var(--gold-soft);
font-size: 0.66rem;
font-weight: 600;
letter-spacing: 0.32em;
text-transform: uppercase;
}
.hero-eyebrow::before {
content: '';
width: 30px;
height: 1px;
background: var(--gold-faint);
}
.hero-copy h1 {
margin: 0 0 12px;
overflow-wrap: anywhere;
color: var(--paper);
font-family: var(--serif);
font-weight: 400;
font-size: clamp(2rem, 3.6vw, 3.1rem);
line-height: 1.12;
letter-spacing: 0.012em;
text-shadow: 0 2px 22px rgba(2, 6, 16, 0.5);
}
.hero-copy > p {
max-width: 520px;
margin: 0;
color: var(--paper-dim);
font-size: clamp(0.95rem, 1.2vw, 1.04rem);
line-height: 1.7;
}
.hero-user {
display: inline-flex;
align-items: center;
gap: 9px;
margin-top: 22px;
padding: 8px 13px;
border: 1px solid rgba(213, 174, 99, 0.25);
border-radius: 999px;
color: var(--paper-dim);
background: rgba(7, 12, 28, 0.45);
font-size: 0.78rem;
letter-spacing: 0.02em;
backdrop-filter: blur(4px);
max-width: 100%;
overflow-wrap: anywhere;
}
.hero-user-dot {
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--gold-line);
box-shadow: 0 0 0 4px rgba(213, 174, 99, 0.12);
}
.hero-plaques {
position: relative;
z-index: 2;
display: flex;
flex-direction: column;
gap: 12px;
}
.hero-plaque {
min-width: 170px;
padding: 16px 20px;
border: 1px solid rgba(213, 174, 99, 0.28);
border-radius: 14px;
text-align: center;
background: rgba(7, 12, 28, 0.5);
box-shadow: inset 0 1px 0 rgba(230, 196, 116, 0.1);
backdrop-filter: blur(6px);
}
.hero-plaque strong {
display: block;
color: var(--paper);
font-family: var(--serif);
font-weight: 400;
font-size: 1.7rem;
line-height: 1.1;
letter-spacing: 0.06em;
font-variant-numeric: tabular-nums;
}
.hero-plaque span {
display: block;
margin-top: 7px;
color: var(--gold-soft);
font-size: 0.62rem;
font-weight: 600;
letter-spacing: 0.26em;
text-transform: uppercase;
}
/* ================= Section heading ================= */
.property-section { margin-top: 44px; }
.property-section-heading {
display: flex;
align-items: end;
justify-content: space-between;
gap: 20px;
margin-bottom: 20px;
}
.property-section-heading h2 {
margin: 0 0 6px;
color: var(--navy);
font-family: var(--serif);
font-weight: 400;
font-size: 1.55rem;
letter-spacing: 0.015em;
}
.property-section-heading p {
margin: 0;
color: var(--muted);
font-size: 0.9rem;
}
.secure-note {
display: inline-flex;
align-items: center;
gap: 7px;
color: #7C8799;
font-size: 0.76rem;
white-space: nowrap;
}
/* ================= Property cards ================= */
.property-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 20px;
}
.property-form {
min-width: 0;
animation: propertyArrive 0.6s cubic-bezier(0.22, 1, 0.36, 1) both;
animation-delay: calc(var(--card-order, 0) * 90ms);
perspective: 900px;
}
.property-card {
position: relative;
display: flex;
flex-direction: column;
width: 100%;
padding: 0;
overflow: hidden;
border: 1px solid rgba(213, 174, 99, 0.28);
border-radius: 18px;
text-align: left;
color: inherit;
background: linear-gradient(180deg, #0E1731 0%, #0A1122 100%);
box-shadow:
inset 0 1px 0 rgba(230, 196, 116, 0.08),
0 6px 18px rgba(10, 17, 34, 0.18);
cursor: pointer;
font: inherit;
will-change: transform;
transition: transform 0.25s cubic-bezier(0.22, 1, 0.36, 1), border-color 0.25s ease, box-shadow 0.25s ease;
}
.property-card:hover,
.property-card:focus-visible {
border-color: rgba(230, 196, 116, 0.6);
box-shadow:
inset 0 1px 0 rgba(230, 196, 116, 0.12),
0 22px 46px rgba(10, 17, 34, 0.32),
0 0 0 1px rgba(230, 196, 116, 0.12);
outline: none;
}
.property-card:not(.tilting):hover,
.property-card:focus-visible { transform: translateY(-5px); }
/* --- engraved art strip --- */
.property-art {
position: relative;
height: 158px;
overflow: hidden;
}
.property-art > svg {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
display: block;
}
.card-star { fill: #EDE8DB; opacity: 0.35; }
.property-card:hover .card-star { opacity: 0.7; }
.mini .ln {
fill: none;
stroke: var(--gold-line);
stroke-width: 1.3;
stroke-linecap: round;
stroke-linejoin: round;
opacity: 0.8;
}
.mini .ln.dim { opacity: 0.35; stroke-width: 1; }
.mini .accent { stroke: var(--hotel-color, #D5AE63); opacity: 0.9; }
.mini .win {
fill: none;
stroke: var(--gold-line);
stroke-width: 0.9;
opacity: 0.5;
transition: fill 0.35s ease, opacity 0.35s ease, filter 0.35s ease;
}
.mini .win.lit { fill: rgba(243, 203, 126, 0.75); opacity: 0.85; }
.property-card:hover .mini .win,
.property-card:focus-visible .mini .win {
fill: rgba(243, 203, 126, 0.8);
opacity: 0.95;
filter: drop-shadow(0 0 3px rgba(243, 203, 126, 0.7));
}
.property-card:hover .mini .win:nth-of-type(1) { transition-delay: 0ms; }
.property-card:hover .mini .win:nth-of-type(2) { transition-delay: 60ms; }
.property-card:hover .mini .win:nth-of-type(3) { transition-delay: 120ms; }
.property-card:hover .mini .win:nth-of-type(4) { transition-delay: 180ms; }
.property-card:hover .mini .win:nth-of-type(5) { transition-delay: 240ms; }
.property-card:hover .mini .win:nth-of-type(6) { transition-delay: 300ms; }
.property-card:hover .mini .win:nth-of-type(7) { transition-delay: 360ms; }
.property-card:hover .mini .win:nth-of-type(8) { transition-delay: 420ms; }
.property-card:hover .mini .win:nth-of-type(9) { transition-delay: 480ms; }
.property-card:hover .mini .win:nth-of-type(10) { transition-delay: 540ms; }
.mini-sign text {
fill: var(--gold-line);
font-family: var(--serif);
font-size: 15px;
letter-spacing: 5px;
opacity: 0.9;
}
.mini-sign rect { transition: filter 0.3s ease; }
.property-card:hover .mini-sign,
.property-card:focus-visible .mini-sign {
filter: drop-shadow(0 0 6px rgba(243, 203, 126, 0.55));
}
.mini-doorglow {
opacity: 0.25;
transition: opacity 0.4s ease;
}
.property-card:hover .mini-doorglow { opacity: 0.7; }
.property-chip {
position: absolute;
top: 13px;
right: 13px;
z-index: 1;
padding: 5px 10px;
border-radius: 999px;
color: var(--paper-dim);
background: rgba(7, 12, 28, 0.6);
border: 1px solid rgba(213, 174, 99, 0.3);
font-size: 0.62rem;
font-weight: 700;
letter-spacing: 0.18em;
text-transform: uppercase;
backdrop-filter: blur(4px);
}
.property-chip.current-property {
color: #14203E;
background: linear-gradient(180deg, #E9CA80, #C89B3C);
border-color: transparent;
}
/* --- card body --- */
.property-body {
display: flex;
flex-direction: column;
flex: 1;
padding: 20px 22px 18px;
border-top: 1px solid rgba(213, 174, 99, 0.16);
}
.property-name-row {
display: flex;
align-items: center;
gap: 13px;
}
.property-icon-img {
width: 42px;
height: 42px;
flex: 0 0 auto;
border-radius: 11px;
object-fit: contain;
background: #fff;
border: 1px solid rgba(213, 174, 99, 0.3);
padding: 3px;
}
.property-name {
margin: 0;
color: var(--paper);
font-family: var(--serif);
font-weight: 400;
font-size: 1.22rem;
line-height: 1.3;
letter-spacing: 0.015em;
}
.property-label {
margin-top: 5px;
color: var(--gold-soft);
font-size: 0.63rem;
font-weight: 600;
letter-spacing: 0.22em;
text-transform: uppercase;
}
.property-action {
display: flex;
align-items: center;
justify-content: space-between;
gap: 14px;
margin-top: auto;
padding-top: 18px;
}
.property-action > span:first-child {
color: var(--paper-dim);
font-size: 0.68rem;
font-weight: 600;
letter-spacing: 0.22em;
text-transform: uppercase;
transition: color 0.2s ease;
}
.property-card:hover .property-action > span:first-child,
.property-card:focus-visible .property-action > span:first-child { color: var(--gold-line); }
.property-action-icon {
display: inline-flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
border-radius: 50%;
color: var(--gold-line);
border: 1px solid rgba(213, 174, 99, 0.35);
background: transparent;
transition: color 0.22s ease, background 0.22s ease, transform 0.22s ease, border-color 0.22s ease;
}
.property-card:hover .property-action-icon,
.property-card:focus-visible .property-action-icon {
color: #14203E;
background: linear-gradient(180deg, #E9CA80, #C89B3C);
border-color: transparent;
transform: translateX(3px);
}
.property-empty {
grid-column: 1 / -1;
padding: 54px 28px;
border: 1px dashed rgba(169, 143, 82, 0.45);
border-radius: 18px;
text-align: center;
color: var(--muted);
background: rgba(255, 255, 255, 0.7);
}
.property-empty strong {
display: block;
margin-bottom: 6px;
color: var(--navy);
font-family: var(--serif);
font-weight: 400;
font-size: 1.1rem;
}
@keyframes propertyArrive {
from { opacity: 0; transform: translateY(12px); }
to   { opacity: 1; transform: translateY(0); }
}
/* ================= Responsive ================= */
@media (max-width: 980px) {
.property-hero { grid-template-columns: 1fr; min-height: 0; }
.hero-plaques { flex-direction: row; }
.hero-plaque { min-width: 0; flex: 1; }
.property-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 620px) {
.hotel-dashboard { padding-top: 0; }
.property-hero {
margin: 0 -16px;
padding: 30px 22px;
padding-bottom: 130px;
border-radius: 0 0 22px 22px;
border-left: none;
border-right: none;
border-top: none;
}
.hero-copy h1 { font-size: 1.9rem; }
.hero-plaques { display: grid; grid-template-columns: 1fr 1fr; }
.hero-plaque { padding: 13px 10px; }
.hero-plaque strong { font-size: 1.35rem; }
.hero-plaque span { letter-spacing: 0.16em; font-size: 0.58rem; }
.property-section { margin-top: 34px; }
.property-section-heading { align-items: flex-start; }
.secure-note { display: none; }
.property-grid { grid-template-columns: 1fr; }
}
@media (prefers-reduced-motion: reduce) {
.hero-star, .hero-aurora, .hero-skyline .beacon, .property-form { animation: none !important; }
.hero-skyline .draw, .hero-skyline .glim { animation-duration: 0.01s; animation-delay: 0s !important; }
.hero-skyline .beacon { opacity: 0.8; }
.property-hero, .property-card, .mini .win, .mini-sign, .mini-doorglow,
.property-action-icon, .card-star { transition: none !important; }
}

/* ---------------- reservations: create ----------------
   Lifted from reservations/templates/reservations/create.html on 2026-09-06 (WO-019 C5);
   the rules are unchanged. */
.modal { display: none; position: fixed; z-index: 1000; left: 0; top: 0; width: 100%; height: 100%; overflow: auto; background-color: rgba(0,0,0,0.4); }
.modal-content { background-color: #fefefe; margin: 10% auto; padding: 20px; border: 1px solid #888; width: 60%; border-radius: 8px; }
.close { color: #aaa; float: right; font-size: 28px; font-weight: bold; cursor: pointer; }
.booking-type-option { color: var(--muted); }
.booking-type-option.active { background: white; color: var(--navy); box-shadow: 0 1px 2px rgba(16,26,51,0.1); }

/* ---------------- reservations: edit ----------------
   Lifted from reservations/templates/reservations/edit.html on 2026-09-06 (WO-019 C5);
   the rules are unchanged. */
.modal { display: none; position: fixed; z-index: 1000; left: 0; top: 0; width: 100%; height: 100%; overflow: auto; background-color: rgba(0,0,0,0.4); }
.modal-content { background-color: #fefefe; margin: 8% auto; padding: 20px; border: 1px solid #888; width: min(680px, 92%); border-radius: 8px; }
.close { color: #aaa; float: right; font-size: 28px; font-weight: bold; cursor: pointer; }
.source-note {
display: flex;
gap: 12px;
align-items: flex-start;
margin-bottom: 20px;
padding: 14px 16px;
border: 1px solid #D6C48A;
border-left: 4px solid var(--gold);
border-radius: 8px;
background: var(--gold-bg);
font-size: 0.9em;
line-height: 1.55;
}
.source-note strong { color: var(--navy); }
.source-note code {
padding: 1px 5px;
border-radius: 4px;
background: rgba(22,33,62,0.07);
font-size: 0.92em;
}
/* Read-only, deliberately: these are eZee's reading of the booking, and
the nightly import re-asserts them on every run. An editable box here
would take a correction and lose it the same night. */
.ref-readout {
padding: 9px 12px;
border: 1px solid var(--border, #DDE2EA);
border-radius: 6px;
background: var(--neutral-bg);
}
.ref-readout code {
display: inline-block;
padding: 2px 7px;
margin-right: 6px;
border-radius: 4px;
background: rgba(22,33,62,0.07);
font-size: 0.95em;
word-break: break-all;
}
.ref-note { margin-top: 7px; color: var(--muted); font-size: 0.8em; line-height: 1.5; }
.ref-note code { font-size: 0.9em; margin-right: 0; }
.guest-table { width: 100%; border-collapse: collapse; margin-top: 10px; }
.guest-table th { padding: 6px 5px; text-align: left; background: var(--neutral-bg); font-size: 0.8em; }
.guest-table td { padding: 4px 3px; vertical-align: top; }
.guest-table td .form-control { font-size: 0.88em; }
.guest-meta { color: var(--muted); font-size: 0.75em; white-space: nowrap; }

/* ---------------- finance: the shared shapes ----------------
   WO-020 item 6. Thirteen finance templates carried 333 inline styles between
   them - 163 distinct declarations for what is, over and over, the same six or
   seven ideas: a muted note under a figure, a label-and-value row, a card with
   a coloured edge. Written inline, every screen invented its own spacing, so no
   two finance pages agreed how far a note sits from the thing it explains.

   Named for what they are rather than what they do, so a screen reads as a
   description of itself. `.muted`, `.nowrap`, `.num`, `.tight`, `.data-muted`
   and `.kv-row` already existed and are reused rather than re-cut. */

/* A note under the thing it explains. The single most-repeated shape in the
   module, at five slightly different sizes and four different margins. */
.note { color: var(--muted); font-size: .85em; margin: 4px 0 0; }
.note-above { color: var(--muted); font-size: .85em; margin: 0 0 10px; }
.note-danger { color: var(--danger); font-size: .85em; margin: 4px 0 0; }
.note-warning { color: var(--warning); font-size: .85em; margin: 4px 0 0; }

/* A heading or paragraph that starts a card: no top margin, because the card
   already has padding and two gaps stacked read as a mistake. */
.flush-top { margin-top: 0; }
.flush { margin: 0; }

/* Label on the left, figure on the right. `.kv-row` is the pair; `.is-ruled`
   adds the divider that separates a list of them. */
.kv-row.is-ruled { border-bottom: 1px solid var(--border); }
.kv-list .kv-row:last-child { border-bottom: 0; }

/* A card with a coloured edge, which is how this module says "read this one
   first". One class per meaning rather than a colour spelled out each time. */
.card-flag { border-left: 4px solid var(--border); margin-bottom: 18px; }
.card-flag-danger { border-left: 4px solid var(--danger); margin-bottom: 18px; }
.card-flag-warning { border-left: 4px solid var(--warning); margin-bottom: 18px; }
.card-flag-info { border-left: 4px solid var(--info); margin-bottom: 18px; }
.card-flag-gold { border-left: 4px solid var(--gold); margin-bottom: 18px; }
.card-flag-success { border-left: 4px solid var(--success); margin-bottom: 18px; }

/* A row of buttons or chips. */
.btn-row { display: flex; gap: 10px; flex-wrap: wrap; }
.btn-row-tight { display: flex; gap: 8px; }
.btn-row-baseline { display: flex; gap: 10px; align-items: flex-end; flex-wrap: wrap; }

/* A table that needs more room than `.data-table` gives it before the scroll
   starts. Five different min-widths were in use - 380, 480, 520, 720, 760 -
   and one is enough. Written against `table.data-table` because that rule
   declares a min-width itself and would otherwise outrank a bare class; the
   inline values never met that problem, because nothing outranks an inline
   style. That is the whole shape of this item in one line. */
table.data-table.table-wide { min-width: 760px; }

/* Fixed-width table columns, for the two or three that need to stop wrapping. */
.col-narrow { width: 110px; }

/* Nothing to show. Was three different paddings across three screens. */
.empty-pad { text-align: center; padding: 40px 20px; }

/* A grid of small figures. */
.figure-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 14px; }
.figure-grid-wide { grid-column: 1 / -1; }

/* Good, bad, or neither - chosen by the template's own `{% if %}` rather than
   by a colour written into a style attribute.

   **Written twice on purpose.** These replace inline styles, and an inline
   style beat every rule in this file; a single class does not. `.cl-tile
   strong` (one class, one element) outranks `.is-bad` (one class), so the
   city-ledger movement figure came back navy instead of red - the one thing on
   that tile that was telling somebody the number is bad news. Doubling the
   selector raises it above ordinary component rules without reaching for
   `!important`, which would win everywhere including where it should not. */
.is-bad.is-bad { color: var(--danger); }
.is-good.is-good { color: var(--success); }
.is-plain.is-plain { color: var(--muted); }
.is-strong.is-strong { color: var(--navy); font-weight: 600; }

/* Spacing that has to be said. Kept few on purpose: a screen needing a fourth
   one usually needs a shape, not a margin. */
.space-above { margin-top: 14px; }
.space-below { margin-bottom: 14px; }
.space-below-lg { margin-bottom: 18px; }

/* A bar whose length is a datum. The **only** kind of inline style a finance
   screen may carry, and it carries a custom property rather than a rule: a
   stylesheet cannot hold a number that is different for every row, and
   `style="--bar: 42%"` keeps the rule here where the rest of them are. */
.bar-fill { width: var(--bar, 0%); }
.bar-column { height: var(--bar, 0%); }

/* The rest of the vocabulary the finance pass needed. Ordinary shapes, named
   for what they are: nothing here is finance-specific and any screen may use
   them, which is the point of moving them out of thirteen files. */
.flex-fill { flex: 1; min-width: 0; }
.side-column { width: 330px; flex-shrink: 0; }
.stack-col { display: flex; flex-direction: column; gap: 10px; }
.is-centred { align-items: center; }
.is-top-aligned { align-items: flex-start; }
.is-middle { vertical-align: middle; }
.is-inline { display: inline; }
.is-inherit { color: inherit; }
.is-hidden { display: none; }
.is-normal-weight { font-weight: 400; }

/* Reading width. A paragraph of explanation running the full width of a
   desktop card is a paragraph nobody finishes. */
.measure { max-width: 720px; }

.small-text { font-size: .9em; }
.lead-text { font-size: .98rem; }
.bullets { margin: 0 0 10px; padding-left: 18px; }

/* The label above a figure, in the module's own small-caps. */
.field-label {
    color: var(--muted);
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.4px;
    font-weight: 700;
}

/* Chips, at the two sizes actually in use. */
.chip-sm { padding: 4px 12px; font-size: .84em; }
.chip-xs { padding: 2px 8px; font-size: 11px; margin-left: 6px; }

/* A short refusal or warning, inline above the thing it is about. */
.alert-danger {
    padding: 10px 14px;
    border-radius: 8px;
    background: var(--danger-bg);
    color: var(--danger);
    font-size: 0.86em;
    margin-bottom: 14px;
}

/* A finding, with its severity as a class rather than a colour written into
   the markup. */
.finding {
    display: flex;
    gap: 12px;
    align-items: flex-start;
    padding: 12px 14px;
    border-radius: 8px;
    background: var(--bg);
    border-left: 3px solid var(--gold);
}
.finding.is-high { border-left-color: var(--danger); }

/* ---------------- accounts: access overview ----------------
   G33. Twelve module columns beside a name; the columns are narrow and centred
   so a gap in one is visible reading down, which is the whole use of the page. */
.access-grid .access-col { text-align: center; white-space: nowrap; }
.access-grid thead .access-col { font-size: .78em; font-weight: 600; }
.access-grid tfoot td { border-top: 2px solid var(--border); font-weight: 600; }

/* ---------------- hotels: guide ----------------
   G84. The user guide, rendered from docs/USER_GUIDE.md. Contents beside the
   text on a wide screen, above it on a narrow one - a 1,800-line document with
   no way to jump is a document nobody finishes. */
.guide-layout { display: grid; grid-template-columns: 260px 1fr; gap: 18px; align-items: start; }
.guide-contents { position: sticky; top: 16px; max-height: calc(100vh - 40px); overflow-y: auto; font-size: .9em; }
.guide-contents ul { list-style: none; margin: 8px 0 0; padding: 0; }
.guide-contents li { margin: 2px 0; }
.guide-contents a { color: var(--muted); text-decoration: none; }
.guide-contents a:hover { color: var(--text); text-decoration: underline; }
.guide-level-1 { margin-top: 10px !important; font-weight: 600; }
.guide-level-1 a { color: var(--text); }
.guide-level-3 { padding-left: 12px; }
.guide-body { line-height: 1.6; max-width: 74ch; }
.guide-body h2 { margin: 26px 0 8px; padding-top: 6px; border-top: 1px solid var(--border); }
.guide-body h2:first-child { margin-top: 0; border-top: 0; }
.guide-body h3 { margin: 20px 0 6px; }
.guide-body h4 { margin: 16px 0 4px; }
.guide-body p { margin: 0 0 10px; }
.guide-body li { margin: 0 0 5px; }
.guide-body blockquote { margin: 10px 0; padding: 8px 12px; border-left: 3px solid var(--border); color: var(--muted); }
.guide-table { border-collapse: collapse; margin: 10px 0; width: 100%; }
.guide-table th, .guide-table td { border: 1px solid var(--border); padding: 6px 8px; text-align: left; }
.guide-missing-detail { margin: 6px 0 0; }

@media (max-width: 900px) {
    .guide-layout { grid-template-columns: 1fr; }
    .guide-contents { position: static; max-height: 220px; }
}

/* ---------------- hotels: standards ----------------
   Lifted from hotels/templates/hotels/standards.html on 2026-09-05
   (WO-019 B7); the rules are unchanged. */
.std-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 16px; }
.std-card {
    display: block; text-decoration: none; color: inherit; background: #fff;
    border: 1px solid var(--border); border-radius: var(--radius); padding: 20px;
    box-shadow: 0 1px 2px rgba(16,26,51,0.06);
    transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}
.std-card:hover {
    transform: translateY(-2px); border-color: var(--gold);
    box-shadow: 0 6px 18px rgba(16,26,51,0.09);
}
.std-card .icon {
    width: 38px; height: 38px; border-radius: 9px; background: var(--gold-bg);
    color: var(--gold-ink); display: flex; align-items: center; justify-content: center;
    margin-bottom: 12px;
}
.std-card h4 { margin: 0 0 5px; font-size: 1.02em; }
.std-card p { margin: 0; color: var(--muted); font-size: 0.88em; line-height: 1.5; }
.std-card .count { font-size: 0.8em; font-weight: 700; color: var(--navy); margin-top: 9px; display: block; }
.std-section { margin: 28px 0 14px; }
.std-section h3 { margin: 0 0 4px; }
.std-section p { margin: 0; color: var(--muted); font-size: 0.9em; }

/* ---------------- sales: document edit ----------------
   Lifted from sales/templates/sales/edit.html on 2026-09-05
   (WO-019 B7); the rules are unchanged. */
.lines-table { width: 100%; border-collapse: collapse; }
.lines-table th {
    text-align: left; font-size: 0.74em; text-transform: uppercase; letter-spacing: 0.4px;
    color: var(--muted); font-weight: 700; padding: 8px 6px; border-bottom: 2px solid var(--border);
}
.lines-table td { padding: 6px; border-bottom: 1px solid var(--border); vertical-align: top; }
.lines-table input, .lines-table select { font-size: 0.9em; padding: 7px 9px; }
.lines-table .del { text-align: center; }
/* A heading or note row uses only its description, so the numeric inputs
   are dimmed rather than removed - removing them would make the row jump
   around as the type changes. */
tr.non-priced .numeric { opacity: 0.35; pointer-events: none; }

/* ---------------- roster: roster detail ----------------
   Lifted from roster/templates/roster/detail.html on 2026-09-05
   (WO-019 B7); the rules are unchanged. */
/* ---------- Roster grid ----------
   Two sticky axes at once: the employee column stays put horizontally and
   the two header rows stay put vertically, so on a 31-column month you can
   always tell which person and which date a cell belongs to. The corner
   cell needs the highest z-index of the three or it gets painted over by
   whichever axis scrolls under it. */
.grid-wrap {
    overflow: auto;
    max-height: calc(100vh - 260px);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: white;
}
table.roster-grid { border-collapse: separate; border-spacing: 0; width: max-content; min-width: 100%; }
table.roster-grid th, table.roster-grid td { border-right: 1px solid var(--border); border-bottom: 1px solid var(--border); }

.rg-corner, .rg-name {
    position: sticky; left: 0; background: white; z-index: 2;
    min-width: 210px; max-width: 210px; text-align: left; padding: 8px 12px;
    box-shadow: 1px 0 0 var(--border);
}
.rg-corner { z-index: 4; top: 0; background: var(--navy); color: #fff; }
.rg-head { position: sticky; top: 0; z-index: 3; background: var(--navy); color: #fff; }
.rg-head th {
    padding: 5px 0; min-width: 42px; font-size: 0.72em; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.3px; text-align: center;
}
.rg-head th.dow { font-size: 0.66em; opacity: 0.75; padding-bottom: 0; }
.rg-head th.dom { font-size: 0.95em; padding-top: 0; }
.rg-head th.weekend { background: var(--gold); color: var(--navy); }
.rg-head th.holiday { background: var(--danger); color: #fff; }

.rg-name { font-size: 0.86em; }
.rg-name .who { font-weight: 700; color: var(--navy); display: block; }
.rg-name .meta { color: var(--muted); font-size: 0.88em; }

td.rg-cell {
    width: 42px; min-width: 42px; height: 38px; text-align: center; padding: 0;
    font-size: 0.8em; font-weight: 700; cursor: default; position: relative;
    transition: box-shadow 0.08s ease;
}
td.rg-cell.weekend { background: var(--gold-bg); }
td.rg-cell.holiday { background: #FBEAEA; }
td.rg-cell .chip {
    display: flex; align-items: center; justify-content: center;
    width: 100%; height: 100%; border-radius: 3px;
}
/* Editable cells advertise themselves on hover; read-only ones must not,
   or a published roster looks clickable and isn't. */
.editable td.rg-cell:hover { box-shadow: inset 0 0 0 2px var(--navy); }
.editable td.rg-cell { cursor: pointer; }
td.rg-cell.flagged::after {
    content: ''; position: absolute; top: 2px; right: 2px;
    width: 6px; height: 6px; border-radius: 50%; background: var(--danger);
}
td.rg-total { min-width: 62px; text-align: center; font-size: 0.8em; font-weight: 700; background: var(--bg); }

/* The paper's own furniture (WO-038): the WEEK 1..5 band over the day columns,
   the days somebody was not yet - or no longer - employed, and the mark that
   says which day that changed. Hatched rather than blank, because an empty
   cell and "not this roster's to answer for" are different facts and a
   supervisor reading a blank one would take it for an unfilled shift. */
.rg-head th.rg-band { background: var(--navy); color: var(--gold); font-size: 0.68em; }
td.rg-cell.rg-outside {
    background: repeating-linear-gradient(45deg, var(--neutral-bg), var(--neutral-bg) 3px, #fff 3px, #fff 6px);
    cursor: not-allowed;
}
.editable td.rg-cell.rg-outside:hover { box-shadow: none; }
.rg-mark {
    position: absolute; left: 0; right: 0; bottom: 0; font-size: 0.55em; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.2px; color: var(--navy); background: var(--gold-bg);
}

tr.rg-coverage td { background: var(--neutral-bg); font-size: 0.74em; font-weight: 700; text-align: center; padding: 5px 0; }
tr.rg-coverage td.short { background: var(--danger-bg); color: var(--danger); }
tr.rg-coverage .rg-name { background: var(--neutral-bg); font-size: 0.78em; }

/* ---------- Paint palette ---------- */
.palette { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.swatch {
    border: 2px solid transparent; border-radius: 7px; padding: 6px 11px; cursor: pointer;
    font-weight: 700; font-size: 0.82em; display: inline-flex; align-items: center; gap: 6px;
}
.swatch.active { border-color: var(--navy); box-shadow: 0 0 0 3px var(--gold-bg); }
.swatch { user-select: none; }
.swatch:active { cursor: grabbing; }
.swatch[draggable="true"] { cursor: grab; }
/* The cell being dragged over, so the drop target is never ambiguous. */
td.rg-cell.drop-target { box-shadow: inset 0 0 0 3px var(--gold); }
.swatch small { font-weight: 500; opacity: 0.85; }

.legend { display: flex; flex-wrap: wrap; gap: 8px; }
.legend span { display: inline-flex; align-items: center; gap: 6px; font-size: 0.82em; color: var(--muted); }
.legend i { width: 13px; height: 13px; border-radius: 3px; display: inline-block; }

@media (max-width: 900px) {
    .grid-wrap { max-height: none; }
    .rg-corner, .rg-name { min-width: 150px; max-width: 150px; }
}

/* ---------------- roster: shift list ----------------
   Lifted from roster/templates/roster/shift_list.html on 2026-09-05
   (WO-019 B7); the rules are unchanged. */
details.setup-panel > summary {
    cursor: pointer; list-style: none; display: flex; align-items: center; justify-content: space-between;
    gap: 12px; font-weight: 700; color: var(--navy);
}
details.setup-panel > summary::-webkit-details-marker { display: none; }
details.setup-panel > summary::after { content: '+'; font-size: 1.35rem; color: var(--gold); }
details.setup-panel[open] > summary::after { content: '\2212'; }
details.setup-panel[open] > summary { margin-bottom: 16px; padding-bottom: 12px; border-bottom: 1px solid var(--border); }
.nested-setup { margin-top: 14px; border-top: 1px solid var(--border); padding-top: 12px; }
.nested-setup > summary { cursor: pointer; color: var(--navy); font-weight: 700; }

/* ---------------- roster: team list ----------------
   Lifted from roster/templates/roster/team_list.html on 2026-09-05
   (WO-019 B7); the rules are unchanged. */
.team-toolbar { display: grid; grid-template-columns: minmax(240px, 1.4fr) minmax(190px, .8fr) auto; gap: 12px; align-items: end; }
.team-table { min-width: 880px; }
.team-table thead th { position: sticky; top: 0; z-index: 2; }
.team-table th:first-child, .team-table td:first-child {
    position: sticky; left: 0; z-index: 1; background: #fff; box-shadow: 1px 0 0 var(--border);
}
.team-table thead th:first-child { z-index: 3; background: var(--navy); }
.team-savebar {
    position: sticky; bottom: 14px; z-index: 4; margin-top: 14px; padding: 12px 14px;
    display: flex; align-items: center; justify-content: space-between; gap: 14px;
    border: 1px solid var(--border); border-radius: var(--radius); background: rgba(255,255,255,.96);
    box-shadow: 0 10px 30px rgba(20, 31, 52, .14); backdrop-filter: blur(8px);
}
.team-scroll-note { display: none; color: var(--muted); font-size: .82em; margin: 0 0 8px; }
@media (max-width: 760px) {
    .team-toolbar { grid-template-columns: 1fr; }
    .team-scroll-note { display: block; }
    .team-table th:first-child, .team-table td:first-child { min-width: 165px; max-width: 165px; }
    .team-savebar { bottom: 8px; align-items: stretch; flex-direction: column; }
    .team-savebar > div > div { display: none; }
    .team-savebar .btn { width: 100%; }
}
#team-save:disabled { opacity: .48; cursor: not-allowed; }

/* ---------------- roster: week view ----------------
   Lifted from roster/templates/roster/week.html on 2026-09-05
   (WO-019 B7); the rules are unchanged. */
/* The mobile view is a stack of per-employee cards rather than a squeezed
   grid: a 31-column table cannot be made usable at 375px, and staff on a
   phone want "what am I doing this week", not the whole department-month. */
.week-nav { display: flex; gap: 8px; align-items: center; justify-content: space-between; flex-wrap: wrap; }
.person { border: 1px solid var(--border); border-radius: var(--radius); background: #fff; margin-bottom: 12px; overflow: hidden; }
.person > header {
    display: flex; justify-content: space-between; align-items: center; gap: 10px;
    padding: 11px 14px; background: var(--bg); border-bottom: 1px solid var(--border);
}
.person h4 { margin: 0; font-size: 0.98em; }
.days { display: grid; grid-template-columns: repeat(7, 1fr); }
.day { padding: 9px 4px; text-align: center; border-right: 1px solid var(--border); }
.day:last-child { border-right: none; }
.day.weekend { background: var(--gold-bg); }
.day.holiday { background: #FBEAEA; }
.day.outside { opacity: 0.35; }
.day .dow { font-size: 0.68em; text-transform: uppercase; letter-spacing: 0.4px; color: var(--muted); font-weight: 700; }
.day .dom { font-size: 0.82em; color: var(--muted); margin-bottom: 5px; }
.day .code {
    display: inline-block; min-width: 30px; padding: 4px 6px; border-radius: 5px;
    font-weight: 700; font-size: 0.82em;
}
.day .none { color: var(--muted-light); font-size: 0.9em; }
@media (min-width: 900px) { .days { grid-template-columns: repeat(7, 1fr); } }

/* ---------------- night_audit: run detail ----------------
   Lifted from night_audit/templates/night_audit/detail.html on 2026-09-05
   (WO-019 B7); the rules are unchanged. */
.audit-overview { display: grid; grid-template-columns: repeat(4, minmax(150px, 1fr)); gap: 12px; margin-bottom: 18px; }
.audit-stat { padding: 16px 18px; }
.audit-stat span { display: block; color: var(--muted); font-size: .78em; text-transform: uppercase; letter-spacing: .05em; }
.audit-stat strong { display: block; color: var(--navy); font-size: 1.22rem; margin-top: 5px; }
.audit-layout { display: grid; grid-template-columns: minmax(250px, 320px) minmax(0, 1fr); gap: 20px; align-items: start; }
.audit-status { position: sticky; top: 18px; }
.audit-status, .report-stack, details.report-section { min-width: 0; }
details.report-section { padding: 0; overflow: hidden; }
details.report-section > summary {
    cursor: pointer; list-style: none; padding: 18px 20px; display: flex; align-items: center;
    justify-content: space-between; gap: 12px; color: var(--navy); font-weight: 700;
}
details.report-section > summary::-webkit-details-marker { display: none; }
details.report-section > summary::after { content: '+'; color: var(--gold); font-size: 1.35rem; }
details.report-section[open] > summary::after { content: '\2212'; }
details.report-section[open] > summary { border-bottom: 1px solid var(--border); }
.report-section__body { padding: 0 20px 20px; }
.report-stack { display: flex; flex-direction: column; gap: 14px; }
@media (max-width: 900px) { .audit-overview { grid-template-columns: repeat(2, minmax(0,1fr)); } .audit-layout { grid-template-columns: minmax(0, 1fr); } .audit-status { position: static; } }
@media (max-width: 520px) { .audit-overview { grid-template-columns: 1fr 1fr; } .audit-stat { padding: 13px 14px; } .audit-stat strong { font-size: 1rem; } }

/* nao:start - WO-083: what is inside Other. On the run list the figure opens
   into its names in place (the table scrolls sideways, so a floating panel
   would be clipped); `table.data-table td` outranks one class, hence the
   longer selector on the nested cells. */
.nao-other > summary { cursor: pointer; list-style: none; text-decoration: underline dotted var(--muted); text-underline-offset: 3px; }
.nao-other > summary::-webkit-details-marker { display: none; }
.nao-other > summary::after { content: ' \25BE'; color: var(--gold); }
.nao-other[open] > summary::after { content: ' \25B4'; }
.nao-other-list { margin-top: 6px; border-collapse: collapse; white-space: normal; }
table.data-table .nao-other-list td { height: auto; padding: 2px 0; border: 0; font-size: .85em; color: var(--muted); }
table.data-table .nao-other-list td + td { padding-left: 12px; text-align: right; white-space: nowrap; color: var(--ink); }
.nao-unrecorded { font-size: .8em; color: var(--muted); white-space: normal; }
.nao-head-note { display: block; max-width: 30ch; margin-top: 3px; font-size: .92em; font-weight: 500; letter-spacing: 0; text-transform: none; color: var(--muted); white-space: normal; }
.nao-sub { margin: 18px 0 8px; font-size: .95rem; color: var(--navy); }
.nao-seen { margin: 0 0 16px; padding: 14px 16px; border: 1px solid var(--gold); border-radius: var(--radius-sm); background: var(--warning-bg); }
.nao-seen-add { display: flex; gap: 8px; align-items: center; }
.nao-seen-add input.na-cell-input { width: 84px; height: 32px; }
/* nao:end */

/* ---------------- night_audit: settings ----------------
   Lifted from night_audit/templates/night_audit/settings.html on 2026-09-05
   (WO-019 B7); the rules are unchanged. */
.na-settings-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 22px; }
.na-index {
    position: sticky; top: 0; z-index: 4;
    display: flex; flex-wrap: wrap; gap: 6px; margin: -6px 0 18px; padding: 8px 0;
    background: linear-gradient(180deg, var(--bg) 80%, rgba(244,245,247,0));
}
.na-index a {
    display: inline-flex; align-items: center; gap: 6px; min-height: 32px; padding: 4px 12px;
    border-radius: 999px; background: var(--surface); border: 1px solid var(--border);
    color: var(--ink); text-decoration: none; font-size: 0.8rem; font-weight: 600;
}
.na-index a:hover { border-color: var(--gold); color: var(--navy); }
.na-index a span { font-size: 0.7rem; font-weight: 800; color: var(--muted); background: var(--neutral-bg); border-radius: 999px; padding: 0 7px; }
.na-index a.is-alert { border-color: var(--danger); color: var(--danger); }
.na-card, .na-card h3[id] { scroll-margin-top: 64px; }
@media (max-width: 1023.98px) { .na-index { top: var(--topbar-h); } .na-card, .na-card h3[id] { scroll-margin-top: calc(var(--topbar-h) + 64px); } }
.na-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 22px; box-shadow: var(--shadow-sm); }
.na-card h3 { margin: 0 0 4px; font-size: 1.08rem; }
.na-card .na-hint { margin: 0 0 14px; color: var(--muted); font-size: 0.85rem; }
/* Same trap, same fix: `.na-card .na-hint` is two classes and beats `.mt-18`. */
.na-card .na-hint.is-spaced { margin-top: 18px; }
.na-table { width: 100%; border-collapse: collapse; font-size: 0.88rem; }
.na-table th { text-align: left; padding: 7px 10px; color: var(--muted); font-size: 0.74rem; text-transform: uppercase; letter-spacing: 0.06em; border-bottom: 1px solid var(--border); }
.na-table td { padding: 7px 10px; border-bottom: 1px solid var(--border); }
.na-table tr:last-child td { border-bottom: none; }
.na-cell-code { font-family: Consolas, monospace; background: var(--neutral-bg); padding: 1px 7px; border-radius: 5px; font-size: 0.84em; }
.na-ignored { color: var(--muted-light); font-style: italic; }
.na-add-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: end; margin-top: 12px; padding-top: 14px; border-top: 1px dashed var(--border); }
.na-add-row .form-group { margin: 0; }
.na-add-row label { display: block; font-size: 0.74rem; color: var(--muted); margin-bottom: 3px; }
.na-add-row input, .na-add-row select { height: 36px; }
.na-add-row input.na-cell-input { width: 84px; }
.btn-delete-inline { border: none; background: none; color: var(--danger); cursor: pointer; font-size: 0.82rem; padding: 3px 7px; border-radius: 5px; }
.btn-delete-inline:hover { background: var(--danger-bg); }
.na-status-ok { color: var(--success); font-weight: 600; }
.na-status-missing { color: var(--danger); font-weight: 600; }
.na-two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 22px; }
@media (max-width: 900px) { .na-two-col { grid-template-columns: minmax(0, 1fr); } }

/* ---------------- ledger: budgets ----------------
   Lifted from ledger/templates/ledger/budgets.html on 2026-09-05
   (WO-019 B7); the rules are unchanged. */
.bdg-input { width: 130px; text-align: right; font-variant-numeric: tabular-nums; }
.bdg-actual { color: var(--muted); font-variant-numeric: tabular-nums; }
.bdg-section td { padding-top: 16px; font-weight: 700; color: var(--navy); }
/* WO-062 item 11: the rules that were `style=` attributes on this template,
   moved here unchanged, and the year-to-date column the bullets sit in. The
   grid is wider by one column, so it scrolls inside its card a little sooner -
   `min-width` is what makes the scroll happen rather than the columns
   collapsing onto each other. */
/* `table.` is deliberate: `table.data-table` sets `min-width: 640px` and a bare
   `.bdg-table` loses to it on specificity, so the fourth column would have been
   squeezed into a table still declared 640 wide. Read back from the computed
   style, which is the only way that kind of near-miss is ever visible. */
table.bdg-table { min-width: 760px; }
/* `min-width: 0` is load-bearing, not tidiness (DESIGN §6). The form is a grid
   item of `.rp-page` now, a grid item's automatic minimum size is its
   min-content, and its min-content is the table's own `min-width` - so the
   page's column stretched to 674px at 390px wide and `.table-scroll` never got
   the chance to scroll. Measured by tools/ui_sweep.py, which is what it is for. */
.bdg-form { padding-bottom: 8px; min-width: 0; }
.bdg-rule { margin-bottom: 18px; border-left: 4px solid var(--info); }
.bdg-rule-body { color: var(--muted); font-size: .88em; margin-top: 4px; }
.bdg-none { color: var(--muted-light); }
.bdg-ytd { min-width: 190px; }
.bdg-ytd .rp-chart { display: block; }
.bdg-ytd .rp-empty { margin: 0; font-size: .82em; color: var(--muted-light); }
.bdg-ytd-figures {
    color: var(--muted); font-size: .82em; text-align: right;
    font-variant-numeric: tabular-nums;
}
/* The save bar follows the page down: this table is as long as the chart,
   and a button only at the bottom means scrolling past forty rows to use it. */
.bdg-bar {
    position: sticky; bottom: 0; z-index: 3; margin-top: 14px;
    display: flex; gap: 12px; align-items: center; flex-wrap: wrap;
    padding: 12px 14px; border: 1px solid var(--border); border-radius: var(--radius);
    background: var(--surface); box-shadow: 0 -4px 14px rgba(16, 28, 58, 0.06);
}
.bdg-bar .bdg-note { color: var(--muted); font-size: .85em; }
@media (max-width: 560px) { .bdg-input { width: 100%; } }

/* ---------------- ledger: profit and loss ----------------
   Lifted from ledger/templates/ledger/profit_and_loss.html on 2026-09-05
   (WO-019 B7); the rules are unchanged. */
/* Favourable and adverse, decided by the account's type in `budgets.py` and
   never by the sign of the number - under budget on a cost and under budget
   on revenue are the same arithmetic and opposite news. */
.pl-good { color: var(--success); }
.pl-bad { color: var(--danger); }
.pl-nobudget { color: var(--muted-light); font-size: .85em; }

/* --- Employee picker ----------------------------------------------------
   A searchable list of people, replacing the `<select>` that carried every
   name at the hotel. Scrolls rather than growing the page: sixty rows is a
   normal month, and the search box has to stay in view while somebody types.
   Rows hidden by the filter use `hidden`, so the list is correct with
   JavaScript off - everything simply shows. */
.picker-list {
    max-height: 260px;
    overflow-y: auto;
    border: 1px solid var(--border);
    border-radius: 8px;
    margin-top: 8px;
}
.picker-row {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 8px 12px;
    border-bottom: 1px solid var(--border);
    cursor: pointer;
}
.picker-row:last-child { border-bottom: 0; }
.picker-row:hover { background: var(--surface-2, rgba(0, 0, 0, .03)); }
.picker-row input { margin-top: 3px; }
.picker-row .employee-meta { display: block; margin-top: 2px; }
.picker-empty { padding: 12px; color: var(--muted); font-size: .9em; }

/* --- "What was this day?" ------------------------------------------------
   Folded away by default: a month has thirty rows and only a few of them are
   ever a question, so the control has to be reachable without shouting on
   every line. */
.day-answer { margin-top: 6px; }
.day-answer > summary {
    cursor: pointer;
    font-size: .84em;
    color: var(--navy);
    font-weight: 600;
    list-style: none;
}
.day-answer > summary::-webkit-details-marker { display: none; }
.day-answer > summary::before { content: "+ "; }
.day-answer[open] > summary::before { content: "\2212 "; }
.day-answer > summary:hover { text-decoration: underline; }
/* The Note column is the narrowest in a table that already scrolls sideways,
   so the panel sets its own width rather than inheriting a squeezed one -
   otherwise the reason box arrives about eight characters wide. */
.day-answer[open] { min-width: 210px; }
.day-answer form { min-width: 200px; }

/* ---------------- WO-022: the person page ---------------- */
/* Small utilities a working screen needs instead of a style attribute. */
.muted { color: var(--muted); }
.nowrap { white-space: nowrap; }
.text-warning { color: var(--warning); }
.text-info { color: var(--info); }
.form-control-sm { padding: 5px 8px; font-size: 0.86rem; }
.form-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 14px; }

/* A card's left rule says what state the thing in it is in. */
.card.is-held { border-left: 4px solid var(--warning); }
.card.is-ready { border-left: 4px solid var(--info); }
.card.is-approved { border-left: 4px solid var(--success); }
.caveat-card { font-size: 0.88rem; margin-bottom: 18px; }

/* The net in large type beside the one thing to do about it. */
.hero-card { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 18px 28px; align-items: start; margin-bottom: 18px; }
.hero-number { font-size: 2rem; font-weight: 800; color: var(--navy); line-height: 1.1; font-variant-numeric: tabular-nums; }
.hero-note { color: var(--muted); font-size: 0.86rem; margin-top: 4px; }
.state-reasons { margin: 6px 0 0 18px; padding: 0; font-size: 0.92rem; line-height: 1.5; }
.state-form { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; margin-top: 8px; }
.state-form .form-control { flex: 1 1 220px; min-width: 0; }
.state-line { font-size: 0.92rem; margin-top: 4px; }
.metric-note { color: var(--muted); font-size: 0.8rem; margin-top: 2px; }
.metric-value.muted { color: var(--muted); }

/* Secondary actions behind one button, so the header keeps one primary. */
.overflow-menu { position: relative; }
.overflow-menu > summary { list-style: none; }
.overflow-menu > summary::-webkit-details-marker { display: none; }
.overflow-menu-list {
    position: absolute; right: 0; top: calc(100% + 6px); z-index: 30; min-width: 220px; padding: 6px;
    background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-sm); box-shadow: var(--shadow-md);
}
.overflow-menu-list > a, .overflow-menu-list > button, .overflow-menu-list > form > button {
    display: block; width: 100%; text-align: left; padding: 10px 12px; font: inherit; font-size: 0.92rem;
    color: var(--ink); background: none; border: none; border-radius: 6px; cursor: pointer; text-decoration: none;
}
.overflow-menu-list > a:hover, .overflow-menu-list > button:hover,
.overflow-menu-list > form > button:hover { background: var(--surface-2); }
.overflow-menu-list > .is-danger { color: var(--danger); }

/* The day table: one row per day, the answer inline, the reason only once a day is changed. */
.days-bulk { display: grid; grid-template-columns: minmax(0, 220px) minmax(0, 1fr); gap: 12px; margin-bottom: 12px; }
.days-table tr.is-absent td { background: var(--danger-bg); }
.days-table tr.is-over td { background: var(--warning-bg); }
.days-table .day-cell { min-width: 230px; }
.days-table .day-cell .form-control + .form-control { margin-top: 6px; }
.days-table .hours-cell .form-control { width: 88px; }
.note-cell { min-width: 240px; max-width: 340px; font-size: 0.84rem; }
.figures-table td:first-child { width: 60%; }
.figures-total td { font-weight: 700; border-top: 2px solid var(--border-strong); }

@media (max-width: 767px) {
    .hero-card { grid-template-columns: minmax(0, 1fr); }
    .days-bulk { grid-template-columns: minmax(0, 1fr); }
}

/* ---------------- WO-022: the month page ---------------- */
/* Filter tabs are links, so a filter is a URL somebody can come back to. */
/* `nowrap` only while it fits (WO-029 item 3). A state label can be as long
   as "Approved - being repaid (before disbursement was recorded)", which at
   447px is wider than a phone: with the strip no longer scrolling, a tab that
   refuses to wrap makes the *page* scroll sideways instead, which is the same
   complaint one level up. It wraps inside its own tab rather than doing that. */
.tabs-nav a {
    font-weight: 600; font-size: 0.9rem; border-bottom: 2px solid transparent;
    color: var(--muted); padding: 11px 15px; margin-bottom: -1px; max-width: 100%;
    display: inline-flex; align-items: center; gap: 8px; text-decoration: none;
}
.tabs-nav a:hover { color: var(--navy); }
.tabs-nav a[aria-selected="true"] { color: var(--navy); border-bottom-color: var(--gold); }
.tabs-nav a[aria-selected="true"] .tab-count { background: var(--navy); color: #fff; }
.tabs-menu { align-self: center; }
.tabs-menu:first-of-type { margin-left: auto; }
.tabs-menu > summary { cursor: pointer; font-size: 0.86rem; font-weight: 600; color: var(--muted); padding: 8px 10px; white-space: nowrap; }
.tabs-menu > summary:hover { color: var(--navy); }

.month-hero .hero-number small { font-size: 1rem; font-weight: 600; color: var(--muted); }
.month-hero-wide { grid-column: 1 / -1; }
.text-danger { color: var(--danger); }
.text-success { color: var(--success); }
/* The colour, and only the colour. `.data-muted` sets a font-size with it, which
   is right for a caption and wrong for a cell that must stay the table's size -
   swapping one for the other is the single-class trap WO-036 item 8 measured
   (WO-044). */
.text-muted { color: var(--muted); }
.text-info { color: var(--info); }
.tick-col { width: 36px; }
.tick-col input { width: 18px; height: 18px; margin: 0; }
.evidence-body { padding: 16px 20px 20px; }
.evidence-line { color: var(--muted); font-size: 0.9rem; margin-bottom: 12px; }
.evidence .block-heading { margin-top: 14px; }

@media (max-width: 767px) {
    /* The month table collapses to person, net, state and the button. */
    .month-table .phone-hide { display: none; }
    .tabs-menu:first-of-type { margin-left: 0; }
}
@media (max-width: 767px) {
    /* Person, net, state and the button fit a phone once the notes go. */
    table.month-table { min-width: 0; }
    table.month-table th, table.month-table td { padding-left: 8px; padding-right: 8px; }
    .month-table .metric-note, .month-table .row-flags { display: none; }
    .month-table .employee-meta .meta-dot:nth-child(n+2) { display: none; }
}

/* ---------------- WO-022: the queue and the forms it opens ---------------- */
.picker-search { padding: 14px 18px 4px; }
.picker-search .block-heading { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin: 0 0 8px; }
.queue-actions { display: flex; gap: 6px; justify-content: flex-end; }
.advance-actions { min-width: 240px; }
.advance-form { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.advance-form .form-control { width: auto; min-width: 0; }
.advance-form input[name="month"] { width: 64px; }
.advance-form input[name="year"] { width: 80px; }
.advance-form input[type="text"] { width: 150px; }
.advance-form input[type="date"] { width: 150px; }
.manual-cell { min-width: 110px; }
.btn-block { width: 100%; }

/* ---------------- WO-022: employees and the form ---------------- */
#employee-editor details.editor-section { margin-bottom: 18px; }
#employee-editor .field-grid { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); align-items: start; }
.check-list { display: grid; gap: 10px; margin-top: 16px; }
.check-row { display: flex; align-items: flex-start; gap: 9px; font-weight: 500; cursor: pointer; }
.check-row input { margin-top: 3px; }
.check-row .field-hint { display: block; font-weight: 400; }
.derived-figure { padding: 10px 12px; background: var(--gold-bg); border-radius: var(--radius-sm); font-size: 0.92rem; font-weight: 700; color: var(--navy); }

/* ---------------- WO-022: the register and the rest ----------------
   The last inline styles, lifted into names. Spacing and emphasis only;
   colours are tokens. */
.small { font-size: 0.88em; }
.strong { font-weight: 700; }
.semibold { font-weight: 600; }
.tight { margin: 0; }
.tight-below { margin: 0 0 8px; }
.mb-0 { margin-bottom: 0; }
.mb-10 { margin-bottom: 10px; }
.mb-14 { margin-bottom: 14px; }
.mb-18 { margin-bottom: 18px; }
.mt-8 { margin-top: 8px; }
.mt-14 { margin-top: 14px; }
.mt-16 { margin-top: 16px; }
.ml-4 { margin-left: 4px; }
.w-40 { width: 40%; }
.min-w-180 { min-width: 180px; }
.min-w-220 { min-width: 220px; }
.text-ink { color: var(--ink); }
.text-navy { color: var(--navy); }
.card.is-info { border-left: 4px solid var(--info); }
.main-col { flex: 1; min-width: 0; }
.sidebar-col { width: 340px; flex-shrink: 0; }
table.table-wide { min-width: 900px; }
tr.row-total td { background: var(--bg); font-weight: 700; }
.table-foot-note { padding: 12px 16px; font-size: 0.85em; color: var(--muted); border-top: 1px solid var(--border); }
.bullet-list { margin: 0; padding-left: 18px; color: var(--muted); font-size: 0.9em; line-height: 1.7; }
.rule { border: none; border-top: 1px solid var(--border); margin: 18px 0; }
.callout-gold { margin-top: 16px; padding: 12px; background: var(--gold-bg); border-radius: var(--radius-sm); font-size: 0.86em; color: var(--gold-ink); }

/* Key-value rows on the register's detail page. */
.kv-row { display: flex; justify-content: space-between; gap: 12px; padding: 7px 0; }
.kv-row.is-ruled { border-bottom: 1px solid var(--border); }
.kv-row.is-loose { padding: 10px 0; }
.kv-row.is-topped { border-top: 1px solid var(--border); }
.kv-row.is-total { padding: 12px 0; font-size: 1.15em; }

@media (max-width: 767px) {
    .sidebar-col { width: auto; }
}

/* ---------------- WO-029: the leave register ---------------- */
/* A filter row that wraps, like everything else on a payroll page since item
   3: no fixed height, no inner scrollbar, and the boxes drop onto a second
   line rather than the strip growing a scrollbar of its own. */
.filter-row {
    display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-end;
    padding: 14px 18px; margin-bottom: 14px;
}
.filter-row .form-group { margin-bottom: 0; min-width: 150px; flex: 1 1 150px; }
.filter-row .filter-actions { display: flex; gap: 8px; flex: 0 0 auto; min-width: 0; }

/* Cancelled, not deleted (item 5, G14). Struck through and dimmed, because
   what it says is still the history of how a month was classified - it is the
   calculations that stop reading it, not the reader. */
tr.is-cancelled td { color: var(--muted); }
tr.is-cancelled td:first-child strong,
tr.is-cancelled td:nth-child(2),
tr.is-cancelled td:nth-child(3),
tr.is-cancelled td:nth-child(4) { text-decoration: line-through; }
.badge-muted { background: var(--neutral-bg); color: var(--muted); }
.row-action > summary { cursor: pointer; font-size: 0.86rem; font-weight: 600; color: var(--muted); }
.row-action > summary:hover { color: var(--navy); }
.row-action[open] > summary { margin-bottom: 6px; }

/* ---------------- WO-036 item 8: the vocabulary the five modules needed ----
   Measured 2026-09-08 across the screens of accounting, invoices, integrations,
   roster, sales, hotels and finance: 1,181 inline `style=` attributes, 487 of
   them distinct, 308 of those used exactly once.

   The 308 are not addressed here and naming them would not improve anything -
   a single-use class is an inline style with an extra indirection. What is
   here is the part that genuinely repeats: spacing, alignment, one-line flex
   rows and the two or three type sizes these screens actually use. WO-022
   built the same vocabulary for payroll and the names below follow it.

   One trap, kept rather than fixed because renaming it would touch payroll:
   `.mt-3` above is **15px** - a scale name from an older pass - while
   `.mt-8`, `.mt-14` and `.mt-16` are pixel names. Everything added here is a
   pixel name, and `.mt-3` is left alone and unused by this sweep. */

/* Spacing. Pixel names, matching the majority of what WO-022 left. */
.mt-0 { margin-top: 0; }
.mt-4 { margin-top: 4px; }
.mt-6 { margin-top: 6px; }
.mt-10 { margin-top: 10px; }
.mt-12 { margin-top: 12px; }
.mt-20 { margin-top: 20px; }
.mb-4 { margin-bottom: 4px; }
.mb-8 { margin-bottom: 8px; }
.mb-16 { margin-bottom: 16px; }
.mb-22 { margin-bottom: 22px; }
.mb-26 { margin-bottom: 26px; }
.p-20 { padding: 20px; }
.p-24 { padding: 24px; }

/* Type. Only the sizes these screens actually reach for. */
.fs-85 { font-size: 0.85em; }
.fs-88 { font-size: 0.88em; }
.fs-90 { font-size: 0.9em; }

/* Alignment. `.num` already covers a right-aligned *number* (it adds tabular
   figures); this is for the ones that are not numbers. */
.ta-right { text-align: right; }
.ta-center { text-align: center; }
.va-middle { vertical-align: middle; }

/* Flex rows, by gap. These were sixteen and nine copies of the same two
   declarations; `.action-group` above is the same idea with `align-items:
   center` and stays where a row of buttons needs it. */
.row-8 { display: flex; gap: 8px; flex-wrap: wrap; }
.row-10 { display: flex; gap: 10px; flex-wrap: wrap; }
.row-12 { display: flex; gap: 12px; flex-wrap: wrap; }
.flex-1 { flex: 1; }
.w-full { width: 100%; }

/* A heading that sits flush with the top of the card it names. Eleven copies
   of `margin-top: 0; font-size: 1.02em`. */
.panel-heading { margin-top: 0; font-size: 1.02em; }

/* The rule above a form's last, quieter action - "delete this draft", "void".
   Seven copies, all of them the same three declarations. */
.section-top { margin-top: 18px; border-top: 1px solid var(--border); padding-top: 14px; }

/* ---------------- WO-036 item 8: the sweep itself ----------------
   The block above was built from the first measurement and covered the
   spacing and type the six modules repeated. Sweeping the 645 attributes the
   gate refuses turned up a second layer: the same *idea* written at ten
   different sizes. A muted note under a thing appeared at .8, .82, .84, .85,
   .86, .87, .88, .89, .9 and .92em, with margin-tops of 0, 2, 3, 4 and 6px -
   47 attributes for one idea, which is `.note` and has been since WO-020.

   Those collapse onto `.note`, `.data-muted` and `.field-hint` rather than
   growing `.fs-82`, `.fs-84`, `.fs-86`, `.fs-87` and `.fs-89`. That is a
   visible change - a hundredth of an em here and there - and it is the point
   of the item: the reviewers' complaint was that no two pages agree, and ten
   sizes for one idea is what disagreement looks like in a stylesheet. */

/* Buttons at the two sizes these screens reach for beyond `.btn-sm`. The
   large one is the single primary action on an upload or a confirm page. */
.btn-lg { padding: 12px 24px; font-size: 1.05em; }
.btn-xs { padding: 4px 10px; font-size: 12px; }

/* Spacing, continuing the pixel names above. */
.mt-2 { margin-top: 2px; }
.mt-18 { margin-top: 18px; }
.mt-22 { margin-top: 22px; }
.mt-26 { margin-top: 26px; }
.mb-2 { margin-bottom: 2px; }
.mb-6 { margin-bottom: 6px; }
.mb-12 { margin-bottom: 12px; }
.mb-20 { margin-bottom: 20px; }
.ml-6 { margin-left: 6px; }
.ml-10 { margin-left: 10px; }
.ml-auto { margin-left: auto; }
.p-0 { padding: 0; }
.p-12 { padding: 12px; }
.p-28 { padding: 28px; }
.pt-8 { padding-top: 8px; }

/* Type and colour. `.muted` is the colour alone; these are the two the
   screens actually distinguish it from. */
.fs-12 { font-size: 12px; }
.fs-115 { font-size: 1.15em; }
.fs-150 { font-size: 1.5em; }
.muted-light { color: var(--muted-light); }
.fw-500 { font-weight: 500; }

/* Width. `.min-w-180` and `.min-w-220` above are the same idea; these are the
   widths a table sets on itself so `.table-scroll` knows when to scroll. */
.w-auto { width: auto; }
.min-w-0 { min-width: 0; }
.min-w-320 { min-width: 320px; }
.min-w-420 { min-width: 420px; }
.min-w-480 { min-width: 480px; }
.min-w-520 { min-width: 520px; }
.min-w-560 { min-width: 560px; }
.min-w-640 { min-width: 640px; }
.max-w-320 { max-width: 320px; }
.max-w-620 { max-width: 620px; }

/* Flex and grid, continuing `.row-8` / `.row-10` / `.row-12` above. */
.row-6 { display: flex; gap: 6px; flex-wrap: wrap; }
.row-24 { display: flex; gap: 24px; flex-wrap: wrap; }
.flex-2 { flex: 2; }
.flex-none { flex: 0 0 auto; }
.is-block { display: block; }
.is-flex { display: flex; }
.is-none { display: none; }
.is-inline-flex { display: inline-flex; }
.is-column { flex-direction: column; }
.is-baseline { align-items: baseline; }
.is-end { align-items: flex-end; }
.is-spread { justify-content: space-between; }
.is-pointer { cursor: pointer; }

/* An auto-fitting grid of small cards. Four copies at 200px, two at 260px. */
.auto-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 12px; }
.auto-grid-wide { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 12px; }

/* A borderless two-column list of figures - a label on the left, a figure on
   the right - inside a card. Twenty copies between the invoice, payment and
   statement pages, none of them agreeing about the padding. */
.fig-row { padding: 5px 0; color: var(--muted); }
.fig-val { padding: 5px 0; text-align: right; }
.fig-val-strong { padding: 5px 0; text-align: right; font-weight: 700; }


/* The rest of what the sweep met. Each of these was two or more copies; the
   ones that were genuinely singular stayed in the screen block that names
   them, further down. */

/* A small-caps label above a figure. Seventeen copies, three spellings. */
.eyebrow { font-size: 0.82em; color: var(--muted); font-weight: 700; text-transform: uppercase; letter-spacing: 0.4px; }

/* A bordered row in a pick list - a checkbox, a name, a note. */
.pick-row { display: flex; gap: 8px; align-items: flex-start; padding: 8px; border: 1px solid var(--border); border-radius: 8px; margin-bottom: 6px; font-size: .9em; }

/* A filter row sunk into the page rather than sitting on it. */
.inset-row { display: flex; gap: 10px; flex-wrap: wrap; align-items: flex-end; padding: 10px; background: var(--bg); border: 1px solid var(--border); border-radius: 7px; margin-bottom: 8px; }

/* Plain table cells, for the tables that are not `.data-table`. */
.td-ruled { padding: 8px 10px; border-bottom: 1px solid var(--border); }
.th-plain { text-align: left; padding: 8px 10px; color: var(--muted); font-size: 0.74rem; text-transform: uppercase; letter-spacing: 0.06em; border-bottom: 1px solid var(--border); }
.td-empty { padding: 14px 10px; color: var(--muted); }
.ruled { border-bottom: 1px solid var(--border); }
.rule-strong { border-top: 2px solid var(--border); }

/* A panel a button opens. Hidden until a script sets `hidden` off. */
.drawer { display: none; background: var(--neutral-bg); border-radius: 8px; padding: 14px; }

/* The file drop target on the Inbox's upload page. */
.dropzone { border: 2px dashed var(--border-strong); border-radius: 12px; padding: 22px; text-align: center; margin-bottom: 10px; transition: border-color .15s ease, background .15s ease; }

/* An amber cousin of `.alert-danger`, which was already here. */
.alert-warning { padding: 10px 12px; border-radius: 8px; background: var(--warning-bg); color: var(--warning); font-size: 0.88em; margin-bottom: 16px; }

.dimmed { opacity: .58; }
.is-centred-x { justify-content: center; }
.is-plain-link { text-decoration: none; }
.fs-72 { font-size: .72em; }
.form-control-xs { width: auto; padding: 4px 6px; font-size: 12px; }
.stack-col.is-loose { gap: 20px; }

/* Column widths, for the tables that set one. */
.w-34 { width: 34px; }
.w-52 { width: 52px; }
.w-90 { width: 90px; }
.w-120 { width: 120px; }
.w-160 { width: 160px; }
.max-w-160 { max-width: 160px; }
.max-w-340 { max-width: 340px; }
.max-w-560 { max-width: 560px; }
.pb-11 { padding-bottom: 11px; }

/* ---------------- WO-036 item 8: roster, the grid and its palette ----------
   A shift's colour is a column on the shift, chosen by a person - a
   stylesheet cannot hold it, so it arrives as a custom property through the
   door the finance gate opened for the bar whose length is its own figure.
   `readable_on` decides black or white ink against it. */
.swatch-fill { background: var(--swatch); color: var(--swatch-ink); }
.legend i.swatch-fill { background: var(--swatch); }
/* The one swatch with no colour of its own: "erase what is here". */
.swatch-erase { background: #fff; border: 2px dashed var(--border); color: var(--muted); }
/* One warning per row in the list the Show / hide button opens. */
.warn-row { padding: 7px 0; }
/* The absence-code pick list above the grid. */
.code-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 6px; margin-bottom: 12px; }
.code-pick { display: flex; align-items: center; gap: 8px; font-size: 0.9em; padding: 5px 8px; border: 1px solid var(--border); border-radius: 7px; }
.col-hours { min-width: 62px; }

/* ---------------- WO-036 item 8: the invoice, sales and statement pages ----
   The A4 stage on the invoice detail page: a grey mount, a caption bar and a
   white page of exactly A4 inside it. It is the only place in the system that
   draws paper, so it is named here rather than made a utility. */
.doc-stage { padding: 0; background: #525659; overflow: hidden; display: flex; flex-direction: column; align-items: center; }
.doc-stage-bar { background: #333; width: 100%; color: #fff; padding: 10px; font-size: 0.9em; text-align: center; }
.doc-stage-mount { width: 100%; padding: 20px; box-sizing: border-box; overflow: auto; display: flex; justify-content: center; }
.doc-page { width: 21cm; min-height: 29.7cm; background: #fff; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); padding: 1.5cm; box-sizing: border-box; flex-shrink: 0; }

/* A credit note that was withdrawn: struck through and dimmed, the same
   treatment WO-029 item 5 gave a cancelled leave row. */
.is-void { opacity: .55; }
.is-struck { text-decoration: line-through; }
/* "Refunded", set above a figure in very small capitals. */
.stamp { font-size: .75em; font-weight: 600; text-transform: uppercase; letter-spacing: .04em; }
/* The reason box beside a withdraw button, which must stay on the line. */
.reason-inline { display: inline-block; width: 190px; font-size: .82em; padding: 3px 6px; }

/* ---------------- WO-036 item 8: roster, the setup screens ---------------- */
.setup-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 10px; align-items: end; }
.setup-grid-wide { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; align-items: end; }
.row-inset { background: var(--bg); }
.side-column-wide { width: 400px; flex-shrink: 0; }
.min-w-780 { min-width: 780px; }

/* The last of the sweep: widths a column sets on itself, and three
   properties that had one caller each but are not screen-specific ideas. */
.w-220 { width: 220px; }
.w-45pct { width: 45%; }
.min-w-620 { min-width: 620px; }
.min-w-780 { min-width: 780px; }
.p-26 { padding: 26px; }
.break-all { word-break: break-all; }
.pre-line { white-space: pre-line; }
.lh-17 { line-height: 1.7; }
.stack-col.is-tight { gap: 8px; }

/* ---------------- WO-036 item 8: the invoice line-items editor ----------
   The only table in the system a person types into row by row, so its head
   is a filled bar rather than the usual rule. */
.li-table { width: 100%; border-collapse: collapse; }
.li-table thead tr { background: var(--neutral-bg); text-align: left; }
.li-table th { padding: 8px; }
.li-table th:first-child { border-radius: 6px 0 0 6px; }
.li-table th:last-child { border-radius: 0 6px 6px 0; }
.li-col-amount { width: 130px; }
.li-col-del { width: 40px; }
.li-total { text-align: right; margin-top: 15px; font-size: 1.15em; font-weight: 700; }

/* ---------------- WO-036 item 8: the sales document -------------------- */
.doc-total-row { background: var(--bg); font-weight: 700; }
.doc-heading-line { font-weight: 700; }

/* ---------------- WO-036 item 8: the last of it ---------------- */
/* An ageing bucket on the receivables page: a figure, its label and a count,
   in a box that flags itself when the bucket is the 90-day one. */
.stat-box { flex: 1; min-width: 140px; padding: 12px 16px; border: 1px solid var(--border); border-radius: 6px; }
.stat-box.is-overdue { border-left: 4px solid var(--danger); }
.stat-figure { font-size: 1.1em; font-weight: 700; }

/* A bordered aside inside a card - "confirmed by", a reading's provenance. */
.box-inset { margin-top: 10px; padding: 10px 12px; border: 1px solid var(--border); border-radius: 8px; }

.card-flag-muted { border-left: 4px solid var(--muted); }
.card-danger { border-color: var(--danger); }
.span-all { grid-column: 1 / -1; }
.tile-facts.is-two { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.lh-18 { line-height: 1.8; }
.w-50 { width: 50px; }
.w-110 { width: 110px; }
.w-130 { width: 130px; }

/* The denominator beside a count - "18/24 rooms". It sits inside a `<strong>`
   that the tile styles in small capitals, so it has to opt out of all of it. */
.of-total { display: inline; font-size: inherit; letter-spacing: 0; text-transform: none; color: var(--muted-light); }
.min-w-140 { min-width: 140px; }
.min-w-150 { min-width: 150px; }
.min-w-160 { min-width: 160px; }
.min-w-860 { min-width: 860px; }
.max-w-120 { max-width: 120px; }
.max-w-600 { max-width: 600px; }
.w-80 { width: 80px; }
.is-contents { display: contents; }
.card-flag-navy { border-left: 4px solid var(--navy); }
.card-flag-strong { border-left: 4px solid var(--border-strong); }
/* A card whose heading sits in its own padded strip above a full-bleed table. */
.card-head-pad { padding: 14px 16px 0; }
/* The last row of a form, separated by a dashed rule rather than a solid one:
   it adds a thing rather than finishing the form. */
.dashed-top { margin-top: 16px; padding-top: 16px; border-top: 1px dashed var(--border); }
/* A quiet bordered aside, the plainer cousin of `.box-inset`. */
.box-quiet { border: 1px solid var(--border); border-radius: 8px; padding: 10px 12px; margin: 12px 0; }
/* A pick list bounded so the panel it sits in does not grow without limit.
   Named in NothingButATableScrollsInsideThePageTests' ALLOWED as `.table-scroll`. */
.table-scroll.is-bounded { max-height: 320px; overflow-y: auto; }
/* WO-072 item 7: a table over fifteen rows, marked by static/js/shell.js at a
   desk's width only, is held to the window so its head stays in view while
   the rows move under it. Below 1024px nothing marks it and the page scrolls. */
@media (min-width: 1024px) {
    .table-scroll.is-bounded.is-long { max-height: calc(100vh - 140px); overflow-y: auto; }
}

/* ---------------- WO-036 item 8, the corrections ----------------
   Found by measuring computed styles in a real browser before and after the
   sweep, not by reading the diff. Both faults are the same shape: a class was
   picked because its name fitted, and it brought declarations the inline style
   it replaced never had.

   1. `.lines-table` is the *editable line-item* table from the sales editor -
      it styles `th` and `td` (`padding: 6px`, a rule under every row,
      `vertical-align: top`). Three read-only summary tables were given it for
      its two harmless declarations, and `.lines-table td` (a class plus an
      element) then outranked the `.fig-row` / `.td-ruled` classes on the cells
      themselves - which had been written to match the old inline styles
      exactly. The cells lost their padding and alignment and every row grew a
      rule it never had. `.table-plain` is the two declarations without the
      side effects.

   2. `rem` is absolute and `em` is relative to the parent. `fs-90` is `0.9em`,
      and it replaced `font-size: 0.9rem` on a table already inside a smaller
      context - 14.4px became 13.5px, and every cell under it inherited the
      difference. Sizes that were written in `rem` keep `rem`. */
.table-plain { width: 100%; border-collapse: collapse; }
.fs-74r { font-size: 0.74rem; }
.fs-90r { font-size: 0.9rem; }
.fs-105r { font-size: 1.05rem; }
.fs-110r { font-size: 1.1rem; }
/* Exact sizes the sweep rounded to a neighbour. `.fs-92` and `.fs-80` had no
   utility so it reached for `.fs-90` and `.fs-85`; `.rule-tight` and
   `.note-loose` are the two spacings `.rule` and `.note` do not carry. */
.fs-80 { font-size: 0.8em; }
.fs-86 { font-size: 0.86em; }
.fs-92 { font-size: 0.92em; }
.rule-tight { border: none; border-top: 1px solid var(--border); margin: 8px 0; }
.note-loose { color: var(--muted); font-size: .82em; margin-top: 6px; }
/* `.bullet-list` is payroll's, at 0.9em with a 1.7 line-height. The Inbox's
   detail lists were .86em with no line-height of their own, and they are the
   tallest thing in a table that sizes its columns from content - so the
   difference moved every column on the page. Ties on specificity with
   `.bullet-list` and is declared after it, so it wins on what it sets. */
.bullet-list.fs-86 { font-size: .86em; line-height: inherit; }
/* `.field-label` is a small-caps caption for a figure, and inside a
   `.form-group` it loses to `.form-group label` (a class plus an element) on
   every property both set. This wins back the four the inline style had. */
.form-group label.field-label { color: var(--muted); font-size: 0.74rem; font-weight: 400; margin-bottom: 3px; }
/* `.btn-block` set only the width, so a link styled as a full-width button
   kept `display: inline-flex` from `.btn` and lost its centring. */
.btn-block { display: block; text-align: center; box-sizing: border-box; }

/* ---------------- WO-036 item 8, the second round of corrections ----------
   Both faults below were found the same way as the first round - by measuring
   computed styles in a browser before and after - and both are systemic
   rather than one-off, which is why they get rules instead of edits.

   1. THE SIDE COLUMN WAS SIX WIDTHS, NOT ONE. `.side-column` is 330px, and
      the sweep pointed every detail-page sidebar at it. Only one of them was
      actually 330: the others were 340, 350, 360 and 380, and each lost the
      difference to the `flex: 1` main column beside it - which then reflowed
      every table, grid and field inside it. That is one wrong class producing
      a hundred width diffs on a page. A shared name is right for a shared
      measurement and wrong for six different ones.

   2. `table.data-table` OUTRANKS EVERY UTILITY. `table.data-table td` sets
      `font-size: 0.92em` and `th` sets `text-align: left`, both at a class
      plus two elements - so a single-class utility on a cell can never win,
      whatever the source order. The inline styles they replaced always won,
      because inline beats every selector. app.css already knew this: the
      comment above `.num` says so and ships `table.data-table th.num` for
      exactly this reason. The sweep reached for `.ta-right` (`.num`'s sibling)
      and for `.fs-90` and `.data-muted`, and walked into the documented trap.
      These are the same fix, written for the three utilities that hit it. */
.side-column-340 { width: 340px; flex-shrink: 0; }
.side-column-350 { width: 350px; flex-shrink: 0; }
.side-column-360 { width: 360px; flex-shrink: 0; }
.side-column-380 { width: 380px; flex-shrink: 0; }
table.data-table td.fs-90,
table.data-table td.muted.fs-90 { font-size: 0.9em; }
table.data-table td.data-muted { font-size: 0.88em; }
table.data-table th.ta-right,
table.data-table td.ta-right { text-align: right; }
/* `select.form-control` reserves 30px on the right for its arrow, at a class
   plus an element, so the small variants lost that side of their padding. */
.form-control.form-control-xs { padding-right: 6px; }
/* `.ml-0` was written into a template and never existed in the stylesheet, so
   the `.chip-xs` margin it was there to cancel applied unopposed. */
.ml-0 { margin-left: 0; }
.row-9 { display: flex; gap: 9px; flex-wrap: wrap; }
.fs-82 { font-size: 0.82em; }
/* Named for its pixels, not `.mt-3`: that one is 15px, from the older scale. */
.mt-3px { margin-top: 3px; }
/* The same two traps, written once for every utility that meets them rather
   than one utility at a time: a size or alignment utility on a `.data-table`
   cell, and a weight or layout utility on a label inside a `.form-group`.
   Both host rules carry a class plus an element, so a bare utility never wins
   - which the inline styles they replaced always did. */
table.data-table td.fs-72 { font-size: 0.72em; }
table.data-table td.fs-80 { font-size: 0.8em; }
table.data-table td.fs-82 { font-size: 0.82em; }
table.data-table td.fs-85 { font-size: 0.85em; }
table.data-table td.fs-86 { font-size: 0.86em; }
table.data-table td.fs-88 { font-size: 0.88em; }
table.data-table td.fs-92 { font-size: 0.92em; }
.form-group label.is-normal-weight { font-weight: 400; }
.form-group label.is-flex { display: flex; }
/* `.form-group label` is a class plus an element and beats a single-class
   utility - one of the two app.css names WO-036 item 8 called out as biting
   hardest. A size utility on one of those labels needs the same reach (WO-044). */
.form-group label.fs-85r { font-size: 0.85rem; }

/* ---------------------------------------------------------------------------
   night_audit: the intake's own screens. WO-044.

   `night_audit` was in no census module and behind no inline-style gate, so
   WO-036 item 8's sweep never reached it and its seven screens carried 170
   inline `style=` attributes between them. What is here is what the shared
   vocabulary genuinely could not say; everything else on those pages now uses
   the utilities every other module uses, which is the point - "no two screens
   agree how far a note sits from the thing it explains" was the finding, not
   the styling.
   --------------------------------------------------------------------------- */

/* A card that is itself the alarm, rather than a card with a flag on it. */
.na-danger-card { background: var(--danger-bg); padding: 16px 18px; }
.na-warning-card { background: var(--warning-bg, #fff6e0); padding: 16px 18px; }

/* The night's report sections: a stack of `<details>`, each a card whose body
   is inset from its own summary. */
.na-section-body { border-top: none; padding-top: 0; }
.na-section-table { width: 100%; font-size: 0.9em; border-collapse: collapse; }
.na-section-table td { padding: 6px 0; }
.na-section-table td:last-child { text-align: right; }
.na-section-table td:first-child { color: var(--muted); }
.na-section-table td.is-top { vertical-align: top; }

/* The figure a night leads with - one big number under a small label. */
.na-headline { font-weight: 700; font-size: 1.28em; margin-top: 4px; }
.na-label { color: var(--muted); font-size: 0.82em; text-transform: uppercase; letter-spacing: 0.03em; }

/* The settings screen's mapping rows: a wide grid of small paired inputs. */
.na-grid-240 { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 6px; }
.na-grid-210 { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 14px; }
.na-narrow-input { width: 84px; padding: 5px 8px; }

.max-w-720 { max-width: 720px; }
.fs-85r { font-size: 0.85rem; }
.fs-78 { font-size: 0.78em; }
.fs-95 { font-size: 0.95em; }
.ta-left { text-align: left; }
.min-w-200 { min-width: 200px; }
.min-w-380 { min-width: 380px; }
.w-100 { width: 100%; }

/* The night detail: a headline row of figures, each a bordered tile. */
.na-figures { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 14px; }
.na-figure { border: 1px solid var(--border); border-radius: 8px; padding: 12px 14px; }
.na-figure-missing { color: var(--muted); font-weight: 600; font-size: 0.72em; }
.na-spread { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.na-pick { display: flex; gap: 8px; align-items: flex-start; font-size: 0.9em; }
.na-summary { cursor: pointer; font-weight: 600; }
.na-heading-row { display: flex; align-items: center; gap: 10px; }
.na-form-row { display: flex; gap: 10px; flex-wrap: wrap; align-items: flex-end; }
.na-note { color: var(--muted); font-size: 0.87em; margin: 4px 0 8px; }
.na-note.is-loose { margin: 6px 0; }

/* A settings card that is itself the alarm - this hotel cannot be routed to. */
.na-card-flag-danger { border-left: 4px solid var(--danger); }

/* A note the colour of a caution, inside a card rather than beside it. */
.na-warning-note {
    padding: 10px 14px; border-radius: 8px;
    background: var(--warning-bg, #fff6e0); font-size: 0.88em;
}

/* A block set off from the one above by a rule, inside a card. */
.na-rule-above { margin-top: 20px; border-top: 1px solid var(--border); padding-top: 16px; }
.na-rule-above.is-tight { margin-top: 14px; padding-top: 12px; }

/* A checkbox and its explanation, side by side and both clickable. */
.na-tickbox { display: flex; gap: 8px; align-items: flex-start; cursor: pointer; }

/* An inline form in a header, sitting beside the buttons. */
.na-inline-form { display: inline-flex; align-items: center; margin-right: 8px; gap: 6px; }

/* The balance table needs room for four columns of prose on a phone. */
.min-w-720 { min-width: 720px; }
.va-top { vertical-align: top; }

/* A label sitting on the same line as the control it names. */
.na-inline-label { align-self: center; }

/* A pre-formatted parser complaint, kept as the parser wrote it. */
.na-parser-error {
    background: var(--danger-bg); color: var(--danger); padding: 10px 12px;
    border-radius: 8px; font-size: 0.88em; white-space: pre-line;
}

/* ---------------------------------------------------------------------------
   purchasing: and inventory:  — WO-048

   The two apps carried 391 inline `style=` attributes between them and no gate
   refused one, because the sweep in WO-036 item 8 covered the eight modules it
   listed and these were not among them. The census had never read them either,
   so nothing measured the number and nothing held it down.

   What follows is the vocabulary those 391 turned out to be: mostly the same
   six or seven ideas already in this file under other names, plus the widths a
   table sets on itself so `.table-scroll` knows when to scroll.
   --------------------------------------------------------------------------- */

/* Flex rows. `.action-group` and `.filter-form` above are the two shapes most
   of these were spelling out by hand; these are the pieces for the rest. */
.wrap { flex-wrap: wrap; }
.gap-6 { gap: 6px; }
.gap-8 { gap: 8px; }
.gap-10 { gap: 10px; }
.gap-12 { gap: 12px; }
.gap-14 { gap: 14px; }
.gap-16 { gap: 16px; }
.flex-shrink-0 { flex-shrink: 0; }
.is-grid { display: grid; }
.is-inline-block { display: inline-block; }
.is-block { display: block; }

/* Type, continuing the `.fs-` names above. */
.fs-84 { font-size: 0.84em; }
.fs-87 { font-size: 0.87em; }
.fs-105 { font-size: 1.05em; }
.fs-130 { font-size: 1.3em; }
.fs-160 { font-size: 1.6em; }
.fw-normal { font-weight: normal; }

/* Spacing, continuing the pixel names. */
.mr-4 { margin-right: 4px; }
.mt-neg-8 { margin-top: -8px; }
.pl-20 { padding-left: 20px; }
.pt-10 { padding-top: 10px; }
.pt-12 { padding-top: 12px; }
.p-18 { padding: 18px; }
.p-34 { padding: 34px; }
.p-3-10 { padding: 3px 10px; }
.p-4-12 { padding: 4px 12px; }
.p-5-8 { padding: 5px 8px; }
.p-7-0 { padding: 7px 0; }
.p-10-0 { padding: 10px 0; }
.p-12-14 { padding: 12px 14px; }
.m-4-0-0 { margin: 4px 0 0; }
.m-4-0-8 { margin: 4px 0 8px; }
.m-6-0-0 { margin: 6px 0 0; }
.m-8-0-0 { margin: 8px 0 0; }
.m-10-0-0 { margin: 10px 0 0; }

/* A card with a coloured left edge, which is how every screen in this repo
   says *this one is different* - and which four of them were spelling out
   inline, one colour each. */
.flag-info { border-left: 4px solid var(--info); }
.flag-warning { border-left: 4px solid var(--warning); }
.flag-danger { border-left: 4px solid var(--danger); }
.flag-gold { border-left: 4px solid var(--gold); }
.border-top-1 { border-top: 1px solid var(--border); }

/* Widths a table sets on itself, and the few a cell does. */
.min-w-130 { min-width: 130px; }
.min-w-165 { min-width: 165px; }
.min-w-240 { min-width: 240px; }
.min-w-680 { min-width: 680px; }
.min-w-700 { min-width: 700px; }
.min-w-760 { min-width: 760px; }
.min-w-780 { min-width: 780px; }
.min-w-800 { min-width: 800px; }
.min-w-820 { min-width: 820px; }
.min-w-900 { min-width: 900px; }
.max-w-260 { max-width: 260px; }
.w-70 { width: 70px; }
.w-100 { width: 100px; }
.w-116 { width: 116px; }
.w-140 { width: 140px; }
.w-320 { width: 320px; }
.w-330 { width: 330px; }
.w-340 { width: 340px; }
.w-8em { width: 8em; }

/* A grid that fits as many equal columns as the width allows. Two sizes,
   because the tiles on these screens come in two. */
.grid-fit-180 { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }
.grid-fit-200 { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }

/* Two flex bases the bill queue's filter row needs and nothing else does. */
.flex-260 { flex: 1 1 260px; }
.flex-320 { flex: 0 1 320px; }
.is-start { align-items: flex-start; }

/* A note set into a card: the same shade as the page behind it, so it reads
   as an aside rather than as another card. */
.inset-note {
    padding: 12px 14px; background: var(--bg); border-radius: 8px;
    font-size: 0.88em; color: var(--muted);
}

/* A `select.form-control` reserves 30px on its right for the arrow, at a class
   plus an element, so a bare padding utility loses that side - the same trap
   `.form-control-xs` above was written for, and the reason the bill queue's
   two compact selects need the reach (WO-048). */
select.form-control.p-5-8 { padding: 5px 8px; }
/* A size utility on a `.data-table` cell, continuing the block above. */
table.data-table td.fs-87 { font-size: 0.87em; }
table.data-table th.fs-85 { font-size: 0.85em; }
table.data-table th.fs-87 { font-size: 0.87em; }
table.data-table th.fs-88 { font-size: 0.88em; }
/* And a size utility on a `.form-group` label, which is the other host rule
   that carries a class plus an element. `.fs-85r` beside it is rems - a
   different number - so this is the em one the screens were writing inline. */
.form-group label.fs-85 { font-size: 0.85em; }
.form-group label.fs-88 { font-size: 0.88em; }
/* And the third host rule, which is the one that bit hardest here:
   `table.data-table` sets `min-width: 640px` on itself at a class plus an
   element. A table that wants a *narrower* minimum said so inline, where it
   always won; a bare `.min-w-520` loses, and the table silently went back to
   640 - eight pixels wider than it had been, which then reflowed every cell in
   it. One rule per width the two apps actually use (WO-048). */
table.data-table.min-w-520 { min-width: 520px; }
table.data-table.min-w-560 { min-width: 560px; }
table.data-table.min-w-620 { min-width: 620px; }

/* ---------------------------------------------------------------------------
   reservations: and vouchers:  — WO-049

   The last two modules to join the census, and the last to be swept. Their
   screens carried ~200 inline `style=` attributes; the two `*_pdf.html` are
   documents and keep theirs, which is the A1 pattern.

   **The colours below are the ones the templates had**, kept to the byte so
   the sweep changes where a rule lives and nothing else. Several are not this
   theme's tokens - `#7f8c8d`, `#e74c3c`, `#ddd`, `#ccc`, `#fafafa`, `#f9f9f9`,
   `#555` - and that is worth fixing, in a change that says it is changing a
   colour rather than in one that says it is moving a rule.
   --------------------------------------------------------------------------- */

/* More of the vocabulary. */
.is-hidden { display: none; }
.is-between { justify-content: space-between; }
.is-column { flex-direction: column; }
.no-underline { text-decoration: none; }
.fw-bold { font-weight: bold; }
.fs-11 { font-size: 11px; }
.fs-120 { font-size: 1.2em; }
.gap-2 { gap: 2px; }
.gap-4 { gap: 4px; }
.gap-20 { gap: 20px; }
.ml-4 { margin-left: 4px; }
.mb-15 { margin-bottom: 15px; }
.p-5 { padding: 5px; }
.p-10 { padding: 10px; }
.p-15 { padding: 15px; }
.p-20 { padding: 20px; }
.p-25 { padding: 25px; }
.p-3-6 { padding: 3px 6px; }
.p-4-8 { padding: 4px 8px; }
.p-12-24 { padding: 12px 24px; }
.pt-16 { padding-top: 16px; }
.w-150 { width: 150px; }
.w-8pct { width: 8%; }
.w-20pct { width: 20%; }
.w-24pct { width: 24%; }
.max-w-350 { max-width: 350px; }
.border-collapse { border-collapse: collapse; }
.shrink-0 { flex-shrink: 0; }

/* The booking form's two tabs - one guest or a group - as a pill group. */
.seg-tabs {
    display: inline-flex; background: var(--neutral-bg); border-radius: 8px;
    padding: 4px; margin-bottom: 20px; gap: 2px;
}
.seg-tab {
    font-weight: 600; font-size: 0.92em; padding: 7px 18px; border-radius: 6px;
    cursor: pointer; transition: background-color .15s, color .15s;
}

/* A note the booking screens put above a section. */
.rn-notice {
    background: var(--gold-bg); padding: 10px; border-radius: 6px; margin-bottom: 15px;
}
/* One room, one guest, one charge: a card in a list, with the button that
   takes it out again sitting in its corner. */
.rn-row {
    background: var(--bg); padding: 10px; margin-bottom: 10px;
    border: 1px solid var(--border); border-radius: 7px; position: relative;
}
.rn-row-remove {
    position: absolute; right: 10px; top: 10px; background: none; border: none;
    color: var(--danger); cursor: pointer; font-size: 1.1em;
}
/* Drop a passport photograph here. */
.rn-dropzone {
    margin-bottom: 15px; border: 2px dashed #ccc; border-radius: 8px; padding: 25px;
    text-align: center; cursor: pointer; background: #fafafa;
}
.rn-panel {
    background: #f9f9f9; padding: 15px; border: 1px solid #ddd; border-radius: 6px;
}
/* What the booking comes to, at the foot of its own table. */
.rn-total { text-align: right; margin-top: 20px; font-weight: bold; }
.rn-rule { margin: 20px 0; border-top: 1px solid #ddd; }
.rn-rule-soft { margin: 18px 0; border: none; border-top: 1px solid var(--border); }
.rn-muted { color: #7f8c8d; }
.rn-alert { color: #e74c3c; }
.rn-ink { color: #555; }

/* The voucher screen: the form on the left, the voucher itself on the right,
   A4 and to scale on the grey a document reader uses. */
.vo-form-column { flex: 1; max-width: 350px; }
.vo-preview {
    flex: 2; padding: 0; background: #525659; overflow: hidden;
    display: flex; flex-direction: column; align-items: center;
}
.vo-preview-bar {
    background: #333; width: 100%; color: white; padding: 10px;
    font-size: 0.9em; text-align: center;
}
.vo-preview-scroll {
    width: 100%; padding: 20px; box-sizing: border-box; overflow: auto;
    display: flex; justify-content: center;
}
.vo-sheet {
    width: 21cm; min-height: 29.7cm; background: white;
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); padding: 1.5cm;
    box-sizing: border-box; flex-shrink: 0;
}
.mt-24 { margin-top: 24px; }
.fs-110 { font-size: 1.1em; }
.p-14-4 { padding: 14px 4px; }
.is-inline-flex { display: inline-flex; }
.bg-neutral { background: var(--neutral-bg); }
.text-gold-ink { color: var(--gold-ink); }

/* ---------------------------------------------------------------------------
   housekeeping:  — WO-055

   Rooms, the front desk board and the housekeeper's phone. The board and the
   phone are the two screens used standing up, so their targets are 44px and
   nothing on them scrolls sideways.
   --------------------------------------------------------------------------- */

/* A form inside a table cell: its control and buttons on one line, wrapping on a phone. */
.hk-inline-form { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.hk-inline-form .form-control { width: auto; min-width: 0; }
.hk-number-input { max-width: 110px; }

/* The board's search box. */
.hk-find { display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-end; }
.hk-find .form-group { margin-bottom: 0; }
.hk-search { max-width: 140px; }

/* The sheet a tap opens: a panel over the foot of the board, above the phone's tab bar. */
.hk-sheet {
    position: fixed; left: 12px; right: 12px; bottom: 74px; z-index: 60;
    max-width: 440px; margin: 0 auto; padding: 16px;
    background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
    box-shadow: var(--shadow-lg);
}
.hk-sheet-head { display: flex; justify-content: space-between; align-items: center; gap: 8px; }
.hk-sheet-actions { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
.hk-mark { min-height: 48px; }
@media (min-width: 1024px) {
    .hk-sheet { bottom: 24px; }
}

/* Floor assignments: a person on a floor with the button that takes them off. */
.hk-person { display: inline-flex; align-items: center; gap: 6px; margin: 2px 10px 2px 0; }
.hk-floor-ticks { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 4px 12px; }

/* My floors: one card a room, the whole width, the number large enough to read at arm's length. */
.hk-mine { display: grid; grid-template-columns: minmax(0, 1fr); gap: 10px; }
.hk-room { padding: 0; overflow: hidden; border-left: 6px solid var(--border); }
.hk-room-head {
    display: grid; grid-template-columns: auto minmax(0, 1fr); grid-template-areas: "number status" "number floor";
    align-items: center; column-gap: 14px; min-height: 64px; padding: 10px 14px; cursor: pointer; list-style: none;
}
.hk-room-head::-webkit-details-marker { display: none; }
.hk-room-number { grid-area: number; min-width: 3.4em; font-size: 1.6rem; font-weight: 800; font-variant-numeric: tabular-nums; }
.hk-room-status { grid-area: status; font-weight: 700; }
.hk-room-floor { grid-area: floor; color: var(--muted); font-size: .85em; }
.hk-clean-form { padding: 0 14px 14px; }
.hk-big { width: 100%; min-height: 52px; font-size: 1.05em; }
/* The card's edge is its status's swatch (WO-061 item 11). */
.hk-room[class*="swatch-"] { border-left-color: var(--sw-edge); }
.hk-room[class*="swatch-"] .hk-room-status { color: var(--sw-ink); }
@media (min-width: 900px) {
    .hk-mine { grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); }
}

/* Inspection: a card a room, the photo the housekeeper took filling its width. */
.hk-inspect-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 1fr)); gap: 12px; }
.hk-inspect { display: flex; flex-direction: column; gap: 8px; }
.hk-inspect-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.hk-photo-link { display: block; }
.hk-photo { display: block; width: 100%; max-height: 260px; object-fit: cover; border-radius: var(--radius-sm); background: var(--surface-2); }
.hk-inspect-note { margin: 0; font-style: italic; }
.hk-inspect-head .hk-room-number { color: var(--navy); text-decoration: none; }
.hk-inspect-form { display: grid; gap: 8px; margin-top: auto; }
.hk-inspect-form .form-group { margin-bottom: 0; }
.hk-thumb { display: block; width: 64px; height: 48px; object-fit: cover; border-radius: 6px; }

/* ---------------------------------------------------------------------------
   payroll: staff meals — WO-055 item 7. A name, the count, one big tap.
   --------------------------------------------------------------------------- */
.meal-people { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0; }
/* A person, since WO-061 item 12: the name, the count, one big tap - one
   44 px line since WO-064 item 3, the department beside the name and cut
   before it is, the rest under the small − control. */
.meal-tile { display: flex; align-items: center; gap: 8px; min-height: 44px; padding: 3px 0; border-top: 1px solid var(--border); transition: background-color .3s; }
.meal-tile:first-child { border-top: 0; }
.meal-tile.is-saved { background: var(--gold-bg); }
.meal-tile-name { flex: 1 1 auto; min-width: 0; display: flex; align-items: baseline; gap: 8px; white-space: nowrap; overflow: hidden; }
.meal-tile-name > strong { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.meal-tile-dept { flex: 0 100 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--muted); font-size: .84em; }
.meal-count { min-width: 44px; height: 44px; display: inline-flex; align-items: center; justify-content: center; border-radius: 999px; background: var(--surface-2); font-weight: 800; font-variant-numeric: tabular-nums; }
.meal-count.has-meals { background: var(--gold-bg); color: var(--gold-ink); }
.meal-tap { flex: none; min-height: 44px; min-width: 88px; }
.meal-count { flex: none; }
.meal-less { position: relative; flex: none; }
.meal-less.is-empty { visibility: hidden; } /* keeps its place, so the taps line up */
.meal-less > summary { list-style: none; display: inline-flex; align-items: center; justify-content: center; width: 36px; min-height: 44px; border: 1px solid var(--border); border-radius: var(--radius-sm); color: var(--muted); font-size: 1.2em; font-weight: 800; cursor: pointer; }
.meal-less > summary::-webkit-details-marker { display: none; }
.meal-less[open] > summary { border-color: var(--navy); color: var(--navy); }
.meal-less-menu { position: absolute; right: 0; top: calc(100% + 6px); z-index: 20; display: flex; flex-wrap: wrap; align-items: center; gap: 6px; width: min(320px, calc(100vw - 48px)); padding: 8px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-sm); box-shadow: var(--shadow-md); }
.meal-less-menu > [data-undo-slot]:empty { display: none; }
.meal-withdraw-row { display: flex; flex: 1 1 100%; gap: 6px; }
.meal-withdraw-row[hidden] { display: none; }
.meal-withdraw-row .form-control { flex: 1 1 160px; min-width: 0; }
/* Ate today shows eight; the rest fold behind Show all (WO-064 item 3). */
.meal-rest > summary { list-style: none; display: flex; align-items: center; min-height: 44px; border-top: 1px solid var(--border); color: var(--navy); font-weight: 700; font-size: .92em; cursor: pointer; }
.meal-rest > summary::-webkit-details-marker { display: none; }
.meal-rest[open] .meal-rest-closed, .meal-rest:not([open]) .meal-rest-open { display: none; }
@media (max-width: 767.98px) {
    /* On a phone the department goes under the name, still inside the 44 px. */
    .meal-tile-name { flex-direction: column; align-items: stretch; gap: 0; line-height: 1.25; }
    .meal-tap { min-width: 76px; }
}
/* The search, the chips and the footer that keeps the day's meals in view (WO-061 item 12). */
.meal-find { padding: 12px 16px; }
.meal-find label { display: block; font-weight: 700; margin-bottom: 4px; }
.meal-search { font-size: 1.1em; min-height: 48px; margin-bottom: 6px; }
.meal-heading { display: flex; align-items: baseline; gap: 8px; }
.meal-heading-count { color: var(--muted); font-weight: 600; font-size: .9em; }
.meal-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 4px; }
.meal-chip { min-height: 40px; padding: 4px 14px; border-radius: 999px; border: 1px solid var(--border-strong); background: var(--surface); color: var(--ink); font: inherit; font-size: .88em; font-weight: 600; cursor: pointer; }
.meal-chip[aria-pressed="true"] { background: var(--navy); border-color: var(--navy); color: #fff; }
.meal-footer { position: sticky; bottom: 8px; z-index: 5; display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; margin-top: 14px; padding: 12px 16px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); box-shadow: var(--shadow-md); font-size: 1.05em; }
.meal-footer strong { font-size: 1.2em; font-variant-numeric: tabular-nums; }
.meal-footer .note-danger { flex-basis: 100%; margin: 0; }
.meal-footer .note-danger:empty { display: none; }
@media (max-width: 767.98px) {
    body.has-tabbar .meal-footer { bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom) + 8px); }
}
/* A day or month picker with its button, in a header's action group: one row that shrinks, never two controls stacked on each other. */
.date-pick { display: flex; gap: 6px; min-width: 0; }
.date-pick .form-control { flex: 1 1 auto; min-width: 0; }
@media (max-width: 768px) {
    .page-header .date-pick { grid-column: 1 / -1; }
    /* Outranks the header's own `form .btn { width: 100% }`, which is written to fill a cell. */
    .page-header .action-group form.date-pick .btn.btn-secondary { width: auto; flex: 0 0 auto; }
}

/* ---------------------------------------------------------------------------
   cashbook: the front desk sheet — WO-055 item 8. The owner's paper sheet:
   the new row sits under the last one and Enter saves it.
   --------------------------------------------------------------------------- */
.desk-sheet .desk-new-row td { background: var(--gold-bg); vertical-align: middle; }
.desk-sheet .desk-new-row .form-control { min-width: 120px; }
.desk-sheet .desk-amount { max-width: 110px; text-align: right; }
.desk-receipt { max-width: 180px; font-size: .85em; }
.desk-take-back > summary { list-style: none; cursor: pointer; }
.desk-take-back > summary::-webkit-details-marker { display: none; }
.desk-take-back[open] form { margin-top: 6px; min-width: 220px; }

/* ---------------------------------------------------------------------------
   notifications: Telegram groups — WO-056
   --------------------------------------------------------------------------- */

/* Unlink with a reason, inside the group's row: one line, wrapping on a phone. */
.tg-unlink-form { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.tg-unlink-form .form-control { width: auto; min-width: 0; max-width: 180px; }

/* My floors, WO-057: the rooms that need her, then the finished ones folded under a heading. */
.hk-mine-heading { display: flex; align-items: baseline; gap: 8px; margin: 4px 0 10px; }
.hk-mine-count { color: var(--muted); font-weight: 600; }
.hk-done { margin-top: 18px; }
.hk-done > summary { display: flex; align-items: center; gap: 8px; min-height: 44px; cursor: pointer; font-weight: 700; list-style: none; }
.hk-done > summary::-webkit-details-marker { display: none; }
.hk-done > summary::before { content: "\25B8"; color: var(--muted); }
.hk-done[open] > summary::before { content: "\25BE"; }
.hk-done > .hk-mine { margin-top: 10px; }
/* The front desk's note on a card, under the number: a third row across the card. */
.hk-room-head.has-note { grid-template-areas: "number status" "number floor" "note note"; }
.hk-desk-note { display: block; grid-area: note; margin: 6px 0 0; padding: 6px 10px; border-radius: var(--radius-sm); background: var(--warning-bg); color: var(--ink); font-size: .92em; }

/* Setup, related companies (WO-033): a position set in its own row, wrapping on a phone. */
.position-form { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.position-form .form-control { width: auto; min-width: 0; max-width: 170px; }

/* ---------------------------------------------------------------------------
   workspace: tasks and meetings — WO-059

   A task you can open and a meeting you can run. A person is a dot of two
   initials in a tint of their own, from a fixed list by pk, so they are the
   same colour on every screen; the tints are §4 tokens and nothing else.
   --------------------------------------------------------------------------- */

/* A label a screen reader reads and nobody else needs: the box says what it is. */
.sr-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* A person: two initials on a dot. `?` on the neutral dot is nobody yet. */
.person-dot {
    display: inline-grid; place-items: center; flex: 0 0 auto;
    width: 30px; height: 30px; border-radius: 50%;
    font-size: .72rem; font-weight: 800; letter-spacing: .02em; color: #fff;
    background: var(--navy);
}
.person-dot.tint-0 { background: var(--navy); }
.person-dot.tint-1 { background: var(--info); }
.person-dot.tint-2 { background: var(--success); }
.person-dot.tint-3 { background: var(--gold-ink); }
.person-dot.tint-4 { background: var(--warning); }
.person-dot.tint-5 { background: var(--navy-light); }
.person-dot.tint-none { background: var(--neutral-bg); color: var(--muted); border: 1px dashed var(--border-strong); }
.task-person { display: inline-flex; align-items: center; gap: 8px; min-width: 0; }

/* The task page: the detail, then the thread in the order it happened. */
.task-detail { white-space: normal; overflow-wrap: anywhere; }
.task-thread { list-style: none; margin: 0 0 16px; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.thread-line { display: flex; gap: 10px; align-items: flex-start; min-width: 0; }
.thread-line.is-change { align-items: baseline; justify-content: space-between; padding: 2px 0 2px 40px; color: var(--muted); font-size: .88em; }
.thread-change { overflow-wrap: anywhere; }
.thread-body { flex: 1; min-width: 0; background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 8px 12px; }
.thread-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.thread-when { color: var(--muted); font-size: .8em; white-space: nowrap; }
.thread-text { margin: 4px 0 0; overflow-wrap: anywhere; }
.thread-photo { display: block; margin-top: 8px; max-width: 100%; width: 320px; border-radius: var(--radius-sm); }
.thread-form { border-top: 1px solid var(--border); padding-top: 14px; }
.thread-form-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px; margin-top: 8px; }
.thread-photo-pick { display: inline-flex; align-items: center; gap: 8px; min-width: 0; font-size: .88em; }
.thread-file { min-width: 0; max-width: 220px; font-size: .9em; }
/* Change a task: folded under the facts until somebody means to. */
.task-change > summary { display: flex; align-items: center; gap: 8px; min-height: 40px; cursor: pointer; font-weight: 700; color: var(--navy); list-style: none; }
.task-change > summary::-webkit-details-marker { display: none; }
.task-change > summary::before { content: "\25B8"; color: var(--muted); }
.task-change[open] > summary::before { content: "\25BE"; }
.task-change > form { margin-top: 8px; }
@media (max-width: 767.98px) {
    .thread-line.is-change { padding-left: 0; flex-wrap: wrap; }
    .thread-form-row .btn { min-height: 44px; }
}

/* The list (WO-059 item 4). Mine or Everybody, then a strip of people: a dot
   and an open count each, `?` first for work nobody has. Wraps, never scrolls. */
.task-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 16px; margin-bottom: 16px; }
.view-toggle { display: inline-flex; gap: 2px; padding: 3px; border-radius: var(--radius-sm); background: var(--neutral-bg); }
.view-toggle a { display: inline-flex; align-items: center; min-height: 34px; padding: 0 14px; border-radius: 6px; font-weight: 700; font-size: .88em; color: var(--muted); text-decoration: none; }
.view-toggle a.is-active { background: var(--surface); color: var(--navy); box-shadow: var(--shadow-sm); }
/* When the header stretches it on a phone, the halves share the width. */
.view-toggle a { flex: 1 1 0; justify-content: center; }
.people-strip { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 6px; min-width: 0; }
.person-chip { display: inline-flex; align-items: center; gap: 6px; padding: 3px 10px 3px 3px; border-radius: 999px; border: 1px solid var(--border); background: var(--surface); color: var(--ink); text-decoration: none; }
.person-chip:hover { border-color: var(--border-strong); }
.person-chip.is-active { border-color: var(--gold); background: var(--gold-bg); }
.person-count { font-weight: 700; font-size: .86em; font-variant-numeric: tabular-nums; }

/* One line to add a task; whose and when appear once it is in use. */
.quick-add { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 10px 12px; margin-bottom: 16px; }
.quick-add-title { flex: 1 1 240px; min-width: 0; border-style: dashed; }
.quick-add-more { display: none; flex-wrap: wrap; align-items: center; gap: 8px; }
.quick-add:focus-within .quick-add-more,
.quick-add:has(.quick-add-title:not(:placeholder-shown)) .quick-add-more { display: flex; }
.quick-add-more .form-control { width: auto; min-width: 0; max-width: 220px; }

/* A group: its heading and count, then one row a task. */
.task-group { padding: 14px 16px 6px; margin-bottom: 14px; }
.task-group .section-head { margin-bottom: 4px; }
.section-head h2.is-late { color: var(--danger); }
.task-list { list-style: none; margin: 0; padding: 0; }
.task-row { display: flex; align-items: center; gap: 12px; padding: 10px 0; border-top: 1px solid var(--border); min-width: 0; }
.task-list > .task-row:first-child { border-top: 0; }
.task-check-form { margin: 0; flex: 0 0 auto; }
.task-check {
    display: inline-grid; place-items: center; flex: 0 0 auto;
    width: 26px; height: 26px; padding: 0; border-radius: 50%;
    border: 2px solid var(--border-strong); background: var(--surface); color: transparent; cursor: pointer;
}
button.task-check:hover, button.task-check:focus-visible { border-color: var(--success); color: var(--success); outline: none; }
.task-check.is-done { border-color: var(--success); background: var(--success); color: #fff; }
.task-check.is-idle { border-style: dashed; cursor: default; }
.task-main { flex: 1; min-width: 0; }
.task-title { color: var(--ink); font-weight: 600; text-decoration: none; overflow-wrap: anywhere; }
.task-title:hover { color: var(--navy); text-decoration: underline; }
.task-row.is-closed .task-title { color: var(--muted); }
.task-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; margin-top: 2px; color: var(--muted); font-size: .8em; }
.task-meta:empty { display: none; }
.task-meta .chip-xs { margin-left: 0; }
/* A badge in a task's meta can carry words - "Waiting on the second contractor
   to reply" - so it wraps inside the row instead of widening the page. */
.task-meta .badge { white-space: normal; max-width: 100%; overflow-wrap: anywhere; text-align: left; }
.due-chip { flex: 0 0 auto; padding: 2px 9px; border-radius: 999px; font-size: .78em; font-weight: 700; white-space: nowrap; background: var(--neutral-bg); color: var(--muted); }
.due-chip.is-late { background: var(--danger-bg); color: var(--danger); }
.due-chip.is-today { background: var(--warning-bg); color: var(--warning); }
.due-chip.is-soon { background: var(--info-bg); color: var(--info); }
.task-owner { display: inline-flex; align-items: center; gap: 8px; flex: 0 0 auto; max-width: 180px; min-width: 0; }
.task-owner-name { font-size: .86em; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* What was finished this week, folded at the foot. */
.done-fold { padding: 12px 16px; margin-bottom: 10px; }
.done-fold > summary { display: flex; align-items: center; gap: 8px; min-height: 36px; cursor: pointer; font-weight: 700; color: var(--navy); list-style: none; }
.done-fold > summary::-webkit-details-marker { display: none; }
.done-fold[open] > summary { margin-bottom: 4px; }

@media (max-width: 767.98px) {
    /* The check on the left of both lines, the title beside it, the date under
       the title and the dot on the right: a grid, so nothing wraps onto a line
       of its own. */
    .task-row {
        display: grid; grid-template-columns: 32px minmax(0, 1fr) auto;
        grid-template-areas: "check main owner" "check due owner";
        column-gap: 10px; row-gap: 4px; align-items: start;
    }
    .task-row > .task-check-form, .task-row > .task-check { grid-area: check; }
    .task-row > .task-main { grid-area: main; }
    .task-row > .due-chip { grid-area: due; justify-self: start; }
    .task-row > .task-owner { grid-area: owner; }
    .task-owner-name { display: none; }
    .task-check { width: 32px; height: 32px; }
    .view-toggle a { min-height: 40px; }
    .quick-add-more .form-control { max-width: none; flex: 1 1 140px; }
}

/* The board view (WO-059 item 5): three columns of cards, moved by a button.
   `minmax(0, 1fr)` so a long title wraps instead of widening its column. */
.task-columns { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; align-items: start; }
.task-column { background: var(--neutral-bg); border-radius: var(--radius); padding: 12px; min-width: 0; }
.task-column .section-head { margin-bottom: 8px; padding: 0 4px; }
.task-cards { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.task-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 10px 12px; box-shadow: var(--shadow-sm); min-width: 0; }
.task-card.is-closed { box-shadow: none; }
.task-card.is-closed .task-title { color: var(--muted); }
.task-card-foot { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 8px; }
.task-card-move { margin: 0 0 0 auto; }
.task-card-empty { color: var(--muted); font-size: .86em; padding: 6px 4px; }
@media (max-width: 767.98px) {
    .task-columns { grid-template-columns: minmax(0, 1fr); }
    .task-card-move .btn { min-height: 40px; }
}

/* A task in a project (WO-059 item 7): the project's row lists its tasks and
   fills the shared progress track by a custom property, the one inline value
   the house allows (`core/inline_styles.py`). */
.project-progress { min-width: 130px; }
.project-progress .progress-track { margin-top: 6px; }
.project-progress .progress-fill { width: var(--done, 0%); }
.project-tasks { list-style: none; margin: 8px 0 0; padding: 0; display: flex; flex-direction: column; gap: 4px; font-weight: 400; font-size: .9em; }
.project-tasks li { display: flex; align-items: center; gap: 8px; min-width: 0; }
.project-tasks li > a { min-width: 0; overflow-wrap: anywhere; color: var(--ink); font-weight: 500; text-decoration: none; }
.project-tasks li > a:hover { text-decoration: underline; }
.project-tasks li.is-closed > a { color: var(--muted); }
.project-tasks .task-check { width: 16px; height: 16px; border-width: 1.5px; }
.project-tasks .person-dot { width: 22px; height: 22px; font-size: .62rem; margin-left: auto; }

/* Meetings (WO-059 item 9): Upcoming and Past as rows with the date as a
   block, a series' people as dots, and who is expected on a meeting's page. */
.meeting-section { margin-bottom: 14px; }
.meeting-list { list-style: none; margin: 0; padding: 0; }
.meeting-row { display: flex; align-items: center; gap: 14px; padding: 10px 0; border-top: 1px solid var(--border); min-width: 0; }
.meeting-list > .meeting-row:first-child { border-top: 0; }
.meeting-when { display: flex; flex-direction: column; align-items: center; flex: 0 0 56px; padding: 6px 0; border-radius: var(--radius-sm); background: var(--surface-2); border: 1px solid var(--border); line-height: 1.15; }
.meeting-day { font-size: .68rem; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.meeting-date { font-weight: 800; color: var(--navy); font-size: .9em; white-space: nowrap; }
.meeting-time { font-size: .76em; color: var(--muted); font-variant-numeric: tabular-nums; }
.meeting-progress { flex: 0 0 150px; font-size: .86em; }
.meeting-progress .progress-track { margin-top: 5px; }
.meeting-progress .progress-fill { width: var(--done, 0%); }
.people-row { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px; }
.people-row .person-dot { width: 24px; height: 24px; font-size: .62rem; }
.people-picks { border: 0; margin: 0 0 16px; padding: 0; display: flex; flex-wrap: wrap; gap: 6px; min-width: 0; }
.people-picks legend { font-weight: 600; font-size: .92em; margin-bottom: 6px; padding: 0; }
.person-pick { display: inline-flex; align-items: center; gap: 6px; padding: 3px 10px 3px 4px; border: 1px solid var(--border); border-radius: 999px; cursor: pointer; font-size: .88em; min-width: 0; }
.person-pick:has(input:checked) { border-color: var(--gold); background: var(--gold-bg); }
.person-pick input { margin: 0; }
.person-pick .person-dot { width: 24px; height: 24px; font-size: .62rem; }
.attendance-list { list-style: none; margin: 0 0 12px; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.attendance-list li { display: flex; align-items: center; gap: 8px; min-width: 0; }
.attendance-name { min-width: 0; overflow-wrap: anywhere; }
.attendance-list .chip-xs { margin-left: auto; }
@media (max-width: 767.98px) {
    .meeting-row { flex-wrap: wrap; }
    .meeting-row .task-main { flex: 1 1 calc(100% - 80px); }
    .meeting-progress { flex: 1 1 100%; padding-left: 70px; }
    .meeting-row > .btn { margin-left: 70px; }
}

/* The live meeting page (WO-059 item 10): since last time, the agenda item by
   item with its own form, and attendance as a tap per name. */
.meeting-main { display: flex; flex-direction: column; min-width: 0; }
.since-progress { display: flex; align-items: center; gap: 12px; margin: 0 0 8px; font-size: .88em; color: var(--muted); }
.since-progress .progress-track { flex: 1; margin-top: 0; }
.since-progress .progress-fill { width: var(--done, 0%); }
.task-row.is-compact { padding: 6px 0; gap: 10px; }
.task-row.is-compact .task-check { width: 20px; height: 20px; border-width: 1.5px; }
.task-row.is-compact .person-dot { width: 24px; height: 24px; font-size: .62rem; }
.agenda-items { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.agenda-item { border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 12px 14px; background: var(--surface); scroll-margin-top: 80px; }
.agenda-item.is-discussed { border-left: 4px solid var(--success); }
.agenda-item.is-carried { border-left: 4px solid var(--gold); }
.agenda-head { display: flex; align-items: flex-start; gap: 10px; min-width: 0; }
.agenda-number { display: inline-grid; place-items: center; flex: 0 0 28px; height: 28px; border-radius: 50%; background: var(--navy); color: #fff; font-weight: 800; font-size: .8rem; }
.agenda-title { margin: 2px 0 0; font-size: 1rem; overflow-wrap: anywhere; }
.agenda-move { display: flex; gap: 4px; flex: 0 0 auto; }
.agenda-move form { margin: 0; }
.agenda-form { margin-top: 10px; }
.agenda-form .form-group { margin-bottom: 10px; }
.agenda-form-foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px; }
.agenda-discussed { display: inline-flex; align-items: center; gap: 8px; min-height: 36px; font-weight: 600; cursor: pointer; }
.agenda-text { margin: 8px 0 0; overflow-wrap: anywhere; }
.agenda-tasks { margin-top: 8px; border-top: 1px dashed var(--border); padding-top: 4px; }
.agenda-raise { margin-top: 6px; }
.agenda-raise-form { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.agenda-raise-form input[type="text"] { flex: 1 1 220px; min-width: 0; }
.agenda-raise-form select, .agenda-raise-form input[type="date"] { width: auto; min-width: 0; max-width: 200px; }
.agenda-add { margin: 14px 0 0; padding: 0; box-shadow: none; border: 0; }
.attendance-tap { margin: 0; flex: 1; min-width: 0; }
.attendance-tap button {
    display: flex; align-items: center; gap: 8px; width: 100%; min-height: 44px; padding: 4px 10px 4px 4px;
    border: 1px solid var(--border); border-radius: 999px; background: var(--surface); color: var(--ink);
    font: inherit; text-align: left; cursor: pointer;
}
.attendance-tap button:hover { border-color: var(--border-strong); }
.attendance-tap button[aria-pressed="true"] { border-color: var(--success); background: var(--success-bg); }
.attendance-mark { margin-left: auto; font-size: .78em; font-weight: 700; color: var(--muted); white-space: nowrap; }
.attendance-tap button[aria-pressed="true"] .attendance-mark { color: var(--success); }
@media (max-width: 767.98px) {
    .agenda-raise-form select, .agenda-raise-form input[type="date"] { max-width: none; flex: 1 1 140px; }
    .agenda-form-foot .btn { min-height: 40px; }
}

/* Minutes (WO-059 item 11): composed from the items, then the send press and
   the reopen-with-a-reason beside it; what happened to the meeting underneath. */
.minutes { border-left: 4px solid var(--navy); }
.minutes-who { margin: 0 0 10px; font-size: .92em; }
.minutes-items { margin: 0 0 12px; padding-left: 20px; display: flex; flex-direction: column; gap: 8px; }
.minutes-items p { margin: 2px 0 0; overflow-wrap: anywhere; }
.minutes-items ul { margin: 4px 0 0; padding-left: 18px; font-size: .92em; color: var(--muted); }
.minutes-actions { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px; }
.minutes-reopen { flex-wrap: wrap; }
.minutes-reopen .form-control { width: auto; min-width: 0; max-width: 220px; }
.meeting-events { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; font-size: .86em; overflow-wrap: anywhere; }

/* Carry-over (WO-059 item 12): what the series left open, offered ticked. */
.plan-series { margin-bottom: 14px; }
.carry-offer { border: 1px solid var(--gold); background: var(--gold-bg); border-radius: var(--radius-sm); margin: 0 0 16px; padding: 10px 12px; display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.carry-offer legend { font-weight: 700; font-size: .92em; padding: 0 4px; color: var(--gold-ink); }
.carry-pick { display: flex; align-items: flex-start; gap: 10px; cursor: pointer; min-width: 0; }
.carry-pick input { margin-top: 4px; }
.carry-title { font-weight: 600; overflow-wrap: anywhere; }


/* ---------------------------------------------------------------------------
   housekeeping: statuses in the hotel's colours — WO-061

   The twelve swatches a room status may take (docs/DESIGN.md §4). A swatch
   class sets three custom properties - the fill, the edge and the text on
   the fill - and a component reads them, so a status's colour is one class
   and never a typed hex. Each text colour is chosen for its fill (the tests
   hold it to 4.5:1), and each swatch has its dark pair under
   [data-theme="dark"], ready for the day the app has a dark theme.
   --------------------------------------------------------------------------- */
.swatch-red { --sw-bg: #FEE2E2; --sw-edge: #DC2626; --sw-ink: #7F1D1D; }
.swatch-orange { --sw-bg: #FFEDD5; --sw-edge: #EA580C; --sw-ink: #7C2D12; }
.swatch-amber { --sw-bg: #FEF3C7; --sw-edge: #D97706; --sw-ink: #78350F; }
.swatch-lime { --sw-bg: #ECFCCB; --sw-edge: #65A30D; --sw-ink: #365314; }
.swatch-green { --sw-bg: #DCFCE7; --sw-edge: #16A34A; --sw-ink: #14532D; }
.swatch-teal { --sw-bg: #CCFBF1; --sw-edge: #0D9488; --sw-ink: #134E4A; }
.swatch-sky { --sw-bg: #E0F2FE; --sw-edge: #0284C7; --sw-ink: #0C4A6E; }
.swatch-blue { --sw-bg: #DBEAFE; --sw-edge: #2563EB; --sw-ink: #1E3A8A; }
.swatch-indigo { --sw-bg: #E0E7FF; --sw-edge: #4F46E5; --sw-ink: #312E81; }
.swatch-purple { --sw-bg: #F3E8FF; --sw-edge: #9333EA; --sw-ink: #581C87; }
.swatch-pink { --sw-bg: #FCE7F3; --sw-edge: #DB2777; --sw-ink: #831843; }
.swatch-grey { --sw-bg: #E5E7EB; --sw-edge: #6B7280; --sw-ink: #1F2937; }
[data-theme="dark"] .swatch-red { --sw-bg: #450A0A; --sw-edge: #F87171; --sw-ink: #FECACA; }
[data-theme="dark"] .swatch-orange { --sw-bg: #431407; --sw-edge: #FB923C; --sw-ink: #FED7AA; }
[data-theme="dark"] .swatch-amber { --sw-bg: #451A03; --sw-edge: #FBBF24; --sw-ink: #FDE68A; }
[data-theme="dark"] .swatch-lime { --sw-bg: #1A2E05; --sw-edge: #A3E635; --sw-ink: #D9F99D; }
[data-theme="dark"] .swatch-green { --sw-bg: #052E16; --sw-edge: #4ADE80; --sw-ink: #BBF7D0; }
[data-theme="dark"] .swatch-teal { --sw-bg: #042F2E; --sw-edge: #2DD4BF; --sw-ink: #99F6E4; }
[data-theme="dark"] .swatch-sky { --sw-bg: #082F49; --sw-edge: #38BDF8; --sw-ink: #BAE6FD; }
[data-theme="dark"] .swatch-blue { --sw-bg: #172554; --sw-edge: #60A5FA; --sw-ink: #BFDBFE; }
[data-theme="dark"] .swatch-indigo { --sw-bg: #1E1B4B; --sw-edge: #818CF8; --sw-ink: #C7D2FE; }
[data-theme="dark"] .swatch-purple { --sw-bg: #3B0764; --sw-edge: #C084FC; --sw-ink: #E9D5FF; }
[data-theme="dark"] .swatch-pink { --sw-bg: #500724; --sw-edge: #F472B6; --sw-ink: #FBCFE8; }
[data-theme="dark"] .swatch-grey { --sw-bg: #1F2937; --sw-edge: #9CA3AF; --sw-ink: #E5E7EB; }

/* A status as it reads anywhere: its name on its fill, edged in its colour. */
.status-pill { display: inline-flex; align-items: center; min-height: 28px; padding: 2px 12px; border-radius: 999px; border: 2px solid var(--sw-edge, var(--border-strong)); background: var(--sw-bg, var(--surface)); color: var(--sw-ink, var(--ink)); font-weight: 700; font-size: .9em; }
/* The board's sheet: each button is the status in its colour. */
.btn.hk-mark[class*="swatch-"] { background: var(--sw-bg); border-color: var(--sw-edge); color: var(--sw-ink); font-weight: 700; }
.btn.hk-mark[class*="swatch-"]:hover { box-shadow: inset 0 0 0 1px var(--sw-edge); }

/* Setup -> Room statuses: one card a status, its rules, and its change folded. */
.status-setup { display: grid; grid-template-columns: minmax(0, 1fr); gap: 10px; }
.status-row { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px; padding: 12px 14px; }
.status-row.is-retired { opacity: .72; }
.status-rules { flex: 1 1 220px; min-width: 0; color: var(--muted); font-size: .86em; }
.status-moves { display: flex; flex-wrap: wrap; gap: 6px; }
.status-edit { flex-basis: 100%; }
.status-edit > summary { display: inline-flex; align-items: center; min-height: 36px; cursor: pointer; font-weight: 600; color: var(--navy); }
.status-edit[open] > summary { margin-bottom: 8px; }
.status-flags { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 220px), 1fr)); gap: 6px 14px; margin-bottom: 12px; }
/* Twelve dots to pick from, never a colour wheel. The name is read aloud. */
.swatch-picker { border: 0; padding: 0; margin: 0 0 12px; min-width: 0; }
.swatch-options { display: flex; flex-wrap: wrap; gap: 8px; }
.swatch-option { position: relative; display: inline-grid; place-items: center; width: 44px; height: 44px; border-radius: 50%; cursor: pointer; }
.swatch-option input { position: absolute; opacity: 0; inset: 0; margin: 0; cursor: pointer; }
.swatch-dot { width: 32px; height: 32px; border-radius: 50%; background: var(--sw-bg); border: 3px solid var(--sw-edge); }
.swatch-option input:checked + .swatch-dot { box-shadow: 0 0 0 3px var(--surface), 0 0 0 5px var(--sw-ink); }
.swatch-option input:focus-visible + .swatch-dot { outline: 3px solid var(--gold); outline-offset: 3px; }

/* Setup -> Floors and rooms (WO-061 item 5): the rule's six boxes, then a card a floor, top floor first. */
.hk-rule-card > summary.hk-rule-summary { display: flex; align-items: center; min-height: 40px; cursor: pointer; font-weight: 700; font-size: 1.05em; color: var(--navy); }
.hk-rule-card[open] > summary.hk-rule-summary { margin-bottom: 10px; }
.hk-rule { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 150px), 1fr)); gap: 0 12px; align-items: end; }
.hk-rule-go { display: flex; align-items: flex-end; }
.hk-plan-table { min-width: 0; }
.hk-floor-setup { display: grid; grid-template-columns: minmax(0, 1fr); gap: 10px; }
.hk-floor-card { padding: 12px 14px; position: relative; }
.hk-floor-card-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 4px 12px; margin-bottom: 8px; }
.hk-floor-card-head h3 { margin-bottom: 0; font-size: 1em; }
.hk-room-chips { display: flex; flex-wrap: wrap; gap: 4px; }
.hk-room-chip { display: inline-block; min-width: 3.4em; padding: 2px 6px; border-radius: 6px; border: 1px solid var(--border); background: var(--surface-2); text-align: center; font-size: .82em; font-variant-numeric: tabular-nums; }
.hk-room-chip.is-retired { color: var(--muted-light); text-decoration: line-through; background: var(--surface); border-style: dashed; }
.hk-floor-edit { margin-top: 10px; }
.hk-floor-edit > summary { display: inline-flex; align-items: center; min-height: 36px; cursor: pointer; font-weight: 600; color: var(--navy); }
/* WO-072 item 6: Change sits on the card's header row, not under the chips. */
.hk-floor-edit > summary.hk-floor-change { position: absolute; top: 4px; right: 8px; list-style: none; }
.hk-floor-edit > summary.hk-floor-change::-webkit-details-marker { display: none; }
.hk-floor-card:has(.hk-floor-change) .hd-head { padding-right: 76px; }
.hk-floor-edit:not([open]) { margin-top: 0; }
.hk-floor-forms { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr)); gap: 8px 16px; margin-top: 6px; }
.hk-in-use { border: 0; margin: 0 0 8px; padding: 0; min-width: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); gap: 4px 10px; }
.hk-in-use legend { grid-column: 1 / -1; margin-bottom: 4px; }
.hk-building-heading { margin: 18px 0 8px; font-size: 1em; color: var(--muted); text-transform: uppercase; letter-spacing: .06em; }

/* The Room Board as the building (WO-061 item 6). Floors stacked top floor
   first; each a row of windows lit in the status's swatch; the legend above is
   the filter. A dimmed window is one the filter is not asking about. */
.hk-board-toolbar { display: flex; flex-direction: column; gap: 12px; }
.status-legend { display: flex; flex-wrap: wrap; gap: 6px; }
.hk-legend { display: inline-flex; align-items: center; gap: 8px; min-height: 40px; padding: 4px 12px; border-radius: 999px; border: 2px solid var(--sw-edge, var(--border-strong)); background: var(--sw-bg, var(--surface)); color: var(--sw-ink, var(--ink)); font: inherit; font-size: .88em; font-weight: 600; cursor: pointer; }
.hk-legend.is-unmarked { border: 2px dashed var(--border-strong); background: var(--surface); color: var(--muted); }
.hk-legend strong { font-variant-numeric: tabular-nums; font-weight: 800; }
.hk-legend[aria-pressed="true"] { box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--sw-ink, var(--ink)); }
.status-legend.is-filtering .hk-legend[aria-pressed="false"] { opacity: .5; }
.hk-tower { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow-sm); overflow: hidden; }
.hk-storey { display: grid; grid-template-columns: minmax(0, 1fr); gap: 8px; padding: 10px 12px; border-top: 1px solid var(--border); }
.hk-storey:first-child { border-top: 0; }
.hk-storey-side { display: flex; flex-wrap: wrap; align-items: center; gap: 2px 10px; min-width: 0; }
.hk-storey-name { margin: 0; font-size: 1em; font-weight: 800; color: var(--navy); }
.hk-storey-range { color: var(--muted); font-size: .82em; font-variant-numeric: tabular-nums; }
.hk-storey-people { display: inline-flex; flex-wrap: wrap; gap: 3px; margin-left: auto; }
.hk-storey-people .person-dot { width: 26px; height: 26px; font-size: .64rem; }
/* The initials say the name on hover and on a tap (WO-068 item 2), beside
   them so the tower never clips it: to their left on a phone, where they
   end the floor's line, and to their right on a laptop. */
.hk-floor-person { position: relative; padding: 0; border: 0; font-family: inherit; line-height: 1; cursor: pointer; }
.hk-floor-person:hover::after, .hk-floor-person.is-named::after { content: attr(data-person-name); position: absolute; top: 50%; right: calc(100% + 6px); z-index: 3; transform: translateY(-50%); padding: 4px 8px; border-radius: var(--radius-sm); background: var(--ink); color: var(--surface); font-size: .78rem; font-weight: 700; letter-spacing: 0; white-space: nowrap; box-shadow: var(--shadow-sm); pointer-events: none; }
.hk-windows { display: grid; grid-template-columns: repeat(auto-fill, minmax(56px, 1fr)); gap: 5px; }
.hk-window { position: relative; display: grid; place-items: center; min-width: 0; min-height: 44px; padding: 4px 2px; border-radius: 6px; border: 2px solid var(--sw-edge); background: var(--sw-bg); color: var(--sw-ink); font: inherit; font-size: .86em; font-weight: 800; font-variant-numeric: tabular-nums; cursor: pointer; transition: opacity .15s, box-shadow .15s; }
.hk-window.is-unmarked { border: 1px dashed var(--border-strong); background: var(--surface-2); color: var(--muted); }
.hk-window.is-dim { opacity: .16; }
.hk-window:focus-visible, .hk-window.is-picked { outline: 3px solid var(--gold); outline-offset: 2px; }
.hk-window.is-saved { box-shadow: 0 0 0 3px var(--success); }
.hk-window.is-found { animation: hk-pulse .7s ease-in-out 4; }
@keyframes hk-pulse { 50% { box-shadow: 0 0 0 6px var(--gold); } }
/* The calm window (WO-068 item 2): the number, the colour, and at most two
   small marks in the corner - a note today (amber), a wrench for an open
   job, a bell for an open request. Drawn, never a word. */
.hk-window-marks { position: absolute; top: 2px; right: 2px; display: flex; align-items: center; gap: 2px; pointer-events: none; }
.hk-window-mark { display: grid; place-items: center; width: 14px; height: 14px; border-radius: 50%; background: var(--surface); color: var(--ink); box-shadow: 0 0 0 1px var(--sw-edge, var(--border-strong)); }
.hk-window-mark svg { width: 10px; height: 10px; fill: none; stroke: currentColor; stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; }
.hk-window-mark.is-note { width: 10px; height: 10px; margin: 2px; background: var(--warning); box-shadow: 0 0 0 1.5px var(--surface); }
.hk-window-mark.is-note.is-urgent { background: var(--danger); }
/* The sheet as a drawer (WO-068 item 3): on the right, full height, never
   over the windows - the page makes room for it and the board stays beside
   it, its windows dimmed but for the room picked, each still a tap away.
   On a phone the drawer is the screen, over the tab bar. */
.hk-drawer { position: fixed; inset: 0; z-index: 80; display: flex; flex-direction: column; gap: 12px; padding: 16px 16px calc(16px + env(safe-area-inset-bottom)); overflow-y: auto; overscroll-behavior: contain; background: var(--surface); }
.hk-drawer[hidden] { display: none; }
.hk-drawer:focus { outline: none; }
.hk-drawer > * { flex: 0 0 auto; margin-top: 0; margin-bottom: 0; }
.hk-drawer-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.hk-drawer-number { margin: 0; color: var(--navy); font-size: 2.2rem; font-weight: 800; line-height: 1.1; font-variant-numeric: tabular-nums; }
.hk-drawer-now { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; color: var(--muted); }
.hk-drawer-foot { margin-top: auto; padding-top: 10px; border-top: 1px solid var(--border); }
.hk-drawer-keys { display: none; }
/* The notes first (WO-068 item 4): the words on the room today, an urgent
   one red and first, then the one line that adds a note. */
.hk-drawer-part { display: grid; grid-template-columns: minmax(0, 1fr); gap: 8px; }
.hk-drawer-notes { display: grid; grid-template-columns: minmax(0, 1fr); gap: 6px; margin: 0; padding: 0; list-style: none; }
.hk-drawer-note { padding: 8px 10px; border-left: 4px solid var(--warning); border-radius: var(--radius-sm); background: var(--warning-bg); }
.hk-drawer-note.is-urgent { border-left-color: var(--danger); background: var(--danger-bg); }
.hk-drawer-note-words { margin: 0; color: var(--ink); font-weight: 600; overflow-wrap: anywhere; }
.hk-drawer-note-who { color: var(--muted); font-size: .82em; }
.hk-drawer-note.is-urgent strong { color: var(--danger); }
.hk-drawer-none { margin: 0; color: var(--muted); }
.hk-drawer-add { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.hk-drawer-add .form-control { flex: 1 1 180px; min-width: 0; }
.hk-drawer-urgent { display: inline-flex; align-items: center; gap: 6px; min-height: 44px; margin: 0; color: var(--danger); font-weight: 700; cursor: pointer; }
.hk-drawer-urgent input { width: 20px; height: 20px; accent-color: var(--danger); }
/* The status buttons (WO-068 item 5): big and in colour, one tap marks and
   closes; on a laptop each says its key. */
.hk-drawer-marks .hk-mark { min-height: 60px; font-size: 1.05rem; }
/* Needs, Fix and the trail (WO-068 item 6): the request kinds as chips that
   ask at a tap, what the room waits for above them; Fix, one chip with the
   job open on the room beside it; the last lines of the trail, small. */
.hk-drawer-label { margin: 0; color: var(--navy); font-size: .78rem; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; }
.hk-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.hk-chip { display: inline-flex; align-items: center; gap: 6px; min-height: 44px; padding: 0 14px; border: 1px solid var(--border-strong); border-radius: 999px; background: var(--surface); color: var(--ink); font: inherit; font-weight: 700; text-decoration: none; cursor: pointer; }
.hk-chip:hover { border-color: var(--navy); color: var(--navy); }
.hk-chip[disabled] { opacity: .5; cursor: default; }
.hk-chip svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.hk-chip-fix.is-urgent { border-color: var(--danger); color: var(--danger); }
.hk-drawer-fix { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; }
.hk-drawer-job { color: var(--muted); }
.hk-drawer-waits, .hk-drawer-trail { display: grid; grid-template-columns: minmax(0, 1fr); gap: 4px; margin: 0; padding: 0; list-style: none; }
.hk-drawer-waits li { overflow-wrap: anywhere; }
.hk-drawer-small { color: var(--muted); font-size: .84em; }
.hk-drawer-line { overflow-wrap: anywhere; }
.hk-drawer-line > span:first-child { font-variant-numeric: tabular-nums; font-weight: 700; color: var(--ink); }
.hk-key { display: none; margin-left: 8px; padding: 0 5px; border: 1px solid currentColor; border-radius: 4px; background: transparent; color: inherit; font: inherit; font-size: .72em; opacity: .7; }
.hk-drawer-open .hk-window:not(.is-picked):not(.is-dim) { opacity: .45; }
@media (max-width: 768px) {
    body.hk-drawer-open { overflow: hidden; }
}
@media (min-width: 769px) {
    .hk-drawer { left: auto; width: 400px; border-left: 1px solid var(--border); box-shadow: var(--shadow-lg); }
    body.hk-drawer-open .app-main { padding-right: 400px; }
    .hk-drawer-keys { display: inline; }
    .hk-drawer-marks .hk-key { display: inline-block; }
}
/* The floor row (WO-066 item 1): every view narrows to one floor. It wraps on
   a phone rather than scrolling; the picked floor is filled in navy. */
.hk-floor-row { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 12px; }
.hk-floor-pick { min-width: 40px; min-height: 36px; padding: 0 10px; border-radius: 999px; border: 1px solid var(--border-strong); background: var(--surface); color: var(--ink); font: inherit; font-size: .86em; font-weight: 700; font-variant-numeric: tabular-nums; cursor: pointer; }
.hk-floor-pick[aria-pressed="true"] { background: var(--navy); border-color: var(--navy); color: #fff; }
[data-floor].is-off-floor { display: none; }
/* Needed by (WO-066 item 5): a gold corner on the window, a section on the
   sheet, and a gold line on the housekeeper's card. */
.hk-flag { display: none; position: absolute; top: 0; left: 0; width: 0; height: 0; border-style: solid; border-width: 14px 14px 0 0; border-color: var(--gold) transparent transparent transparent; border-top-left-radius: 4px; }
.hk-window.has-flag .hk-flag { display: block; }
.hk-sheet-flag { min-width: 0; margin: 12px 0 0; padding: 10px 0 0; border: 0; border-top: 1px solid var(--border); }
.hk-sheet-flag legend { float: left; width: 100%; margin-bottom: 6px; padding: 0; font-weight: 700; color: var(--navy); }
.hk-sheet-flag legend + *, .hk-sheet-flag .hk-flag-row { clear: both; }
.hk-flag-row { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0 10px; align-items: end; }
@media (min-width: 600px) {
    .hk-flag-row { grid-template-columns: 130px minmax(0, 1fr) auto; }
}
.hk-room-needed { margin: 0 14px 10px; padding: 6px 10px; border-radius: var(--radius-sm); border-left: 4px solid var(--gold); background: var(--gold-bg); font-weight: 700; }
.hk-needed-heading { color: var(--gold-ink); }
/* Arrivals today (WO-066 item 6; the supervisor's day since WO-068 item 2): a
   room, its time and where the booking came from, and the one tap; on a
   phone the tap drops under the words. */
.hk-arrival-list { margin: 0; padding: 0; list-style: none; display: grid; gap: 6px; }
.hk-arrival { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; padding: 6px 0; border-top: 1px solid var(--border); }
.hk-arrival-room { min-width: 3.4em; font-weight: 800; font-variant-numeric: tabular-nums; }
.hk-arrival-when { flex: 1 1 200px; min-width: 0; }
.hk-arrival-state { font-weight: 700; color: var(--gold-ink); }
/* Requests (WO-066 item 7): one card a request - the room large, what and
   who, where it stands - and its next step as plain buttons in a row that
   wraps; Can't opens its why. The card's small acts on My Floors sit under
   the big button, as quiet disclosures. */
.hk-requests { display: grid; grid-template-columns: minmax(0, 1fr); gap: 10px; }
.hk-request { padding: 12px 14px; border-left: 6px solid var(--warning); }
.hk-request.is-taken { border-left-color: var(--info); }
.hk-request.is-done { border-left-color: var(--success); }
.hk-request.is-cant { border-left-color: var(--muted); }
.hk-request-head { display: grid; grid-template-columns: auto minmax(0, 1fr); grid-template-areas: "number what" "number who" "number state"; column-gap: 14px; align-items: center; }
.hk-request-head .hk-room-number { grid-area: number; }
.hk-request-what { grid-area: what; overflow-wrap: anywhere; }
.hk-request-who { grid-area: who; font-size: .88em; }
.hk-request-state { grid-area: state; font-weight: 700; font-size: .9em; }
.hk-request-acts { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 8px; margin-top: 10px; }
.hk-request-acts .btn { min-height: 44px; min-width: 88px; }
.hk-request-cant > summary { display: inline-flex; align-items: center; min-height: 44px; padding: 0 14px; border: 1px solid var(--border-strong); border-radius: var(--radius-sm); cursor: pointer; font-weight: 600; list-style: none; }
.hk-request-cant > summary::-webkit-details-marker { display: none; }
.hk-request-cant-form { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.hk-request-cant-form .form-control { flex: 1 1 200px; min-width: 0; }
.hk-request-raise > summary { display: flex; align-items: center; min-height: 40px; cursor: pointer; font-weight: 700; color: var(--navy); }
.hk-request-form { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0 12px; align-items: end; margin-top: 8px; }
@media (min-width: 769px) {
    .hk-requests { grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: start; }
    .hk-request-form { grid-template-columns: 120px 180px minmax(0, 1fr) auto; }
}
/* The runner on duty (WO-066 item 8), a slot above the floors. */
.hk-runner-slot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 16px; }
.hk-runner-now { min-width: 0; }
.hk-runner-now h3 { margin-bottom: 2px; font-size: 1em; }
.hk-runner-form { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.hk-runner-form .form-control { width: auto; min-width: 0; max-width: 240px; }
.hk-room-small { padding: 0 14px 12px; }
.hk-room-ask > summary { display: inline-flex; align-items: center; min-height: 40px; cursor: pointer; font-weight: 600; color: var(--navy); }
.hk-ask-form { display: grid; grid-template-columns: minmax(0, 1fr); gap: 6px; margin-top: 4px; }
.hk-room-small { display: flex; flex-wrap: wrap; gap: 0 16px; }
.hk-room-small > details { flex: 1 1 100%; }
.hk-room-small > details:not([open]) { flex: 0 0 auto; }
.hk-small-label { font-size: .85em; color: var(--muted); }
/* Time in a room (WO-066 item 11): how long a done room took, on her card;
   the too-fast ones on the day, for the supervisor. */
.hk-room-took { margin: 0 14px 10px; color: var(--muted); font-size: .9em; }
.hk-too-fast { color: var(--danger); }
.hk-too-fast-card { margin-top: 12px; border-left: 4px solid var(--warning); }
/* The supervisor's day (WO-066 item 12): cards in one column on a phone,
   columns on a laptop with the housekeepers across the top. */
.hk-sup { display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; align-items: start; }
.hk-sup .card h3 { font-size: 1em; }
.hk-sup-list { margin: 0; padding: 0; list-style: none; display: grid; gap: 10px; }
.hk-sup-person { display: grid; gap: 2px; padding-top: 8px; border-top: 1px solid var(--border); overflow-wrap: anywhere; }
.hk-sup-person:first-child { padding-top: 0; border-top: 0; }
@media (min-width: 769px) {
    .hk-sup { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .hk-sup-people { grid-column: 1 / -1; }
    .hk-sup-list { grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr)); }
    .hk-sup-person, .hk-sup-person:first-child { padding-top: 8px; border-top: 1px solid var(--border); }
}
@media (min-width: 1200px) {
    .hk-sup { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
/* Setup -> Housekeeping (WO-066 item 14): the numbers in a grid, a kind a row. */
.hk-setup-form { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0 16px; align-items: start; }
.hk-setup-form > .btn { justify-self: start; }
@media (min-width: 769px) {
    .hk-setup-form { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.hk-kind-list { margin: 0 0 10px; padding: 0; list-style: none; display: grid; gap: 6px; }
.hk-kind { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.hk-kind.is-retired .form-control { color: var(--muted); text-decoration: line-through; }
.hk-kind-form { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; flex: 1 1 auto; min-width: 0; }
.hk-kind-form .form-control { flex: 1 1 160px; min-width: 0; max-width: 280px; }
/* The day's found items and faults (WO-066 item 10), under the floors. */
.hk-day-lists { display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; margin-top: 12px; }
.hk-day-events { margin: 0; padding: 0; list-style: none; display: grid; gap: 8px; }
.hk-day-events li { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; overflow-wrap: anywhere; }
.hk-day-room { min-width: 3.4em; font-weight: 800; font-variant-numeric: tabular-nums; }
.hk-day-photo { margin-left: auto; font-weight: 600; }
@media (min-width: 769px) {
    .hk-day-lists { grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: start; }
}
/* By status: every chip starts on; one turned off is faded and struck through. */
[data-status-set] .hk-legend[aria-pressed="true"] { box-shadow: none; }
[data-status-set] .hk-legend[aria-pressed="false"] { opacity: .45; text-decoration: line-through; }
@media (min-width: 769px) {
    .hk-storey { grid-template-columns: 150px minmax(0, 1fr); align-items: center; gap: 14px; }
    .hk-storey-side { flex-direction: column; align-items: flex-start; }
    .hk-storey-people { margin-left: 0; }
    .hk-floor-person:hover::after, .hk-floor-person.is-named::after { right: auto; left: calc(100% + 6px); }
    .hk-windows { grid-template-columns: repeat(auto-fill, minmax(62px, 1fr)); }
}

/* Select many (WO-061 item 7): a chosen window is ringed in navy; a floor's
   "All of" button shows only in the mode; the tower leaves room for the bar. */
.hk-storey-pick { display: none; }
.hk-tower.is-selecting .hk-storey-pick { display: inline-flex; }
[data-hk-board].is-selecting { margin-bottom: 340px; }
.hk-window.is-selected { outline: 3px solid var(--navy); outline-offset: 2px; box-shadow: inset 0 0 0 2px var(--surface); }
[data-select-many][aria-pressed="true"] { background: var(--navy); border-color: var(--navy); color: #fff; }

/* rp:start */
/* ---------------------------------------------------------------------------
   reports: the kit - WO-062 (docs/DESIGN.md §10)

   Every report screen is built from these: the head, tiles, the headline,
   the caveats chip, figure cards and the statement table, around charts drawn
   on the server by core/charts.py. A chart mark names a slot - rp-s1..rp-s6,
   rp-in, rp-out, rp-total, rp-hi, rp-other, rp-seq-1..5 - and only this block
   says what colour a slot is. Each colour below is an existing token or a
   step of one, run through the dataviz validator light and dark (§10 has the
   output): navy stepped into the lightness band, gold's own dark step, then
   the WO-061 swatch edges in the order that passes. PDFs copy this block
   between the rp:start and rp:end markers (core/templatetags/charts.py), so
   keep both markers.
   --------------------------------------------------------------------------- */
:root {
    --chart-1: #334F8F;  /* navy: --navy stepped into the band (#14203D is L 0.25) */
    --chart-2: #8B6A22;  /* gold: --gold-ink (--gold is 2.56:1 on white) */
    --chart-3: #0284C7;  /* sky: .swatch-sky edge */
    --chart-4: #EA580C;  /* orange: .swatch-orange edge */
    --chart-5: #9333EA;  /* purple: .swatch-purple edge */
    --chart-6: #0D9488;  /* teal: .swatch-teal edge */
    --chart-in: var(--chart-6);
    --chart-out: var(--chart-4);
    --chart-total: var(--muted);
    --chart-other: var(--muted-light);
    --chart-track: var(--neutral-bg);
    --chart-grid: var(--border);
    --chart-surface: var(--surface);
    --chart-seq-1: #8EABE4;  /* magnitude: one navy hue, light to dark */
    --chart-seq-2: #6A85BD;
    --chart-seq-3: #496297;
    --chart-seq-4: #294072;
    --chart-seq-5: #0F2352;
    --rp-radius: 16px;
}
[data-theme="dark"] {
    --chart-1: #6083D4;
    --chart-2: #A97E1A;
    --chart-3: #198ED2;
    --chart-4: #CA653D;
    --chart-5: #976FCB;
    --chart-6: #00A091;
    --chart-seq-1: #395184;
    --chart-seq-2: #5771A6;
    --chart-seq-3: #7692CA;
    --chart-seq-4: #97B4EE;
    --chart-seq-5: #B9D8FF;
}

/* Slots: a mark takes its slot's colour as `color`, and draws in currentColor. */
.rp-s1 { color: var(--chart-1); }
.rp-s2, .rp-hi { color: var(--chart-2); }
.rp-s3 { color: var(--chart-3); }
.rp-s4 { color: var(--chart-4); }
.rp-s5 { color: var(--chart-5); }
.rp-s6 { color: var(--chart-6); }
/* WO-072 item 8: the run before, under the run it is set against - lighter,
   thinner, no fill and no point, so this period is read first. */
.rp-compare { color: var(--muted-light); }
.rp-draw .rp-compare { stroke-width: 1.5px; stroke-dasharray: 4 3; }
.rp-in { color: var(--chart-in); }
.rp-out { color: var(--chart-out); }
.rp-total { color: var(--chart-total); }
.rp-other { color: var(--chart-other); }
.rp-seq-1 { color: var(--chart-seq-1); }
.rp-seq-2 { color: var(--chart-seq-2); }
.rp-seq-3 { color: var(--chart-seq-3); }
.rp-seq-4 { color: var(--chart-seq-4); }
.rp-seq-5 { color: var(--chart-seq-5); }

/* Marks. Thin, rounded at the data end, separated by the surface, never outlined. */
.rp-chart { display: block; overflow: visible; font-family: var(--sans); }
.rp-chart:focus-visible { outline: 2px solid var(--gold); outline-offset: 4px; border-radius: 6px; }
.rp-bar, .rp-seg, .rp-cell { fill: currentColor; }
.rp-seg, .rp-cell { stroke: var(--chart-surface); stroke-width: 2px; }
.rp-line { stroke: currentColor; stroke-width: 2px; stroke-linejoin: round; stroke-linecap: round; }
.rp-fill { stroke: none; }
.rp-dot { fill: currentColor; stroke: var(--chart-surface); stroke-width: 2px; }
.rp-arc { stroke: currentColor; }
.rp-track { fill: var(--chart-track); }
.rp-track-ring { stroke: var(--chart-track); }
.rp-gridline { stroke: var(--chart-grid); stroke-width: 1px; }
/* The figure a run is measured against (WO-071 item 9): dotted, under the
   data, named at the end so it is not another gridline. */
.rp-reference { stroke: var(--chart-2); stroke-width: 1.5px; stroke-dasharray: 4 4; }
.rp-reference-label { fill: var(--chart-2); font-size: 10px; font-weight: 600; text-anchor: end; }
.rp-base, .rp-connector { stroke: var(--border-strong); stroke-width: 1px; }
.rp-target { stroke: var(--ink); stroke-width: 2px; stroke-linecap: round; }
.rp-unknown { fill: var(--muted-light); }
.rp-unknown-cell { fill: var(--chart-surface); stroke: var(--border-strong); stroke-width: 1px; stroke-dasharray: 3 2; }
.rp-hit { fill: transparent; }
.rp-cross { stroke: var(--border-strong); stroke-width: 1px; opacity: 0; }
.rp-hitgroup:hover .rp-cross, .rp-hitgroup.is-lit .rp-cross { opacity: 1; }
svg:hover > .rp-bar, svg.is-lit > .rp-bar, .rp-seg.is-lit, .rp-cell.is-lit, .rp-arc.is-lit { opacity: .78; }
.rp-chart text { fill: var(--muted); font-size: 11px; }
.rp-chart .rp-axis { paint-order: stroke; stroke: var(--chart-surface); stroke-width: 3px; stroke-linejoin: round; }
.rp-chart .rp-label { fill: var(--ink); font-size: 12px; font-weight: 700; }
.rp-chart .rp-row-label { fill: var(--ink); font-size: 13px; font-weight: 600; }
.rp-chart .rp-row-value { fill: var(--ink); font-size: 13px; font-weight: 700; font-variant-numeric: tabular-nums; }
/* WO-076 item 3: a row read beside the rank but not in it, and a row's move beside its figure. */
.rp-chart .rp-row-muted { fill: var(--muted); font-weight: 500; }
.rp-chart .rp-row-note { fill: var(--muted); font-size: 12px; font-weight: 600; font-variant-numeric: tabular-nums; }
.rp-chart .rp-centre-value { fill: var(--ink); font-size: 11px; font-weight: 800; }
.rp-chart .rp-centre-label { fill: var(--muted); font-size: 6.5px; font-weight: 600; }
.rp-gauge .rp-centre-value { font-size: 14px; }
@media (max-width: 560px) { .rp-tick-minor, .rp-label-minor { display: none; } }

/* Motion: once, on load, 700ms at most; none for anybody who asked for less, and none on paper. */
@keyframes rp-grow { from { transform: scaleY(0); } }
@keyframes rp-grow-x { from { transform: scaleX(0); } }
@keyframes rp-fade { from { opacity: 0; } }
@keyframes rp-reveal { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }
@keyframes rp-arc { from { stroke-dasharray: 0 100; } }
@keyframes rp-rise { from { opacity: 0; transform: translateY(8px); } }
/* WO-077 item 7b: the kit's motion, as tokens a page composes. Each moves
   with `translate` and `scale`, never `transform`, so it adds to an
   element's own - a dot centred on its price stays on it while it pops. A
   page uses them inside `@media (prefers-reduced-motion: no-preference)`. */
@keyframes rise { from { opacity: 0; translate: 0 14px; } }
@keyframes fadein { from { opacity: 0; } }
@keyframes pop { from { opacity: 0; scale: .2; } }
@keyframes ping { 0% { scale: .55; opacity: .75; } 70% { scale: 1.7; opacity: 0; } 100% { scale: 1.7; opacity: 0; } }
@keyframes draw { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }
@keyframes grow { from { scale: 1 0; } }
.rp-grow, .rp-grow-down, .rp-grow-x { transform-box: fill-box; animation: rp-grow .6s cubic-bezier(.2, .7, .2, 1) both; }
.rp-grow { transform-origin: 50% 100%; }
.rp-grow-down { transform-origin: 50% 0; }
.rp-grow-x { transform-origin: 0 50%; animation-name: rp-grow-x; }
.rp-grow-fade { animation: rp-fade .5s ease-out both; }
.rp-draw { animation: rp-reveal .7s ease-out both; }
.rp-draw-arc { animation: rp-arc .7s ease-out both; }
.rp-card { animation: rp-rise .45s ease-out both; }
.rp-kpis > :nth-child(2), .rp-grid > :nth-child(2) { animation-delay: 40ms; }
.rp-kpis > :nth-child(3), .rp-grid > :nth-child(3) { animation-delay: 80ms; }
.rp-kpis > :nth-child(4), .rp-grid > :nth-child(4) { animation-delay: 120ms; }
.rp-kpis > :nth-child(5), .rp-grid > :nth-child(5) { animation-delay: 160ms; }
.rp-kpis > :nth-child(n+6), .rp-grid > :nth-child(n+6) { animation-delay: 200ms; }
@media (prefers-reduced-motion: reduce) {
    .rp-card, .rp-chart, .rp-chart * { animation: none !important; }
}
@media print {
    .rp-card, .rp-chart, .rp-chart * { animation: none !important; }
    .rp-card { box-shadow: none; break-inside: avoid; }
    .rp-figures, .rp-switch, .rp-export, .rp-tooltip { display: none !important; }
}

/* The page: head, headline, caveats, tiles, then figure cards. */
.rp-page { display: grid; gap: 16px; min-width: 0; }
.rp-eyebrow { font-size: .7rem; font-weight: 800; letter-spacing: .09em; text-transform: uppercase; color: var(--gold-ink); }
.rp-head-sub { display: flex; flex-wrap: wrap; }
.rp-head-sub span + span::before { content: "\00B7"; margin: 0 8px; color: var(--muted-light); }
@media (max-width: 560px) { .rp-head-sub { flex-direction: column; } .rp-head-sub span + span::before { content: none; } }
.rp-headline { margin: 0; max-width: 72ch; font-size: 1.06rem; line-height: 1.55; color: var(--ink); }
.rp-card { min-width: 0; padding: 20px 22px; border: 1px solid var(--border); border-radius: var(--rp-radius); background: var(--surface); box-shadow: var(--shadow-sm); }
/* The tile's rules moved into the kit's block on WO-071 item 8, where the
   partial that draws it lives. */
.rp-mark { display: inline-grid; place-items: center; min-width: 17px; height: 17px; padding: 0 4px; border-radius: 999px; background: var(--gold-bg); color: var(--gold-ink); font-size: .68rem; font-weight: 800; letter-spacing: 0; text-decoration: none; }
.rp-chip { display: inline-flex; align-items: center; gap: 8px; min-height: 34px; padding: 4px 14px; border: 1px solid var(--gold); border-radius: 999px; background: var(--gold-bg); color: var(--ink); font-size: .86rem; font-weight: 700; cursor: pointer; list-style: none; }
.rp-chip::-webkit-details-marker { display: none; }
.rp-chip::before { content: "i"; display: inline-grid; place-items: center; width: 18px; height: 18px; border-radius: 50%; background: var(--gold-ink); color: var(--surface); font-size: .72rem; font-weight: 800; font-style: italic; }
.rp-caveat-list { max-width: 80ch; margin: 10px 0 0; padding: 14px 18px 14px 36px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); color: var(--ink); font-size: .92rem; line-height: 1.55; }
.rp-caveat-list li + li { margin-top: 6px; }
.rp-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 380px), 1fr)); gap: 16px; }
/* Small multiples (item 12): narrower columns, because the point of them is
   seeing several at once - three abreast on a laptop, one on a phone. They are
   cards inside a card, so they carry no shadow of their own. */
.rp-small-multiples { grid-template-columns: repeat(auto-fit, minmax(min(100%, 230px), 1fr)); gap: 12px; }
.rp-small-multiples .rp-card { padding: 12px 14px; box-shadow: none; }
.rp-small-multiples .rp-figure-head { margin-bottom: 8px; }
.rp-small-multiples .rp-figure-head h3 { font-size: var(--fs-body); }
.rp-figure.is-wide { grid-column: 1 / -1; }
.rp-figure-head { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: 8px 12px; margin-bottom: 14px; }
.rp-figure-head > div { min-width: 0; }
/* A figure's own heading is a lead, not a title: the figure under it is what
   the card is about (WO-071 item 10). It was 1.02rem in weight 800. */
.rp-figure-head h3 { margin: 0; font-size: var(--fs-lead); font-weight: 600; color: var(--ink); }
.rp-figure-head p { margin: 3px 0 0; font-size: var(--fs-small); color: var(--muted); }
.rp-figure-body { min-width: 0; }
.rp-form-ring, .rp-form-gauge { display: flex; flex-wrap: wrap; align-items: center; gap: 14px 28px; }
.rp-form-ring .rp-plot, .rp-form-gauge .rp-plot { flex: 0 0 auto; }
.rp-form-ring .rp-legend { flex: 1 1 200px; flex-direction: column; min-width: 0; margin: 0; }
.rp-legend { display: flex; flex-wrap: wrap; gap: 6px 16px; margin: 12px 0 0; padding: 0; list-style: none; font-size: .86rem; color: var(--ink); }
.rp-legend li { display: flex; align-items: center; gap: 6px; min-width: 0; }
.rp-legend-group { width: 100%; font-size: .7rem; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.rp-key { flex: 0 0 auto; width: 10px; height: 10px; border-radius: 3px; background: currentColor; }
.rp-form-lines .rp-key { width: 14px; height: 3px; border-radius: 2px; }
.rp-legend-label { min-width: 0; overflow-wrap: anywhere; }
.rp-legend-value { margin-left: auto; padding-left: 8px; font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }
.rp-legend-share { min-width: 3.4em; text-align: right; color: var(--muted); font-variant-numeric: tabular-nums; }
.rp-scale { align-items: center; gap: 8px; font-size: .8rem; color: var(--muted); }
.rp-scale-steps { display: inline-flex; gap: 2px; }
.rp-scale-steps i { width: 16px; height: 10px; border-radius: 2px; background: currentColor; }
.rp-switch { display: inline-flex; gap: 2px; padding: 3px; border-radius: 999px; background: var(--neutral-bg); }
.rp-page > .rp-switch { justify-self: start; max-width: 100%; flex-wrap: wrap; }
.rp-switch a { display: inline-flex; align-items: center; min-height: 30px; padding: 2px 12px; border-radius: 999px; font-size: .8rem; font-weight: 700; color: var(--muted); text-decoration: none; }
.rp-switch a.is-active { background: var(--surface); color: var(--ink); box-shadow: var(--shadow-sm); }
.rp-figures { margin-top: 14px; padding-top: 10px; border-top: 1px solid var(--border); }
.rp-figures summary { cursor: pointer; font-size: .84rem; font-weight: 700; color: var(--navy-lighter); }
.rp-twin { margin-top: 8px; }
.rp-empty { margin: 0; padding: 28px 14px; border-radius: var(--radius-sm); background: var(--surface-2); color: var(--muted); text-align: center; }
.rp-tooltip { position: fixed; top: var(--tip-y, 0); left: var(--tip-x, 0); z-index: 1000; max-width: 260px; padding: 8px 11px; border-radius: 10px; background: var(--navy-deep); color: var(--surface); box-shadow: var(--shadow-md); font-size: .82rem; line-height: 1.45; font-variant-numeric: tabular-nums; pointer-events: none; }
.rp-tooltip-head { margin-bottom: 2px; font-weight: 800; color: var(--gold); }
.rp-export { position: relative; }
.rp-export > summary { list-style: none; }
.rp-export > summary::-webkit-details-marker { display: none; }
.rp-export-menu { position: absolute; top: calc(100% + 6px); right: 0; z-index: 30; display: grid; min-width: 190px; padding: 6px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface); box-shadow: var(--shadow-md); }
.rp-export-menu a { padding: 9px 10px; border-radius: 6px; color: var(--ink); text-decoration: none; }
.rp-export-menu a:hover { background: var(--surface-2); }

/* The period: one control - back, the period, forward, what to compare with (item 2). */
.rp-period { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.rp-period .form-control { width: auto; max-width: 100%; min-height: 40px; }
.rp-period-field { display: inline-flex; align-items: center; gap: 6px; min-width: 0; margin: 0; font-size: .84rem; color: var(--muted); }
.rp-step { justify-content: center; min-width: 40px; padding-inline: 10px; font-size: 1.25rem; line-height: 1; }
.rp-step.is-disabled { opacity: .4; pointer-events: none; }
.rp-period.is-live .rp-period-show { display: none; }
.rp-period-label { white-space: nowrap; }
.rp-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
@media (max-width: 768px) {
    /* One row - back, the period, forward - and the comparison under it.
       `.pg-head-tools` is the kit's header row (WO-071 item 8); `.action-group`
       is the shape the screens not yet swept still use. Outranks the header's
       `.action-group .btn { width: 100% }`, which fills a cell. */
    .page-header .action-group .rp-period,
    .pg-head-tools .rp-period { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; grid-column: 1 / -1; }
    .page-header .action-group form.rp-period .btn.btn-secondary,
    .pg-head-tools form.rp-period .btn.btn-secondary { width: auto; }
    .page-header .action-group form.rp-period .rp-period-show,
    .pg-head-tools form.rp-period .rp-period-show,
    .rp-period .rp-period-field:has(select[name="compare"]) { grid-column: 1 / -1; }
    .rp-period .rp-period-field .form-control { flex: 1 1 auto; width: 100%; }
    .page-header .action-group .rp-export,
    .pg-head-tools .rp-export { grid-column: 1 / -1; }
    .page-header .action-group .rp-export > summary,
    .pg-head-tools .rp-export > summary { width: 100%; }
    /* The tools are the width of the page there, so the control has room. */
    .pg-head-tools { width: 100%; }
    .pg-head-tools > form.rp-period { width: 100%; }
}
.rp-notice { margin: -6px 0 16px; padding: 10px 14px; border-left: 3px solid var(--info); border-radius: var(--radius-sm); background: var(--info-bg); color: var(--ink); font-size: .92rem; }
.rp-notice.is-error { border-left-color: var(--danger); background: var(--danger-bg); }

/* Reports home (item 3): shelves of report cards, each a question and its figure. */
.rp-shelf { display: grid; gap: 10px; min-width: 0; }
.rp-shelf-title { margin: var(--sp-2) 0 0; font-size: var(--fs-eyebrow); font-weight: 600; letter-spacing: .09em; text-transform: uppercase; color: var(--muted); }
.rp-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 250px), 1fr)); gap: 12px; }
.rp-report-card { display: flex; flex-direction: column; gap: 4px; padding: 16px 18px; color: var(--ink); text-decoration: none; transition: border-color .15s, box-shadow .15s, transform .15s; }
.rp-report-card:hover, .rp-report-card:focus-visible { border-color: var(--gold); box-shadow: var(--shadow-md); transform: translateY(-1px); }
.rp-report-name { font-weight: 800; color: var(--navy); }
.rp-report-question { font-size: .88rem; line-height: 1.4; color: var(--muted); }
.rp-report-figure { margin-top: 8px; font-size: 1.35rem; font-weight: 800; line-height: 1.2; overflow-wrap: anywhere; color: var(--ink); }
.rp-report-figure.is-unknown { color: var(--muted); }
.rp-report-note { font-size: .82rem; line-height: 1.4; color: var(--muted); }

/* report:start ------- the report surface: a page, not a grid of boxes (WO-073 item 3) -------
   The owner: "most designs in the reports are too squary". WO-071's kit put a
   card around everything, and a report became a grid of boxes with shadows. A
   page wrapped `rp-page report` reads as one page: the figures in one strip
   divided by hairlines, each section whitespace and a rule above its heading,
   a chart with no box, a caveat beside the figure it qualifies. A card stays
   only where something is done there - `.card.is-action` - and nothing on a
   report casts a shadow. core/tests/test_kit.py holds all three. */
.report { gap: var(--sp-5); }
.report .rp-card { padding: 0; border: 0; border-radius: 0; background: none; box-shadow: none; animation: none; }
/* The strip: one panel, a hairline between figures. Each line is its tile's
   own top and left edge, clipped by the panel, so a short last row on a phone
   leaves plain ground rather than a grey block. */
.report .rp-kpis, .report-strip {
    gap: 0; overflow: hidden;
    border: 1px solid var(--border); border-radius: var(--rp-radius); background: var(--surface);
}
.report .rp-kpis > .rp-kpi, .report-strip > * {
    padding: var(--sp-4) 18px var(--sp-3);
    box-shadow: -1px 0 0 var(--border), 0 -1px 0 var(--border);
}
.report .rp-kpis > .rp-kpi.is-lead { box-shadow: inset 0 2px 0 var(--gold), -1px 0 0 var(--border), 0 -1px 0 var(--border); }
/* A section: whitespace, and a rule above its heading. */
.report .rp-figure, .report-part { padding-top: var(--sp-4); border-top: 1px solid var(--border); }
.report .rp-grid { gap: var(--sp-5) var(--sp-6); }
.report .rp-shelf-title { margin-top: var(--sp-3); }
.report-chart { padding: 0; border: 0; background: none; }
/* WO-073 item 7: a card that stays on a report - a filter, a form, a link to
   load what is missing, a report's own door on Reports home - keeps its box
   and loses its shadow. */
.report .card { box-shadow: none; }
.report .rp-card.is-action {
    padding: 16px 18px; border: 1px solid var(--border); border-radius: var(--rp-radius);
    background: var(--surface);
}
.report .rp-report-card:hover, .report .rp-report-card:focus-visible { box-shadow: none; }
/* A caveat beside the figure it qualifies, not in a list at the foot. */
.report-note {
    margin: var(--sp-1) 0 0; padding-left: var(--sp-2);
    border-left: 2px solid var(--border);
    font-size: var(--fs-small); line-height: 1.45; color: var(--muted);
}
/* report:end */

/* nw:start ------- Performance's night workspace: one chart, one night (WO-073 item 5) ------- */
.nw-body { display: grid; grid-template-columns: minmax(0, 1fr) 280px; gap: var(--sp-5); align-items: start; }
.nw-plot { min-width: 0; }
.nw-night { display: flex; flex-direction: column; gap: var(--sp-3); padding-left: var(--sp-4); border-left: 1px solid var(--border); }
.nw-pick { display: flex; gap: var(--sp-2); align-items: center; }
.nw-pick .form-control { flex: 1; min-width: 0; }
.nw-figures { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3) var(--sp-4); margin: 0; }
.nw-figures dt { font-size: var(--fs-eyebrow); font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); }
.nw-figures dd { margin: 2px 0 0; white-space: nowrap; font-size: var(--fs-lead); font-weight: var(--fw-figure); font-variant-numeric: var(--num); color: var(--ink); }
/* The chosen night keeps its line across the plot, in the brand's gold. */
.nw .rp-hitgroup.is-picked .rp-cross { opacity: 1; stroke: var(--gold); }
@media (max-width: 900px) {
    .nw-body { grid-template-columns: minmax(0, 1fr); }
    .nw-night { padding-left: 0; border-left: 0; padding-top: var(--sp-3); border-top: 1px solid var(--border); }
}
/* nw:end */
@media (prefers-reduced-motion: reduce) { .rp-report-card { transition: none; } .rp-report-card:hover { transform: none; } }

/* The statement: tabular figures, costs in brackets, groups that fold. */
.rp-statement { min-width: 0; }
.rp-stmt-heading td { padding-top: 14px; font-size: .78rem; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.rp-stmt-subtotal td { font-weight: 700; }
.rp-stmt-group.is-summary .rp-stmt-total td { border-top: 2px solid var(--border-strong); font-size: 1.02em; }
.rp-stmt td.is-good { color: var(--success); }
.rp-stmt td.is-bad { color: var(--danger); }
.rp-stmt td.is-muted { color: var(--muted); font-size: .85em; }
.rp-foot { margin: 12px 0 0; max-width: 80ch; font-size: .84rem; line-height: 1.5; color: var(--muted); }
.rp-stmt td.num, .rp-stmt th.num { white-space: nowrap; }
.rp-stmt .rp-stmt-group-head th, .rp-stmt .rp-stmt-group-head td { padding-top: 14px; border-bottom: 1px solid var(--border); background: transparent; color: var(--ink); font-size: .95rem; letter-spacing: 0; text-align: left; text-transform: none; }
.rp-fold { display: inline-flex; align-items: center; gap: 10px; min-height: 32px; padding: 0; border: 0; background: none; color: var(--ink); font: inherit; font-weight: 800; cursor: pointer; }
.rp-fold::before { content: ""; width: 7px; height: 7px; margin-top: -3px; border-right: 2px solid var(--muted); border-bottom: 2px solid var(--muted); transform: rotate(45deg); transition: transform .15s; }
.rp-fold[aria-expanded="false"]::before { margin-top: 0; transform: rotate(-45deg); }
.rp-stmt-group.is-folded .rp-stmt-row { display: none; }
/* A long list read with two controls (item 10): a box that filters as you type
   and a switch that hides the accounts that did nothing. Both are the screen's,
   not the figures': a hidden row is still in every total. */
.rp-stmt.is-hiding-quiet .is-quiet { display: none; }
.rp-table-tools { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; margin-bottom: 12px; }
.rp-table-tools .form-control { width: auto; max-width: 100%; min-width: 220px; }
.rp-switch-label { display: inline-flex; align-items: center; gap: 8px; min-height: 40px; font-size: .88rem; color: var(--muted); }
.rp-stmt-total td { border-top: 1px solid var(--border-strong); font-weight: 800; }
.rp-share, .rp-stmt-note { color: var(--muted); }
.rp-stmt-note { font-size: .8rem; }
.rp-stmt-bullet { width: 170px; min-width: 130px; }
@media (min-width: 1024px) {
    .table-scroll.rp-stmt-wrap { overflow: visible; }
    .rp-stmt thead th { position: sticky; top: 0; z-index: 2; background: var(--surface-2); }
}
/* Ageing (item 8): a cell shaded by how old its bucket is, on the magnitude
   ramp the charts use. A wash rather than the ramp's own colour: these cells
   hold figures a person reads, so the ink stays --ink at every step. */
.rp-age-2 { background: color-mix(in srgb, var(--chart-1) 8%, transparent); }
.rp-age-3 { background: color-mix(in srgb, var(--chart-1) 16%, transparent); }
.rp-age-4 { background: color-mix(in srgb, var(--chart-1) 26%, transparent); }
.rp-age-5 { background: color-mix(in srgb, var(--chart-1) 38%, transparent); }
/* WO-079 item 2: rows that present - the bridge, two columns, the butterfly
   and a rank that takes a share and a second figure. A total's name is bold;
   the chosen mark carries a gold ring; a part's name and figure sit on it, in
   ink on the light steps of the hue and in the surface colour on the dark. */
.rp-chart .rp-row-label.is-total { font-weight: 800; }
.rp-chart .rp-row-share, .rp-chart .rp-row-second { fill: var(--muted); font-weight: 500; }
.rp-chart a { cursor: pointer; }
.rp-chart a:hover .rp-hit, .rp-chart a:focus-visible .rp-hit { fill: color-mix(in srgb, var(--ink) 4%, transparent); }
.rp-chart a:focus { outline: none; }
.rp-chart a:focus-visible .rp-hit { stroke: var(--gold); stroke-width: 1.5px; }
.rp-chart .is-picked .rp-bar, .rp-chart .is-picked .rp-seg { stroke: var(--gold); stroke-width: 2.5px; paint-order: stroke; }
.rp-chart .is-picked .rp-hit { fill: color-mix(in srgb, var(--gold) 9%, transparent); }
.rp-chart .rp-col-name { font-size: 13px; font-weight: 600; }
.rp-chart .rp-col-value { font-size: 13px; font-weight: 700; font-variant-numeric: tabular-nums; }
.rp-chart .rp-col-share { font-size: 11px; font-weight: 500; opacity: .85; }
.rp-chart .rp-col-head { fill: var(--muted); font-size: 11px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; }
.rp-col-part.rp-seq-1 text, .rp-col-part.rp-seq-2 text, .rp-col-part.rp-other text { fill: var(--ink); }
.rp-col-part.rp-seq-3 text, .rp-col-part.rp-seq-4 text, .rp-col-part.rp-seq-5 text { fill: var(--surface); }
/* WO-079 item 6, the dumbbell: a hairline track, a ring where a balance was,
   a dot where it is, the move between them in its direction's colour. */
.rp-track-line { stroke: var(--chart-track); stroke-width: 2px; }
.rp-then { fill: var(--chart-surface); stroke: var(--muted); stroke-width: 1.5px; }
.rp-chart .rp-row-note.rp-in, .rp-chart .rp-row-note.rp-out { fill: currentColor; }
.rp-key.rp-then-key { background: none; border: 1.5px solid var(--muted); border-radius: 50%; }
.rp-key.rp-now-key { color: var(--ink); border-radius: 50%; }
.rp-chart .rp-then-now { fill: var(--muted); font-size: 12px; font-weight: 500; }
@media (max-width: 560px) { .rp-dumbbell .rp-then-now { display: none; } }
/* rp:end */

/* shn:start - WO-085: the navigator. A line at the top when an answer takes
   longer than 150 ms (item 7): a transition, never an animation, so it is not
   counted as the screen arriving; still under reduced motion. */
.sh-line { position: fixed; top: 0; right: 0; left: 0; z-index: 400; height: 2px; background: var(--gold); transform: scaleX(0); transform-origin: 0 50%; transition: transform 2s cubic-bezier(.1, .7, .3, 1); pointer-events: none; }
.sh-line.is-on { transform: scaleX(.85); }
@media (prefers-reduced-motion: reduce) { .sh-line { transition: none; } .sh-line.is-on { transform: scaleX(1); } }
/* shn:end */

/* st:start ------- reports: the stage - WO-079 (docs/DESIGN.md §10) -------
   One pattern for a report screen: a toolbar, one sentence, tiles at 92 px
   and a stage - views, a plot, a panel - all of it whole on a 1366x768
   laptop: top bar 54, padding 20, head 56, sentence 36, tiles 92 (to 125 when
   a change runs long), three gaps of 12, stage 400 at least - a floor, so a
   screen's views keep one height, which every view here fits inside.
   `tools/page_census.py --fold` measures it. One scroll:
   nothing here scrolls inside the page but the views' strip on a phone. */
.st-screen .app-main > .container { padding-top: 20px; }
.st-root { display: grid; gap: var(--sp-3); min-width: 0; }
.st-root > .pg-head { margin-bottom: 0; }
.st-toolbar { flex-wrap: nowrap; align-items: center; min-height: 56px; }
.st-toolbar .pg-head-main { flex: 1 1 auto; }
.st-toolbar .pg-context { max-width: none; margin-top: 3px; }
.st-opens { color: var(--gold-ink); font-weight: 600; }
.st-tools { flex: 0 0 auto; flex-wrap: nowrap; }
.st-tools .rp-period { flex-wrap: nowrap; }
.st-choice .form-control { max-width: 170px; }
.rp-period-vs { font-size: var(--fs-small); color: var(--muted); }
.st-export { gap: 6px; }
.st-caret { width: 6px; height: 6px; margin-top: -3px; border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: rotate(45deg); }
/* The page under the toolbar: the sentence, the tiles, the stage, 12 px apart. */
:is(.st-page, .st-lite).report { gap: var(--sp-3); }
.st-sentence { display: flex; align-items: center; gap: var(--sp-2) var(--sp-4); min-height: 36px; }
.st-sentence .rp-headline { flex: 1 1 auto; max-width: none; font-size: 14px; line-height: 18px; }
.st-sentence .rp-caveats { position: relative; flex: 0 0 auto; }
/* The caveats open over the stage, not above it: a list that pushed the
   stage down would move the thing the reader came to look at. */
.st-sentence .rp-caveat-list { position: absolute; top: calc(100% + 6px); right: 0; z-index: 25; width: min(560px, calc(100vw - 32px)); box-shadow: var(--shadow-md); }
/* Tiles at 92 px: the label and a six-period spark on one line, the figure,
   its change. The figure is still the largest text on the card. */
/* `.st-lite` is Performance (item 9): the toolbar and these tiles, nothing else. */
:is(.st-page, .st-lite) .rp-kpis { grid-template-columns: repeat(auto-fit, minmax(min(100%, 180px), 1fr)); }
:is(.st-page, .st-lite) .rp-kpis > .rp-kpi {
    display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-rows: 20px 30px auto;
    column-gap: var(--sp-2); row-gap: 2px; min-height: 92px; padding: 12px 16px 8px;
    animation: rp-rise .45s ease-out both;
}
/* The label keeps the tile's whole width: five tiles abreast leave a label
   no room beside a spark, and a label broken over three lines is not read. */
:is(.st-page, .st-lite) .rp-kpi-label { grid-column: 1 / -1; grid-row: 1; min-width: 0; }
:is(.st-page, .st-lite) .rp-kpi-value { grid-column: 1 / -1; grid-row: 2; font-size: clamp(1.05rem, 11cqi, 24px); line-height: 30px; }
:is(.st-page, .st-lite) .rp-kpi-foot { grid-column: 1; grid-row: 3; line-height: 16px; }
:is(.st-page, .st-lite) .rp-kpi-spark { grid-column: 2; grid-row: 3; align-self: end; width: 64px; margin: 0; padding: 0; }
/* A swapped page does not arrive again: nothing redraws from nought. */
.is-swapped .rp-kpi, .is-swapped .rp-grow, .is-swapped .rp-grow-down, .is-swapped .rp-grow-x,
.is-swapped .rp-grow-fade, .is-swapped .rp-draw, .is-swapped .rp-draw-arc { animation: none; }
/* A keyed mark moves from its own box (reports.js, Change). */
.st [data-key] { transform-box: fill-box; }
/* The presentable rules on a screen (WO-079 item 2; a document keeps its
   own): a column is 44 px wide at most, centred in its band; figures in
   a chart are tabular, so a column of them lines up. */
.st-page .rp-bars .rp-bar { width: min(45%, 44px); x: calc(50% - min(22.5%, 22px)); }
.st-page .rp-chart text { font-variant-numeric: tabular-nums; }
/* The stage: a hairline panel, as the tiles are; no shadow on a report. */
.st { display: grid; grid-template-rows: auto 1fr; min-width: 0; min-height: 400px; border: 1px solid var(--border); border-radius: var(--rp-radius); background: var(--surface); }
.st:focus { outline: none; }
.st:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
.st-bar { display: flex; align-items: center; gap: var(--sp-4); min-height: 44px; padding: 0 var(--sp-3); border-bottom: 1px solid var(--border); }
.st-views { display: flex; gap: var(--sp-1); min-width: 0; }
.st-view { position: relative; display: inline-flex; align-items: center; height: 44px; padding: 0 var(--sp-3); color: var(--muted); font-size: var(--fs-body); font-weight: 600; text-decoration: none; white-space: nowrap; }
.st-view:hover { color: var(--ink); }
.st-view.is-on { color: var(--ink); }
.st-view.is-on::after { content: ""; position: absolute; right: var(--sp-3); bottom: -1px; left: var(--sp-3); height: 2px; border-radius: 2px; background: var(--gold); }
.st-view:focus-visible { outline: 2px solid var(--gold); outline-offset: -6px; border-radius: 10px; }
.st-cover { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; margin-left: auto; }
.st-cover-strip { width: clamp(120px, 20vw, 250px); }
.st-cover-note { font-size: var(--fs-small); color: var(--muted); font-variant-numeric: var(--num); white-space: nowrap; }
.st-body { display: grid; grid-template-columns: minmax(0, 1fr) 300px; min-height: 356px; }
.st-body.is-full { grid-template-columns: minmax(0, 1fr); }
.st-body.has-wide-panel { grid-template-columns: minmax(0, 1fr) 380px; }
.st-plot { min-width: 0; padding: var(--sp-4) var(--sp-5); }
.st-panel { min-width: 0; padding: var(--sp-4); border-left: 1px solid var(--border); border-radius: 0 0 var(--rp-radius) 0; background: var(--surface-2); }
/* The panel: the chosen mark's name, its figure, and its records. */
.st-pane-head { display: grid; gap: 2px; margin-bottom: var(--sp-3); }
.st-pane-title { margin: 0; font-size: var(--fs-eyebrow); font-weight: 600; letter-spacing: .09em; text-transform: uppercase; color: var(--muted); }
.st-pane-figure { font-size: 22px; font-weight: var(--fw-figure); letter-spacing: -0.02em; line-height: 1.2; font-variant-numeric: var(--num); color: var(--ink); }
.st-pane-note { margin: 0; font-size: var(--fs-small); line-height: 1.4; color: var(--muted); }
.st-pane-more { display: inline-block; margin-top: var(--sp-2); font-size: var(--fs-small); font-weight: 600; }
.st-records { display: grid; margin: 0; padding: 0; list-style: none; }
.st-rec + .st-rec { border-top: 1px solid var(--border); }
.st-rec-link { display: grid; gap: 2px; padding: 7px 0; color: var(--ink); text-decoration: none; }
a.st-rec-link:hover .st-rec-name, a.st-rec-link:focus-visible .st-rec-name { color: var(--info); }
.st-rec-name { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 var(--sp-2); min-width: 0; font-size: var(--fs-body); font-weight: 600; overflow-wrap: anywhere; }
.st-rec-sub { font-size: var(--fs-small); font-weight: 400; color: var(--muted); }
.st-rec-facts { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1) var(--sp-2); font-size: var(--fs-small); font-variant-numeric: var(--num); color: var(--muted); }
.st-rec-amount { font-weight: 600; color: var(--ink); }
.st-none { margin: 0; font-size: var(--fs-small); line-height: 1.45; color: var(--muted); }
/* A pane's figures as lines: a name and its figure, the total ruled above. */
.st-figs { display: grid; margin: 0; }
.st-fig { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 0 var(--sp-3); padding: 6px 0; border-top: 1px solid var(--border); }
.st-fig:first-child { border-top: 0; }
.st-fig dt { color: var(--muted); font-size: var(--fs-body); }
.st-fig dd { margin: 0; font-weight: 600; font-variant-numeric: var(--num); color: var(--ink); white-space: nowrap; }
.st-fig.is-total { border-top: 1px solid var(--border-strong); }
.st-fig.is-total dt, .st-fig.is-total dd { color: var(--ink); font-weight: 800; }
.st-fig-note { flex-basis: 100%; margin: 2px 0 0; font-size: var(--fs-small); line-height: 1.4; color: var(--muted); }
.st-figs.is-ratios dd { font-size: var(--fs-lead); }
/* A list of accounts: a line each, the figure beside its name whatever the
   name's length - a long name wraps in its own column, never the figure. */
.st-figs.is-dense .st-fig { flex-wrap: nowrap; align-items: baseline; padding: 5px 0; line-height: 19px; }
.st-figs.is-dense dt { min-width: 0; overflow-wrap: anywhere; font-size: var(--fs-small); }
.st-figs.is-dense dd { flex: none; font-size: var(--fs-small); }
.st-more { margin-top: var(--sp-2); font-size: var(--fs-small); color: var(--muted); }
.st-more summary { cursor: pointer; font-weight: 600; color: var(--navy-lighter); }
.st-more ol { margin: var(--sp-2) 0 0; padding-left: 18px; line-height: 1.45; }
.st-plot-title { margin: 0 0 var(--sp-2); font-size: var(--fs-body); font-weight: 600; color: var(--ink); }
/* A night nobody read: an outlined stub, never a bar of nought. */
.rp-hollow { fill: none; stroke: var(--border-strong); stroke-width: 1.5px; stroke-dasharray: 3 2; }
/* The trial balance's window, in the toolbar, and the table showing only the
   accounts on the unusual side (WO-079 item 5) - the rest are still in every
   total, as a quiet row is. */
.st-window { align-items: center; }
.st-window .form-control { width: 150px; }
.rp-stmt.is-only-unusual .rp-stmt-row:not(.is-unusual) { display: none; }
/* A line's months, under its figure in a pane (WO-079 item 4). */
.st-pane-trend { margin: 0 0 var(--sp-2); }
/* A stage's full table: 32 px a row, the group heads as tight as the rows. */
.st-page .rp-stmt td, .st-page .rp-stmt th { height: 32px; padding-top: 6px; padding-bottom: 6px; line-height: 20px; }
.st-page .rp-stmt .rp-stmt-group-head th, .st-page .rp-stmt .rp-stmt-group-head td { padding-top: 10px; }
.st-page .rp-stmt-heading td { padding-top: 10px; }
.st-page .rp-fold { min-height: 20px; }
/* Budgets on the stage (WO-079 item 7): the form's rows at 40 px, each side
   folded to its total; the account chosen underlined in gold; the Save bar
   under the stage, never over a row; the year's cells tinted by the actual
   against the budget - green on or better, amber near, red off. */
.st-page .bdg-table { min-width: 0; width: 100%; table-layout: fixed; }
.st-page .bdg-table thead th:nth-child(1) { width: 28%; }
.st-page .bdg-table thead th:nth-child(2) { width: 19%; }
.st-page .bdg-table thead th:nth-child(3) { width: 15%; }
.st-page .bdg-table thead th:nth-child(4) { width: 38%; }
.st-page .bdg-table .bdg-input { width: 100%; }
.st-page .bdg-head .bdg-count { display: block; margin: 0 0 0 17px; }
@media (max-width: 768px) {
    /* A phone keeps the form's natural width and swipes it inside its wrapper. */
    .st-page .bdg-table { table-layout: auto; min-width: 600px; }
}
.st-page .bdg-row td { height: 40px; padding-top: 4px; padding-bottom: 4px; }
.st-page .bdg-head th, .st-page .bdg-head td { height: 40px; }
.bdg-count { margin-left: var(--sp-3); font-size: var(--fs-small); font-weight: 500; color: var(--muted); }
.bdg-account { color: var(--ink); text-decoration: none; font-weight: 500; }
.bdg-account:hover { color: var(--info); }
.bdg-account.is-picked { font-weight: 700; box-shadow: inset 0 -2px 0 var(--gold); }
.st-page .bdg-ytd { min-width: 150px; }
.st-page .bdg-ytd .rp-empty { padding: 0; background: none; text-align: left; font-size: var(--fs-small); line-height: 1.3; }
.st-page .bdg-ytd-line { display: grid; grid-template-columns: minmax(80px, 1fr) auto; align-items: center; gap: var(--sp-2); }
.st-page .bdg-ytd-figures { margin-top: 0; line-height: 14px; white-space: nowrap; }
.st-page .bdg-input { height: 32px; min-height: 32px; padding: 4px 10px; }
.st-page .bdg-bar { position: static; display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-3); margin-top: var(--sp-3); padding: 0; border: 0; background: none; box-shadow: none; }
.bdg-grid th[scope="row"] { font-weight: 500; white-space: nowrap; }
.bdg-grid th[scope="row"] a { color: var(--ink); text-decoration: none; }
.bdg-cell { font-size: var(--fs-small); font-variant-numeric: var(--num); color: var(--muted); }
.bdg-cell.is-on { background: color-mix(in srgb, var(--success) 14%, transparent); color: var(--ink); }
.bdg-cell.is-near { background: color-mix(in srgb, var(--warning) 16%, transparent); color: var(--ink); }
.bdg-cell.is-off { background: color-mix(in srgb, var(--danger) 14%, transparent); color: var(--ink); }
.bdg-key { display: inline-block; padding: 1px 8px; border-radius: 6px; }
/* Where guests come from on the stage (WO-079 item 8): a channel a row at
   40 px, its track in the series colour - gold is the chosen channel's alone -
   and the month's columns held to 44 px like every column on a stage. */
.st-page .sm-rank { width: 100%; min-width: 0; table-layout: fixed; }
.sm-rank .sm-col-name { width: 22%; }
.sm-rank .sm-col-track { width: 23%; }
.sm-rank .sm-col-num { width: 11%; }
.sm-rank td, .sm-rank th { height: 40px; padding-top: 4px; padding-bottom: 4px; }
.sm-rank .sm-channel { overflow-wrap: anywhere; }
.sm-name { color: var(--ink); text-decoration: none; font-weight: 600; }
.sm-name:hover { color: var(--info); }
.sm-name.is-plain { font-weight: 500; font-style: italic; color: var(--muted); }
.sm-rank .sm-bar { height: 8px; border-radius: 4px; background: var(--chart-track); }
.sm-rank .sm-bar > i { background: var(--chart-1); border-radius: 4px; }
.sm-rank .sm-row.is-picked { background: color-mix(in srgb, var(--gold) 9%, transparent); }
.sm-rank .sm-row.is-picked .sm-bar > i { background: var(--gold); }
.sm-rank .badge { margin-left: var(--sp-2); }
.st-page .rp-stacked_columns .rp-bar { width: min(45%, 44px); x: calc(50% - min(22.5%, 22px)); }
@media (max-width: 768px) { .st-page .sm-rank { table-layout: auto; min-width: 620px; } }
/* Two charts that belong together, side by side on a laptop. */
.mo-pair { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr)); gap: var(--sp-5); }
@media (max-width: 1100px) {
    .st-body, .st-body.has-wide-panel { grid-template-columns: minmax(0, 1fr); }
    .st-panel { border-top: 1px solid var(--border); border-left: 0; border-radius: 0 0 var(--rp-radius) var(--rp-radius); }
}
@media (max-width: 900px) {
    .st-toolbar { flex-wrap: wrap; }
    .st-tools { flex-wrap: wrap; width: 100%; }
}
/* A bridge's change sits beside its figure on a laptop; on a phone the label
   needs that room, so the change goes (it is in the tooltip and the panel)
   and the figure slides into its place. */
@media (max-width: 560px) {
    .rp-bridge .rp-row-note { display: none; }
    .rp-bridge .rp-row-value.has-note { transform: translateX(72px); }
}
/* Phone: tiles two by two, the views a strip that scrolls inside itself, the
   panel under the plot, nothing wider than the screen. */
@media (max-width: 768px) {
    .st-sentence { flex-wrap: wrap; }
    .st-sentence .rp-caveats { position: static; }
    .st-sentence .rp-caveat-list { position: static; width: auto; box-shadow: none; }
    :is(.st-page, .st-lite) .rp-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    /* A switch of five (Performance's nights) is wider than a phone: it takes
       the row and wraps, each option as wide as its row allows. */
    .st-tools > .st-scope { display: flex; flex-wrap: wrap; width: 100%; }
    .st-scope .seg-opt { flex: 1 1 auto; text-align: center; }
    .st-bar { flex-wrap: wrap; gap: 0; padding: 0; }
    .st-views { width: 100%; padding: 0 var(--sp-1); overflow-x: auto; scrollbar-width: none; }
    .st-cover { width: 100%; margin: 0; padding: var(--sp-2) var(--sp-3); border-top: 1px solid var(--border); }
    .st-cover-strip { flex: 1 1 auto; width: auto; }
    .st-plot { padding: var(--sp-3); }
    .st-panel { padding: var(--sp-3); }
    /* The trial balance's window: the two dates side by side, Show under them. */
    .st-tools > .st-window { display: grid; flex: 1 1 100%; grid-column: 1 / -1; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); gap: var(--sp-2); width: 100%; }
    .st-window .form-control { width: 100%; }
    .st-window .btn { grid-column: 1 / -1; }
}
/* fam:start - WO-084: a family's screens in the stage's view row. Each
   member's group named small, its views beside it, a hairline between the
   groups; the open member's name in gold. A sibling's view is a link to its
   own address, which reports.js swaps in place like any other view. */
.st-fam { align-items: center; }
.st-fam-part { display: inline-flex; align-items: center; gap: var(--sp-1); }
.st-fam-part + .st-fam-part { margin-left: var(--sp-2); padding-left: var(--sp-2); border-left: 1px solid var(--border); }
.st-fam-group { padding: 0 var(--sp-1); font-size: var(--fs-eyebrow); font-weight: 600; letter-spacing: .09em; text-transform: uppercase; white-space: nowrap; color: var(--muted); }
.st-fam-part.is-open .st-fam-group { color: var(--gold-ink); }
/* A member with no stage (Performance, Targets) draws the strip on its own,
   as the stage's view row would look. */
.st-fam-bar { display: flex; align-items: center; min-width: 0; min-height: 44px; padding: 0 var(--sp-3); border: 1px solid var(--border); border-radius: var(--rp-radius); background: var(--surface); }
/* A grid's one column is as wide as its widest content unless it is told
   otherwise, and a family's strip on a phone is wider than the phone: the
   column is the screen's, and the strip scrolls inside itself. */
.st, .st-root { grid-template-columns: minmax(0, 1fr); }
/* Month's one sentence of the two sources (item 4): why the modules' revenue
   is not the books', under the page's own sentence and inside its row - the
   row is 36 px and a one-line headline takes 18, so the stage does not move. */
.st-said { display: grid; flex: 1 1 auto; min-width: 0; }
/* A family's strip is wider than a screen's own views: it keeps its width,
   the coverage beside it narrows, and a bar too narrow for both puts the
   coverage under the strip rather than over its last view. */
.st-bar.has-fam { flex-wrap: wrap; row-gap: 0; }
.st-bar.has-fam .st-fam { flex: 0 0 auto; max-width: 100%; }
.st-bar.has-fam .st-cover-strip { width: clamp(72px, 8vw, 120px); }
.st-two { margin: 0; font-size: var(--fs-small); line-height: 18px; color: var(--muted); font-variant-numeric: var(--num); }
/* Reports home (item 7): a card a family, its views under a hairline. */
.rp-fam-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr)); gap: 12px; }
.rp-fam-card .rp-report-name { text-decoration: none; }
.rp-fam-card .rp-report-name:hover, .rp-fam-card .rp-report-name:focus-visible { color: var(--gold-ink); }
.rp-fam-views { display: flex; flex-wrap: wrap; gap: 6px 16px; margin-top: var(--sp-2); padding-top: var(--sp-2); border-top: 1px solid var(--border); font-size: var(--fs-small); }
.rp-fam-group { display: inline-flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; }
.rp-fam-group b { font-size: var(--fs-eyebrow); font-weight: 600; letter-spacing: .09em; text-transform: uppercase; color: var(--muted); }
/* fam:end */
/* st:end */

/* ---------------------------------------------------------------------------
   banking: the cash statement - WO-062 item 7

   The sheet's own few shapes, which the kit does not carry: money in and money
   out keep their colour in a column of figures, a mode sits indented under its
   total with its line count, and two tables are narrow because they are two
   columns of figures rather than a list.
   --------------------------------------------------------------------------- */
.cf-in { color: var(--success); }
.cf-out { color: var(--danger); }
.cf-indent { padding-left: 24px; }
.cf-count { color: var(--muted); font-size: .82em; }
.cf-plain { font-weight: 400; }
.cf-narrow { max-width: 640px; }
.cf-slim { max-width: 520px; }
.cf-amount { max-width: 180px; }

/* By status and Week (WO-061 item 9). By status: a card a status, its windows
   wrapping inside. Week: a table of rooms by day, each cell in the swatch of
   the last status given that day, with the initials of who gave it. */
.hk-status-board { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 1fr)); gap: 12px; align-items: start; }
.hk-status-column { padding: 12px; }
.hk-status-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin: 0 0 10px; font-size: 1em; }
.hk-status-head strong { font-variant-numeric: tabular-nums; color: var(--muted); }
.hk-status-column .hk-windows { grid-template-columns: repeat(auto-fill, minmax(56px, 1fr)); }
.hk-week-toolbar { display: flex; flex-direction: column; gap: 10px; }
.hk-week-toolbar .status-pill { font-size: .8em; min-height: 24px; }
table.data-table.hk-week { min-width: 560px; }
.hk-week th.hk-week-day { text-align: center; white-space: nowrap; }
.hk-week tr.hk-week-floor th { background: var(--surface-2); color: var(--navy); font-weight: 800; text-align: left; }
.hk-week th.hk-week-room { font-variant-numeric: tabular-nums; font-weight: 700; white-space: nowrap; }
.hk-week td.hk-week-cell { position: relative; text-align: center; font-size: .78em; font-weight: 800; letter-spacing: .02em; padding: 6px 4px; border-left: 1px solid var(--border); }
.hk-week td.hk-week-cell[class*="swatch-"] { background: var(--sw-bg); color: var(--sw-ink); box-shadow: inset 3px 0 0 var(--sw-edge); }
/* A view name of two words stays on one line when the toggle shares a header (WO-061 item 9). */
.view-toggle a { white-space: nowrap; }

/* Floor Assignments by taps (WO-061 item 10): people as chips, floors as
   cards; the chosen one is ringed in navy, what it is joined to is tinted gold. */
.hk-assign { display: flex; flex-direction: column; gap: 12px; }
.hk-assign-people { display: flex; flex-wrap: wrap; gap: 6px; }
.hk-tap-person { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; padding: 4px 12px 4px 4px; border-radius: 999px; border: 2px solid var(--border); background: var(--surface); color: var(--ink); font: inherit; font-size: .9em; cursor: pointer; }
.hk-tap-name { font-weight: 700; }
.hk-tap-load { color: var(--muted); font-size: .88em; font-variant-numeric: tabular-nums; }
.hk-assign-floors { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 210px), 1fr)); gap: 8px; }
.hk-tap-floor { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; min-height: 76px; padding: 10px 12px; border-radius: var(--radius-sm); border: 2px solid var(--border); background: var(--surface); color: var(--ink); font: inherit; text-align: left; cursor: pointer; }
.hk-tap-floor-name { font-weight: 800; color: var(--navy); }
.hk-tap-work { color: var(--muted); font-size: .85em; }
.hk-tap-on { display: inline-flex; flex-wrap: wrap; gap: 3px; min-height: 26px; align-items: center; font-size: .85em; }
.hk-tap-on .person-dot { width: 26px; height: 26px; font-size: .64rem; }
.hk-tap-person[aria-pressed="true"], .hk-tap-floor[aria-pressed="true"] { border-color: var(--navy); box-shadow: 0 0 0 2px var(--navy); }
.hk-tap-person.is-on, .hk-tap-floor.is-on { border-color: var(--gold); background: var(--gold-bg); }
.hk-tap-person.is-saved, .hk-tap-floor.is-saved { box-shadow: 0 0 0 3px var(--success); }
.hk-tap-person:disabled, .hk-tap-floor:disabled { cursor: default; }
/* Spread evenly (WO-064 item 4): a button that says what it would propose -
   the people over the floors nobody is on - and the proposal opens under it. */
.hk-spread > summary.hk-spread-button { list-style: none; display: inline-flex; flex-wrap: wrap; align-items: baseline; gap: 0 6px; max-width: 100%; min-height: 44px; white-space: normal; text-align: left; }
.hk-spread > summary.hk-spread-button::-webkit-details-marker { display: none; }
.hk-spread[open] > summary.hk-spread-button { border-color: var(--navy); color: var(--navy); }
.hk-spread-counts { font-weight: 500; color: var(--muted); }
.hk-spread-counts::before { content: "\00B7\00A0"; }
.hk-spread-body { margin-top: 8px; }

/* The housekeeper's phone (WO-061 item 11): a ring of her rooms done, then
   Start above Cleaned on a waiting room. */
.hk-progress { display: flex; align-items: center; gap: 14px; padding: 12px 16px; margin-bottom: 14px; }
.hk-ring { width: 64px; height: 64px; flex: 0 0 auto; transform: rotate(-90deg); }
.hk-ring-track { stroke: var(--neutral-bg); stroke-width: 4; }
.hk-ring-done { stroke: var(--success); stroke-width: 4; stroke-linecap: round; transition: stroke-dasharray .3s; }
.hk-progress-text { margin: 0; font-size: 1.15em; color: var(--muted); }
.hk-progress-text strong { font-size: 1.6em; color: var(--ink); font-variant-numeric: tabular-nums; }
.hk-start-form { padding: 0 14px 10px; }

/* My Floors, phone first (WO-066 item 3): one open card a room; the minutes in
   its status beside the status; Photo as the big button before Cleaned, the
   file input itself hidden behind its label. On a laptop the list is two
   columns with her floors beside it; on a phone the floors are the page head. */
.hk-room-head { cursor: default; }
.hk-room-minutes { color: var(--muted); font-weight: 600; font-variant-numeric: tabular-nums; }
.hk-room-minutes::before { content: "\00B7\00A0"; }
.hk-room-retry { color: var(--ink); font-weight: 600; }
.hk-clean-form { position: relative; display: grid; gap: 8px; }
.hk-photo-input { position: absolute; width: 1px; height: 1px; opacity: 0; overflow: hidden; }
.hk-photo-pick { display: flex; align-items: center; justify-content: center; cursor: pointer; }
.hk-photo-pick.has-photo { border-color: var(--success); color: var(--success); }
.hk-mine-page { display: grid; grid-template-columns: minmax(0, 1fr); gap: 14px; }
.hk-floor-summary { display: none; }
.hk-floor-lines { margin: 0; padding: 0; list-style: none; display: grid; gap: 8px; }
.hk-floor-lines li { display: grid; gap: 2px; }
/* The phone's banner (WO-066 item 4): a note written on one of her rooms, on
   top of the page until she says OK. */
.hk-banners { display: grid; gap: 8px; margin-bottom: 12px; }
.hk-banner { display: flex; align-items: center; gap: 10px; padding: 10px 12px; border-radius: var(--radius-sm); border: 1px solid var(--border); border-left: 4px solid var(--warning); background: var(--warning-bg); }
.hk-banner p { flex: 1 1 auto; min-width: 0; margin: 0; font-weight: 600; overflow-wrap: anywhere; }
@media (min-width: 1024px) {
    .hk-mine-page { grid-template-columns: minmax(0, 1fr) 280px; align-items: start; }
    .hk-mine-side { grid-column: 2; grid-row: 1; position: sticky; top: 16px; }
    .hk-mine-main { grid-column: 1; grid-row: 1; min-width: 0; }
    .hk-floor-summary { display: block; }
    .hk-mine-main .hk-mine { grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: start; }
}

/* Staff meals, item 13: Undo for one's own tap for two minutes; ticks for
   Add to many, shown only while ticking, with the go button in the footer. */
.meal-undo { min-height: 36px; }
.meal-tick { display: none; align-items: center; justify-content: center; width: 32px; min-height: 44px; cursor: pointer; }
.meal-tick input { width: 22px; height: 22px; margin: 0; }
.meals-day.is-ticking .meal-tick { display: inline-flex; }
.meals-day.is-ticking .meal-tap, .meals-day.is-ticking .meal-less { display: none; }
.meal-heading-row { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 6px 12px; }
.meal-many-bar { display: inline-flex; flex-wrap: wrap; gap: 6px; margin-left: auto; }
[data-add-many][aria-pressed="true"] { background: var(--navy); border-color: var(--navy); color: #fff; }

/* hk-mine:start ---------------- housekeeping: My Floors, one card open (WO-069) ----------------
   Every room is a fold (`.hk-fold`): one line (`.hk-line`) - the number, the status in its
   colour, the minutes, *by 13:00*, a note mark - that opens to the card (`.hk-open`), the
   desk's note first in its own box, red when urgent. One is open at a time. These rules come
   after the older hk- ones and win by order; the WO-069 rules live between these markers. */
.hk-mine { gap: 6px; }
.hk-fold > .hk-line { display: flex; align-items: center; gap: 10px; min-height: 52px; padding: 6px 14px; cursor: pointer; list-style: none; }
.hk-fold > .hk-line::-webkit-details-marker { display: none; }
.hk-line .hk-room-number { min-width: 3.2em; font-size: 1.25rem; }
.hk-line .hk-room-status { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hk-line-by { flex: 0 0 auto; color: var(--gold-ink); font-size: .9em; font-weight: 700; font-variant-numeric: tabular-nums; }
.hk-note-mark { flex: 0 0 auto; width: 12px; height: 12px; border-radius: 50%; background: var(--warning); }
.hk-note-mark.is-urgent { background: var(--danger); box-shadow: 0 0 0 3px var(--danger-bg); }
.hk-fold[open] > .hk-line { min-height: 60px; }
.hk-fold[open] > .hk-line .hk-room-number { font-size: 2rem; }
.hk-open { display: grid; gap: 10px; padding: 0 14px 14px; }
.hk-open > p { margin: 0; }
/* The older card's grid areas mean nothing here, and a named area in a grid without it adds a column. */
.hk-open > *, .hk-line > * { grid-area: auto; }
.hk-open .hk-room-floor { font-size: .82em; }
.hk-open .hk-start-form, .hk-open .hk-clean-form, .hk-open .hk-room-small { padding: 0; }
.hk-note-box { padding: 10px 12px; border-radius: var(--radius-sm); border-left: 4px solid var(--warning); background: var(--warning-bg); color: var(--ink); font-size: 1.05em; font-weight: 600; overflow-wrap: anywhere; }
.hk-note-box.is-urgent { border-left-color: var(--danger); background: var(--danger-bg); }
.hk-note-who { display: block; margin-bottom: 2px; color: var(--muted); font-size: .78em; font-weight: 700; }
.hk-note-box.is-urgent .hk-note-who { color: var(--danger); }
/* Item 2: one big button. Photo until the input holds one, then Cleaned (and the note); the
   Photo button steps back to a small Retake. `:has()` does it without a script. */
.hk-clean-form:has(.hk-photo-input:invalid) .hk-after-photo { display: none; }
.hk-after-photo { display: grid; gap: 8px; }
.hk-clean-form:has(.hk-photo-input:valid) .hk-photo-pick { min-height: 40px; background: var(--surface); border-color: var(--success); color: var(--success); font-size: .92em; }
/* The three chips, each a bottom sheet: the chip is the fold's line, its ::before the dimmed
   page that closes it, the body pinned to the foot of the screen above the tab bar. */
.hkm-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.hkm-sheet > .hkm-chip { display: inline-flex; align-items: center; min-height: 44px; padding: 0 18px; border: 1px solid var(--border-strong); border-radius: 999px; background: var(--surface); color: var(--navy); font-weight: 700; cursor: pointer; list-style: none; }
.hkm-sheet > .hkm-chip::-webkit-details-marker { display: none; }
.hkm-sheet[open] > .hkm-chip { background: var(--navy); border-color: var(--navy); color: #fff; }
.hkm-sheet[open] > .hkm-chip::before { content: ""; position: fixed; inset: 0; z-index: 40; background: rgba(15, 23, 42, .45); cursor: default; }
.hkm-sheet-body { position: fixed; left: 0; right: 0; bottom: 0; z-index: 41; display: grid; gap: 12px; max-height: 85vh; overflow-y: auto; padding: 18px 16px calc(18px + env(safe-area-inset-bottom)); border-radius: 16px 16px 0 0; background: var(--surface); box-shadow: 0 -8px 30px rgba(15, 23, 42, .25); }
.hkm-sheet-title { margin: 0; font-size: 1.15em; font-weight: 800; }
.hkm-sheet-room { margin-left: 6px; color: var(--muted); font-weight: 600; }
.hkm-sheet-form { display: grid; gap: 10px; }
.hkm-kinds { display: flex; flex-wrap: wrap; gap: 8px; }
.hkm-kind { min-height: 48px; padding: 0 18px; border: 1px solid var(--border-strong); border-radius: 999px; background: var(--surface-2); color: var(--ink); font: inherit; font-weight: 700; cursor: pointer; }
.hkm-kind:active { background: var(--navy); color: #fff; }
.hkm-sheet-close { display: none; }
[data-hk-mine].is-live .hkm-sheet-close { display: flex; justify-content: center; }
/* Item 5: Fix's kinds of job are chips to pick (a radio behind each), then two ticks. */
.hkm-pick { display: inline-flex; align-items: center; }
.hkm-pick input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.hkm-pick:has(input:checked) { background: var(--navy); border-color: var(--navy); color: #fff; }
.hkm-pick:has(input:focus-visible) { outline: 2px solid var(--navy); outline-offset: 2px; }
.hkm-ticks { display: flex; flex-wrap: wrap; gap: 8px 18px; }
.hkm-tick { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; font-weight: 700; }
.hkm-tick input { width: 22px; height: 22px; margin: 0; }
/* A maintenance job open on the room (WO-067 item 5): a wrench on its line, a line inside. */
.hkm-job-mark { flex: 0 0 auto; display: inline-flex; width: 18px; height: 18px; color: var(--muted); }
.hkm-job-mark svg { width: 100%; height: 100%; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.hkm-job-mark.is-urgent { color: var(--danger); }
.hkm-job { padding: 6px 10px; border-radius: var(--radius-sm); border-left: 4px solid var(--border-strong); background: var(--surface-2); font-size: .92em; font-weight: 600; }
.hkm-job.is-urgent { border-left-color: var(--danger); color: var(--danger); }
/* Item 3: the next room scrolls into view under the top bar; an urgent note's banner is red. */
.hk-room { scroll-margin-top: calc(var(--topbar-h) + 12px); }
.hk-banner.is-urgent { border-left-color: var(--danger); background: var(--danger-bg); }
/* Item 4: the runner's Requests on the same cards - a line, one open, one big button. */
.hk-request { padding: 0; }
.hk-requests { gap: 6px; }
.hk-line .hk-request-what { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hk-request-age { flex: 0 0 auto; color: var(--muted); font-weight: 700; font-variant-numeric: tabular-nums; }
.hk-request-age.is-late { color: var(--danger); }
.hk-request-words { font-weight: 600; overflow-wrap: anywhere; }
.hk-request-who, .hk-request-state { font-size: .9em; }
.hk-request-small { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 8px; }
.hk-request-small .btn { min-height: 44px; }
@media (min-width: 1024px) {
    .hk-requests { grid-template-columns: minmax(0, 480px); }
}
@media (min-width: 1024px) {
    .hkm-sheet-body { left: 50%; right: auto; width: 480px; transform: translateX(-50%); }
}
@media (min-width: 1024px) {
    /* A laptop: the same list at phone width, beside her floors. */
    .hk-mine-page { grid-template-columns: minmax(0, 480px) 280px; justify-content: start; }
    .hk-mine-main .hk-mine { grid-template-columns: minmax(0, 1fr); }
}
/* hk-mine:end */

/* WO-071 item 7: the runner and the technicians on one strip at the top of
   Floor Assignments, where the Jobs Board puts the same thing. Two cards under
   the header before, which read as two decisions rather than one line about
   who today's work goes to. */
.hk-duty-strip { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr)); gap: var(--sp-3); margin-bottom: var(--sp-4); }
.hk-duty-said { color: var(--muted); font-size: var(--fs-small); }
.hk-assign-copy { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin-bottom: var(--sp-3); }

/* nt:start ------- where the guests come from, and why it cannot say (WO-071 item 13) -------
   A panel with no figures in it on purpose. It is drawn as plainly as it reads: no
   chart, no percentage, nothing that could be mistaken for a split. */
.nt-missing { padding: var(--sp-4); border: 1px dashed var(--border-strong); border-radius: var(--radius); background: var(--surface-2); }
.nt-why { margin: 0; color: var(--ink-2); }
.nt-said { margin: var(--sp-2) 0 0; color: var(--muted); font-size: var(--fs-small); }
/* nt:end */

/* tg:start ------- targets: where a month stands against its break-even (WO-071 item 12) -------
   The gauge beside the figures, and each figure with the kind of thing it is said under
   it: a fact, a promise, a guess. A month with no break-even typed gets the figures and
   a line saying where to type one - never a gauge against nought. */
.tg-standing { margin-bottom: var(--sp-4); }
.tg-standing-body { display: grid; grid-template-columns: minmax(0, 200px) minmax(0, 1fr); gap: var(--sp-5); align-items: center; }
.tg-gauge { text-align: center; }
.tg-gauge-said { margin-top: var(--sp-2); font-size: var(--fs-small); color: var(--muted); }
.tg-gauge.is-none { padding: var(--sp-4); border: 1px dashed var(--border-strong); border-radius: var(--radius); color: var(--muted); }
.tg-gauge.is-none p { margin: var(--sp-2) 0 0; font-size: var(--fs-small); }
.tg-rows { display: grid; gap: var(--sp-2); margin: 0; }
.tg-rows > div { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-2); padding-bottom: 6px; border-bottom: 1px dashed var(--border); }
.tg-rows > div:last-child { border-bottom: 0; }
.tg-rows dt { flex: 0 0 170px; color: var(--muted); font-size: var(--fs-small); }
.tg-rows dd { margin: 0; min-width: 0; font-variant-numeric: var(--num); }
.tg-said { color: var(--muted-light); font-size: var(--fs-small); font-variant-numeric: normal; }
/* Targets: a card a month, its figures and the boxes to change them. A table
   of five columns with two boxes in it is not a phone screen, and as one this
   ran 150px off the side of a 390. */
.tg-months { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 320px), 1fr)); gap: var(--sp-3); }
.tg-month { display: flex; flex-direction: column; gap: var(--sp-2); padding: 12px 14px; }
.tg-month.is-now { border-color: var(--gold); }
.tg-typed { font-size: var(--fs-small); color: var(--ink-2); font-variant-numeric: var(--num); }
.tg-row { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--sp-2); }
.tg-field { display: flex; flex-direction: column; gap: 2px; flex: 1 1 120px; min-width: 0; margin: 0; }
.tg-field span { font-size: var(--fs-eyebrow); font-weight: 600; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.tg-row .form-control { width: 100%; min-width: 0; }
@media (max-width: 768px) {
    .tg-standing-body { grid-template-columns: minmax(0, 1fr); }
    .tg-rows dt { flex-basis: 100%; }
}
/* tg:end */

/* hd:start ------- the Day per Floor: figures, floor cards, room chips (WO-071 item 6) -------
   The table printed 84 zeros before anything else. It is still the only thing that says
   how many marks of each kind a floor took, and it is what the export is built from, so
   it stays - behind `Show the table`. What opens the page is the figures and the rooms.

   A chip wears the colour of the status the room's last mark of the day set, through the
   same `swatch-*` classes the board uses (a colour is a field on the hotel's RoomStatus,
   not a hard-coded one). A room nobody marked is `.is-unmarked`: plain, because grey is
   not clean. */
.hd-stat .kt-stat-one { padding-left: 12px; border-left: 3px solid var(--sw-edge, var(--border)); }
.hd-floors { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 340px), 1fr)); gap: var(--sp-3); margin-bottom: var(--sp-4); }
.hd-floor { padding: 12px 14px; display: flex; flex-direction: column; gap: var(--sp-2); }
.hd-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-2); }
.hd-head b { font-weight: 600; }
.hd-rooms { color: var(--muted); font-size: var(--fs-small); }
.hd-pills { margin-left: auto; display: flex; flex-wrap: wrap; gap: 5px; }
.hd-who { color: var(--ink-2); font-size: var(--fs-small); }
.hd-who.is-none { color: var(--muted); }
.hd-chips { display: flex; flex-wrap: wrap; gap: 5px; }
.hd-chip {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 42px; height: 26px; padding: 0 6px; border-radius: 6px;
    background: var(--sw-bg, var(--neutral-bg)); color: var(--sw-ink, var(--ink-2));
    font-size: var(--fs-eyebrow); font-weight: 600; font-variant-numeric: var(--num);
}
.hd-chip small { margin-left: 4px; font-size: 10px; font-weight: 500; opacity: 0.85; }
.hd-chip.is-late { box-shadow: inset 0 0 0 2px var(--danger); }
a.hd-chip { text-decoration: none; }
.hd-chip.is-unmarked { background: var(--surface-2); color: var(--muted-light); border: 1px dashed var(--border-strong); }
.hd-chip.is-retired { background: var(--surface-2); color: var(--muted-light); text-decoration: line-through; }
.hd-table > summary { list-style: none; cursor: pointer; }
.hd-table > summary::-webkit-details-marker { display: none; }
.hd-table[open] > summary { margin-bottom: var(--sp-2); }
.hd-table { padding: var(--sp-3) 14px; }
.hd-table-foot { margin: var(--sp-3) 0 0; }
/* hd:end */

/* mk:start ------- maintenance setup: the kinds of job, one a line (WO-071 item 5) -------
   Housekeeping Setup's `.hk-kind-*` did this before and still does its own; these are
   the same shape on the kit, with rename and retire as text and the one thing the page
   is for - adding a kind - the primary at the foot. */
.mk-list { margin: 0; padding: 0; list-style: none; display: grid; }
.mk-kind { border-bottom: 1px solid var(--border); }
.mk-kind:last-child { border-bottom: 0; }
.mk-row {
    display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2);
    min-height: 44px; padding: var(--sp-2) 0;
}
.mk-row .form-control { flex: 1 1 180px; min-width: 0; max-width: 300px; }
.mk-name { flex: 1 1 180px; font-weight: 500; }
.mk-kind.is-retired .form-control, .mk-kind.is-retired .mk-name { color: var(--muted); }
.mk-add { border-top: 1px solid var(--border); margin-top: var(--sp-3); padding-top: var(--sp-3); }
/* mk:end */

/* mj:start ------- maintenance: a job on a card, on the board and on the phone -------
   WO-067 item 6, redrawn on the kit by WO-071 item 4. Two things went: the empty grey
   block every photo-less job drew, and the full-width black button on every card of
   every column. The photo is a 54px thumbnail beside the words and only when there is
   one; one primary a card, with Done and Can't as text that open their form. */
.mj-card { display: flex; flex-direction: column; gap: var(--sp-2); padding: 13px 14px; }
.mj-card.is-urgent { border-left: 3px solid var(--danger); }
.mj-top { display: flex; gap: var(--sp-3); align-items: flex-start; }
.mj-body { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 5px; }
.mj-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-2); }
.mj-where { font-size: var(--fs-lead); font-weight: 600; }
.mj-age { margin-left: auto; color: var(--muted); font-size: var(--fs-small); white-space: nowrap; }
.mj-words { margin: 0; color: var(--ink-2); overflow-wrap: anywhere; }
.mj-pills { display: flex; flex-wrap: wrap; gap: 5px; }
.mj-who { margin: 0; color: var(--muted); font-size: var(--fs-small); }
.mj-thumb { flex: none; width: 54px; height: 54px; border-radius: var(--radius-sm); overflow: hidden; display: block; }
.mj-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.mj-act { display: flex; flex-direction: column; gap: var(--sp-2); }
.mj-give > summary { list-style: none; cursor: pointer; display: inline-flex; }
.mj-give > summary::-webkit-details-marker { display: none; }
.mj-give-menu { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; margin-top: var(--sp-2); padding-top: var(--sp-2); border-top: 1px solid var(--border); }
.mj-act details > summary { list-style: none; cursor: pointer; }
.mj-act details > summary::-webkit-details-marker { display: none; }
.mj-act details[open] > summary { margin-bottom: var(--sp-2); }

/* The on-duty strip over the board: who a new job goes to, and the one tap that
   changes it. */
.mj-duty { display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--sp-3) 18px; margin-bottom: var(--sp-4); }
.mj-duty-line { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.mj-duty-label { font-size: var(--fs-eyebrow); font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); }
.mj-duty-set { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-3); }
.mj-duty-none { margin: 0; color: var(--muted); font-size: var(--fs-small); }

/* My Jobs is one column on every width: it is read on a phone, and a technician
   holding one job does not want it beside two empty ones. */
.mj-list { display: flex; flex-direction: column; gap: var(--sp-3); margin-bottom: var(--sp-5); }
/* mj:end */

/* letterhead:start ------ the letterhead, on the screen it is edited on (WO-070) ------ */
/* The frame holds the real letterhead, rendered by the real partials at the
   width it prints (A4 less the 15mm margins, 180mm ~ 680px) and scaled down to
   fit the card. Scaled rather than redrawn on purpose: an impression of the
   letterhead in this file would be a second letterhead, and the second one is
   always the one that is wrong.

   `static/js/hotels.js` sets the scale and the height from the card's real
   width, because a fixed factor cuts the contact block off the right-hand side
   of a narrow card - which is what the demo showed at 1366. The values here are
   what a card about 300px wide needs, so the frame is right before the script
   runs and right without it.

   `hidden` and not `auto`: this is a picture, not a scroller, and
   `core/tests/test_templates.py` counts scrollers. */
.letterhead-frame {
    width: 100%;
    height: 78px;
    overflow: hidden;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: #fff;
    padding: 8px;
}
.letterhead-frame iframe {
    display: block;
    width: 680px;
    height: 175px;
    border: 0;
    transform: scale(.42);
    transform-origin: top left;
}
/* letterhead:end */

/* rr:start ------- Rate Radar: Reports > Rates (WO-077 item 7) -------
   The published design, `Managment_System/ui-direction/rates-v3.html`, on
   the shell: a command band on white - the hotel, the read, the verdict,
   three night cards - then the street, the matrix, who moved and fourteen
   days. White like the rest of the app (item 9): the band sits on the page's
   white above a hairline, the verdict is a card on the well tint with a gold
   rule, the night cards are white with the kit's shadow.
   Its colours are the kit's where the kit has them; the few it adds are
   here, with their dark values, because the app has no dark theme yet and
   this page draws one (`prefers-color-scheme`, or `data-theme`). Gold is
   ours alone: our point, our row, our price. A place on a scale is a custom
   property set on the element (--x, --y, --h) - the inline style the rule
   allows - and a switch in `rate_radar.js` changes that, never the element. */
.is-radar {
    --rr-ink: var(--navy-deep);
    --rr-paper: var(--surface);
    --rr-card: var(--surface);
    --rr-well: var(--bg);
    --rr-text: var(--ink);
    --rr-muted: var(--muted);
    --rr-faint: var(--muted-light);
    --rr-line: var(--border);
    --rr-line-2: var(--border-strong);
    --rr-gold: var(--gold);
    --rr-gold-2: #E4C176;
    --rr-gold-ink: var(--gold-ink);
    --rr-gold-soft: var(--gold-bg);
    --rr-good: var(--success);
    --rr-good-soft: var(--success-bg);
    --rr-warn: var(--warning);
    --rr-warn-soft: var(--warning-bg);
    --rr-bad: var(--danger);
    --rr-bad-soft: var(--danger-bg);
    --rr-dot: #5E6D93;
    --rr-dot-2: #B9C2D6;
    --rr-h2-edge: #EBD3A3;
    --rr-h3-edge: #EBB8B8;
    --rr-shadow: 0 1px 2px rgba(15, 27, 51, .06), 0 8px 24px -12px rgba(15, 27, 51, .18);
}
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .is-radar {
        --rr-paper: #0C1426;
        --rr-card: #121C33;
        --rr-well: #101A31;
        --rr-text: #E8ECF5;
        --rr-muted: #9AA6C2;
        --rr-faint: #6B7896;
        --rr-line: #1F2B4A;
        --rr-line-2: #2C3A5E;
        --rr-dot: #93A2C8;
        --rr-dot-2: #3C4A6E;
        --rr-gold-soft: #2A2312;
        --rr-gold-ink: #E4C176;
        --rr-good-soft: #122B1F;
        --rr-warn-soft: #2E2412;
        --rr-bad-soft: #331919;
        --rr-h2-edge: #5A4A22;
        --rr-h3-edge: #5C2A2A;
        --rr-shadow: 0 1px 2px rgba(0, 0, 0, .4), 0 8px 24px -12px rgba(0, 0, 0, .6);
    }
}
[data-theme="dark"] .is-radar {
    --rr-paper: #0C1426;
    --rr-card: #121C33;
    --rr-well: #101A31;
    --rr-text: #E8ECF5;
    --rr-muted: #9AA6C2;
    --rr-faint: #6B7896;
    --rr-line: #1F2B4A;
    --rr-line-2: #2C3A5E;
    --rr-dot: #93A2C8;
    --rr-dot-2: #3C4A6E;
    --rr-gold-soft: #2A2312;
    --rr-gold-ink: #E4C176;
    --rr-good-soft: #122B1F;
    --rr-warn-soft: #2E2412;
    --rr-bad-soft: #331919;
    --rr-h2-edge: #5A4A22;
    --rr-h3-edge: #5C2A2A;
    --rr-shadow: 0 1px 2px rgba(0, 0, 0, .4), 0 8px 24px -12px rgba(0, 0, 0, .6);
}
/* The band runs to the edges of the content column, as the design's does. */
body.is-radar .app-main > .container { max-width: none; padding-top: 0; padding-left: 0; padding-right: 0; background: var(--rr-paper); }
.is-radar .container > .flash-message { margin: var(--sp-3) var(--sp-4) 0; }
.rr { color: var(--rr-text); font-size: 14px; line-height: 1.45; }
.rr-num { font-variant-numeric: tabular-nums; }
.rr h1, .rr h2 { font-family: var(--display); font-weight: 600; letter-spacing: -.01em; margin: 0; text-wrap: balance; }
.rr a:focus-visible, .rr button:focus-visible, .rr summary:focus-visible, .rr-sdot:focus-visible { outline: 2px solid var(--rr-gold); outline-offset: 2px; border-radius: 6px; }
.rr-empty { color: var(--rr-muted); margin: var(--sp-3) 0 0; }

/* ---------- the command band ---------- */
.rr-band { position: relative; overflow: hidden; background: var(--rr-card); border-bottom: 1px solid var(--rr-line); color: var(--rr-text); padding-block: 26px 28px; padding-inline: clamp(16px, 4vw, 40px); }
.rr-wrap { position: relative; max-width: 1180px; margin: 0 auto; }
.rr-crumb { display: flex; flex-wrap: wrap; gap: 8px 16px; align-items: center; color: var(--rr-muted); font-size: 12px; letter-spacing: .06em; text-transform: uppercase; font-weight: 600; }
.rr-sep { opacity: .5; }
.rr-head { display: flex; flex-wrap: wrap; gap: 12px 24px; align-items: end; justify-content: space-between; margin-top: 8px; }
.rr-head h1 { font-size: clamp(26px, 3.4vw, 38px); font-variation-settings: "opsz" 96; color: var(--rr-text); }
.rr-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; color: var(--rr-muted); font-size: 13px; }
.rr-edit { color: var(--rr-gold-ink); text-decoration: none; font-weight: 600; }
.rr-edit:hover { text-decoration: underline; }
.rr-asof { position: relative; }
.rr-asof summary { list-style: none; cursor: pointer; border: 1px solid var(--rr-line-2); border-radius: 999px; padding: 5px 11px; font-size: 12px; font-weight: 600; color: var(--rr-text); }
.rr-asof summary::-webkit-details-marker { display: none; }
.rr-asof summary::after { content: " \25BE"; }
.rr-asof ul { position: absolute; right: 0; z-index: 20; margin: 6px 0 0; padding: 6px; list-style: none; min-width: 180px; background: var(--rr-card); border: 1px solid var(--rr-line); border-radius: 10px; box-shadow: var(--rr-shadow); }
.rr-asof li a { display: block; padding: 6px 10px; border-radius: 6px; color: var(--rr-text); text-decoration: none; font-size: 13px; }
.rr-asof li a:hover, .rr-asof li a[aria-current] { background: var(--rr-well); }
.rr-notice { margin: 14px 0 0; padding: 8px 12px; border-radius: 10px; background: var(--rr-warn-soft); border: 1px solid var(--rr-line); color: var(--rr-text); font-size: 13px; }
.rr-verdict { display: grid; grid-template-columns: 1fr auto auto; gap: 18px 28px; align-items: center; margin-top: 22px; padding: 18px 22px 18px 24px; border: 1px solid var(--rr-line); border-left: 4px solid var(--rr-gold); border-radius: var(--radius); background: var(--rr-well); }
.rr-lbl { font-size: 11px; letter-spacing: .1em; text-transform: uppercase; color: var(--rr-gold-ink); font-weight: 700; margin-bottom: 6px; }
.rr-say p { margin: 0; font-family: var(--display); font-size: clamp(17px, 1.9vw, 22px); font-weight: 500; line-height: 1.35; color: var(--rr-text); }
.rr-say b { color: var(--rr-gold-ink); font-weight: 600; }
.rr-evi { display: flex; gap: 26px; padding-inline: 22px; border-left: 1px solid var(--rr-line-2); }
.rr-evi b { display: block; font-family: var(--display); font-size: 28px; font-weight: 700; color: var(--rr-text); line-height: 1; letter-spacing: -.02em; }
.rr-evi span { display: block; margin-top: 5px; font-size: 10.5px; color: var(--rr-muted); text-transform: uppercase; letter-spacing: .06em; font-weight: 700; white-space: nowrap; }
.rr-act { display: flex; flex-direction: column; gap: 8px; align-items: flex-end; }
.rr-action { font-family: var(--display); font-weight: 700; font-size: 17px; color: var(--rr-text); white-space: nowrap; }
.rr-act form { margin: 0; }
.rr-btn { display: inline-flex; align-items: center; gap: 8px; background: var(--rr-gold); color: var(--rr-ink); font: inherit; font-weight: 700; padding: 11px 16px; border: 0; border-radius: 999px; font-size: 13px; white-space: nowrap; cursor: pointer; }
.rr-btn:hover { box-shadow: 0 8px 20px -8px rgba(200, 155, 60, .8); }
.rr-btn.is-small { padding: 8px 14px; }
.rr-nights { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; margin-top: 16px; }
.rr-night { border: 1px solid var(--rr-line); border-radius: var(--radius); padding: 14px 16px 12px; background: var(--rr-card); box-shadow: var(--rr-shadow); position: relative; overflow: hidden; min-width: 0; }
.rr-night:hover { border-color: var(--rr-gold-2); }
.rr-top { display: flex; justify-content: space-between; align-items: center; gap: 8px; }
.rr-when { font-size: 11px; letter-spacing: .1em; text-transform: uppercase; color: var(--rr-muted); font-weight: 700; }
.rr-price { font-family: var(--display); font-size: 34px; font-weight: 700; letter-spacing: -.02em; line-height: 1; margin: 10px 0 2px; color: var(--rr-text); font-variation-settings: "opsz" 96; }
.rr-price small { font-family: var(--sans); font-size: 12px; font-weight: 500; color: var(--rr-muted); letter-spacing: 0; margin-left: 8px; }
.rr-price.is-unknown { color: var(--rr-muted); }
.rr-line { color: var(--rr-muted); font-size: 12.5px; margin: 0 0 12px; }
.rr-line b { color: var(--rr-text); font-weight: 600; }
.rr-line a { color: var(--rr-gold-ink); }
.rr-chip { display: inline-flex; align-items: center; gap: 6px; font-size: 11px; font-weight: 700; padding: 3px 9px; border-radius: 999px; letter-spacing: .02em; white-space: nowrap; }
.rr-chip i { width: 6px; height: 6px; border-radius: 50%; background: currentColor; display: inline-block; }
.rr-chip.is-good { background: var(--rr-good-soft); color: var(--rr-good); }
.rr-chip.is-warn { background: var(--rr-warn-soft); color: var(--rr-warn); }
.rr-chip.is-bad { background: var(--rr-bad-soft); color: var(--rr-bad); }
.rr-chip.is-plain { background: var(--rr-well); color: var(--rr-text); border: 1px solid var(--rr-line); }
/* The card's small scale. */
.rr-mini { position: relative; height: 38px; margin-top: 4px; }
.rr-mini .rr-axis { position: absolute; left: 0; right: 0; top: 22px; height: 2px; background: var(--rr-line-2); border-radius: 1px; }
.rr-mini .rr-tick { position: absolute; left: 0; top: 28px; font-size: 10px; color: var(--rr-muted); white-space: nowrap; }
.rr-mini .rr-tick.is-r { left: auto; right: 0; }
.rr-mini .rr-d { position: absolute; left: var(--x); top: 17px; width: 12px; height: 12px; border-radius: 50%; background: var(--rr-dot); transform: translateX(-50%); border: 2px solid var(--rr-card); }
.rr-mini .rr-d.is-out { background: transparent; border: 2px solid var(--rr-faint); }
.rr-mini .rr-me { position: absolute; left: var(--x); top: 12px; width: 22px; height: 22px; transform: translateX(-50%) rotate(45deg); background: var(--rr-gold); border-radius: 5px; box-shadow: 0 0 0 4px rgba(200, 155, 60, .28); }
.rr-mini .rr-mid { position: absolute; left: var(--x); top: 14px; width: 1px; height: 18px; background: var(--rr-faint); transform: translateX(-50%); }

/* ---------- the working area ---------- */
.rr-main { max-width: 1180px; margin: 0 auto; padding-block: 26px 56px; padding-inline: clamp(16px, 4vw, 40px); display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); gap: 22px; }
.rr-panel { background: var(--rr-card); border: 1px solid var(--rr-line); border-radius: var(--radius); box-shadow: var(--rr-shadow); padding: 18px 20px 16px; min-width: 0; }
.rr-panel h2 { font-size: 19px; color: var(--rr-text); }
.rr-sub { color: var(--rr-muted); margin: 2px 0 14px; font-size: 13px; }
.rr-toolbar { display: flex; flex-wrap: wrap; gap: 8px 18px; align-items: center; margin-bottom: 14px; }
.rr-group { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.rr-glbl { font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--rr-muted); font-weight: 700; margin-right: 2px; }
.rr-seg { border: 1px solid var(--rr-line-2); border-radius: 999px; padding: 6px 12px; font-size: 12.5px; font-weight: 600; color: var(--rr-text); background: var(--rr-card); text-decoration: none; }
.rr-seg[aria-current] { background: var(--rr-text); color: var(--rr-card); border-color: var(--rr-text); }
.rr-seg:hover:not([aria-current]) { border-color: var(--rr-faint); }
/* The street (item 11): a row a property on one scale, cheapest at the top.
   Four columns - the name, the track, the price, the move - and the scale
   above them once. A row's place is --x and its rank --o (the CSS order);
   the set's middle is --mid on the street, run dashed through every track. */
.rr-street { position: relative; margin: 4px 0 6px; }
.rr-axisrow, .rr-srow, .rr-midlabel { display: grid; grid-template-columns: 230px minmax(0, 1fr) 84px 76px; gap: 14px; }
.rr-axisrow { align-items: end; padding-bottom: 6px; border-bottom: 1px solid var(--rr-line); }
.rr-h { font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--rr-muted); font-weight: 700; }
.rr-h.is-r { text-align: right; }
.rr-scale { position: relative; height: 18px; }
.rr-scale span { position: absolute; left: var(--x); bottom: 0; transform: translateX(-50%); font-size: 11px; color: var(--rr-muted); }
.rr-scale span::after { content: ""; position: absolute; left: 50%; bottom: -7px; width: 1px; height: 5px; background: var(--rr-line-2); }
.rr-rows { display: flex; flex-direction: column; }
.rr-srow { order: var(--o); align-items: center; padding: 7px 0; border-bottom: 1px solid var(--rr-line); }
.rr-srow.is-gone { display: none; }
.rr-srow > * { min-width: 0; }
.rr-sname { font-weight: 600; font-size: 13.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rr-sname small { color: var(--rr-muted); font-weight: 500; margin-left: 7px; }
.rr-srank { display: inline-block; min-width: 18px; color: var(--rr-faint); font-weight: 600; font-size: 11px; margin-right: 6px; }
.rr-strack { position: relative; height: 26px; }
.rr-strack::before { content: ""; position: absolute; left: 0; right: 0; top: 12px; height: 2px; background: var(--rr-well); border-radius: 1px; }
.rr-sfill { position: absolute; left: 0; top: 12px; width: var(--x); height: 2px; background: var(--rr-line-2); }
.rr-smid { position: absolute; left: var(--mid); top: -8px; bottom: -8px; width: 0; border-left: 1px dashed var(--rr-faint); }
.rr-street.no-mid .rr-smid, .rr-street.no-mid .rr-midlabel { display: none; }
.rr-sdot { position: absolute; left: var(--x); top: 6px; width: 14px; height: 14px; border-radius: 50%; background: var(--rr-dot); border: 2px solid var(--rr-card); box-shadow: 0 0 0 1px var(--rr-dot); transform: translateX(-50%); outline: none; }
.rr-sdot:hover, .rr-sdot:focus-visible { transform: translateX(-50%) scale(1.2); }
.rr-sprice { text-align: right; font-weight: 700; font-size: 14px; }
.rr-smove { text-align: right; font-size: 12.5px; color: var(--rr-muted); }
.rr-smove.is-down { color: var(--rr-good); }
.rr-smove.is-up { color: var(--rr-bad); }
.rr-srow.is-out .rr-sdot { background: transparent; box-shadow: 0 0 0 1.5px var(--rr-faint); border-color: transparent; }
.rr-srow.is-out .rr-sfill { background: repeating-linear-gradient(90deg, var(--rr-line-2) 0 6px, transparent 6px 12px); }
.rr-srow.is-out .rr-sname, .rr-srow.is-out .rr-sprice { color: var(--rr-muted); }
/* We are the gold diamond row, on the gold tint. */
.rr-srow.is-me { background: linear-gradient(90deg, var(--rr-gold-soft), transparent 70%); margin: 0 -10px; padding: 7px 10px; border-radius: 8px; }
.rr-srow.is-me .rr-sname { font-weight: 700; }
.rr-srow.is-me .rr-sfill { background: var(--rr-gold-2); }
.rr-srow.is-me .rr-sdot { width: 22px; height: 22px; top: 2px; border-radius: 5px; background: var(--rr-gold); box-shadow: 0 0 0 3px var(--rr-gold-soft), 0 0 0 4px var(--rr-gold); transform: translateX(-50%) rotate(45deg); }
.rr-srow.is-me .rr-sdot:hover, .rr-srow.is-me .rr-sdot:focus-visible { transform: translateX(-50%) rotate(45deg) scale(1.1); }
.rr-midlabel { margin-top: 6px; }
.rr-midlabel span { grid-column: 2; position: relative; height: 14px; }
.rr-midlabel b { position: absolute; left: var(--mid); transform: translateX(-50%); font-size: 10.5px; letter-spacing: .06em; text-transform: uppercase; color: var(--rr-muted); font-weight: 700; white-space: nowrap; }
.rr-tip { position: absolute; z-index: 5; pointer-events: none; background: var(--navy-deep); color: #fff; border-radius: 10px; padding: 10px 12px; font-size: 12px; box-shadow: 0 10px 30px -10px rgba(0, 0, 0, .5); min-width: 170px; left: var(--x, 50%); top: var(--y, 0); transform: translate(-50%, -100%); opacity: 0; }
.rr-tip.is-show { opacity: 1; }
.rr-tip b { display: block; font-weight: 700; margin-bottom: 4px; }
.rr-tip .rr-row { display: flex; justify-content: space-between; gap: 16px; color: #CBD3E6; }
.rr-tip .rr-row.is-low { color: var(--rr-gold-2); font-weight: 600; }
.rr-legend { display: flex; flex-wrap: wrap; gap: 6px 18px; color: var(--rr-muted); font-size: 12px; margin-top: 8px; }
.rr-legend i { display: inline-block; width: 10px; height: 10px; border-radius: 50%; background: var(--rr-dot); margin-right: 6px; vertical-align: -1px; }
.rr-legend i.is-me { background: var(--rr-gold); border-radius: 2px; transform: rotate(45deg); }
.rr-legend i.is-out { background: transparent; box-shadow: inset 0 0 0 1.5px var(--rr-faint); }
.rr-markers { color: var(--rr-muted); font-size: 12px; margin: 8px 0 0; }
.rr-markers b { color: var(--rr-text); font-weight: 600; }
/* The matrix. */
.rr-mtoggle { display: flex; justify-content: space-between; align-items: center; gap: 10px; margin-top: 18px; flex-wrap: wrap; }
.rr-tabs { display: flex; gap: 2px; border-bottom: 1px solid var(--rr-line); }
.rr-tab { padding: 8px 12px; font-weight: 600; font-size: 13px; color: var(--rr-muted); border-bottom: 2px solid transparent; margin-bottom: -1px; text-decoration: none; }
.rr-tab[aria-current] { color: var(--rr-text); border-bottom-color: var(--rr-text); }
.rr-export { font-size: 12.5px; font-weight: 600; color: var(--rr-muted); text-decoration: none; margin-left: auto; }
.rr-export:hover { color: var(--rr-text); }
.rr-mtitle { margin: 6px 0 0; }
.rr-otanote { margin: 8px 0 0; font-size: 12px; }
.rr-matrix { width: 100%; border-collapse: separate; border-spacing: 0; margin-top: 18px; font-size: 13px; }
.rr-matrix th { font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--rr-muted); font-weight: 700; text-align: right; padding: 8px; border-bottom: 1px solid var(--rr-line); white-space: nowrap; background: none; }
.rr-matrix td { padding: 9px 8px; border-bottom: 1px solid var(--rr-line); text-align: right; vertical-align: middle; white-space: nowrap; color: var(--rr-text); }
.rr-matrix th:first-child, .rr-matrix td:first-child { text-align: left; padding-left: 0; }
.rr-matrix .rr-par { text-align: left; color: var(--rr-muted); font-size: 12px; white-space: normal; min-width: 120px; }
.rr-matrix td.is-low { color: var(--rr-good); font-weight: 700; background: linear-gradient(var(--rr-good-soft), var(--rr-good-soft)) no-repeat center / calc(100% - 4px) calc(100% - 8px); }
.rr-matrix td.is-unpriced { color: var(--rr-faint); }
.rr-matrix tr.is-me td { background-color: var(--rr-gold-soft); font-weight: 600; }
.rr-matrix tr.is-me td:first-child { border-radius: 8px 0 0 8px; padding-left: 8px; }
.rr-matrix tr.is-me td:last-child { border-radius: 0 8px 8px 0; }
.rr-m { color: var(--rr-muted); font-size: 12px; }
/* Who moved. */
.rr-stack { display: flex; flex-direction: column; gap: 22px; min-width: 0; }
.rr-mover { display: grid; grid-template-columns: 1fr 84px 70px; gap: 12px; align-items: center; padding: 9px 0; border-bottom: 1px solid var(--rr-line); }
.rr-mover:last-child { border-bottom: 0; }
.rr-mover > * { min-width: 0; }
.rr-n { font-weight: 600; font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rr-n small { display: block; color: var(--rr-muted); font-weight: 500; font-size: 11.5px; }
.rr-spark .rp-chart { display: block; width: 84px; height: 28px; }
.rr-spark .rp-draw { animation: none; }
.rr-spark .rp-line { color: var(--rr-dot); stroke-width: 1.6px; }
.rr-spark .rp-dot { color: var(--rr-dot); }
.rr-dl { text-align: right; font-weight: 700; font-size: 13px; }
.rr-dl.is-down { color: var(--rr-good); }
.rr-dl.is-up { color: var(--rr-bad); }
.rr-dl.is-flat { color: var(--rr-faint); font-weight: 500; }
/* Fourteen days. */
.rr-tape { display: grid; grid-template-columns: repeat(14, minmax(0, 1fr)); gap: 4px; margin-top: 6px; }
.rr-day { display: block; position: relative; min-width: 0; border-radius: 8px; padding: 8px 2px 6px; text-align: center; background: var(--rr-well); border: 1px solid var(--rr-line); color: var(--rr-text); text-decoration: none; }
.rr-day.is-h2 { background: var(--rr-warn-soft); border-color: var(--rr-h2-edge); }
.rr-day.is-h3 { background: var(--rr-bad-soft); border-color: var(--rr-h3-edge); }
.rr-day.is-today { outline: 2px solid var(--rr-text); outline-offset: -1px; }
.rr-day.is-sel { box-shadow: 0 0 0 2px var(--rr-dot) inset; }
.rr-dw { display: block; font-size: 9.5px; letter-spacing: .02em; text-transform: uppercase; color: var(--rr-muted); font-weight: 700; }
.rr-dd { display: block; font-family: var(--display); font-size: 16px; font-weight: 600; line-height: 1.1; }
.rr-so { display: flex; gap: 2px; justify-content: center; margin-top: 7px; height: 6px; }
.rr-so i { width: 5px; height: 6px; border-radius: 2px; background: var(--rr-line-2); }
.rr-so i.is-on { background: var(--rr-text); }
.rr-so.is-unread i { background: transparent; box-shadow: inset 0 0 0 1px var(--rr-line-2); }
.rr-ev { position: absolute; left: 0; right: 0; bottom: -16px; font-size: 9.5px; color: var(--rr-warn); font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rr-tapedetail { margin-top: 22px; padding: 10px 12px; border-radius: 10px; background: var(--rr-well); border: 1px solid var(--rr-line); font-size: 13px; }
.rr-tapedetail b { font-weight: 700; }
.rr-tapeleg { display: flex; flex-wrap: wrap; gap: 6px 16px; color: var(--rr-muted); font-size: 12px; margin-top: 16px; }
.rr-sw { display: inline-block; width: 12px; height: 12px; border-radius: 3px; vertical-align: -2px; margin-right: 6px; border: 1px solid var(--rr-line); background: var(--rr-well); }
.rr-sw.is-h2 { background: var(--rr-warn-soft); }
.rr-sw.is-h3 { background: var(--rr-bad-soft); }
.rr-sw.is-pip { width: 5px; height: 8px; border: 0; border-radius: 2px; background: var(--rr-text); }
.rr-events { margin-top: 16px; border-top: 1px solid var(--rr-line); padding-top: 12px; font-size: 13px; }
.rr-event { display: flex; justify-content: space-between; align-items: center; gap: 12px; margin: 0 0 6px; }
.rr-link { background: none; border: 0; padding: 0; font: inherit; font-weight: 600; color: var(--rr-muted); cursor: pointer; }
.rr-link:hover { color: var(--rr-text); }
.rr-add summary { cursor: pointer; font-weight: 600; color: var(--rr-text); }
.rr-addform { display: flex; flex-wrap: wrap; gap: 8px 12px; align-items: end; margin-top: 10px; }
.rr-addform label { display: flex; flex-direction: column; gap: 4px; font-size: 12px; color: var(--rr-muted); font-weight: 600; }
.rr-addform input { font: inherit; font-size: 13px; color: var(--rr-text); background: var(--rr-card); border: 1px solid var(--rr-line-2); border-radius: 8px; padding: 6px 8px; }
.rr-foot { grid-column: 1 / -1; color: var(--rr-muted); font-size: 12px; line-height: 1.55; border-top: 1px solid var(--rr-line); padding-top: 14px; margin: 0; }
/* 8: the phone (WO-077 item 8), the design's own small-screen rules. Below
   a desk's width - the shell's sidebar takes 232px of the design's 900 - the
   street and the panels beside it read as one column; below 900 the band's
   parts stack, the verdict's figures and action wrap under it, and the tape
   is a week a row. The matrix scrolls in its own box (`table-scroll`). */
@media (max-width: 1132px) {
    .rr-main { grid-template-columns: 1fr; }
}
@media (max-width: 900px) {
    .rr-nights { grid-template-columns: 1fr; }
    .rr-verdict { grid-template-columns: 1fr; }
    .rr-act { flex-direction: row; flex-wrap: wrap; align-items: center; gap: 12px; }
    .rr-evi { padding-inline: 0; border-left: 0; gap: 18px; flex-wrap: wrap; }
    .rr-tape { grid-template-columns: repeat(7, minmax(0, 1fr)); row-gap: 22px; }
    /* A row on the phone: the scale above, the name, price and move in a
       line, the track under them, so nothing is clipped. */
    .rr-axisrow, .rr-srow, .rr-midlabel { grid-template-columns: minmax(0, 1fr) 70px 60px; }
    .rr-scale { grid-column: 1 / -1; order: -1; margin-bottom: 6px; }
    .rr-strack { grid-column: 1 / -1; order: 3; height: 22px; }
    .rr-sname { grid-column: 1; }
    .rr-sprice { grid-column: 2; }
    .rr-smove { grid-column: 3; }
    .rr-midlabel span { grid-column: 1 / -1; }
    .rr-mover { grid-template-columns: 1fr 70px 64px; }
}
/* 7b: motion, each piece with a reason (WO-077 item 7b) - and none of it
   under reduced motion: every animation and transition of the page is in
   this one guard, so `prefers-reduced-motion: reduce` gets the page whole and
   still. No figure moves: each is served final, and nothing counts up. */
@media (prefers-reduced-motion: no-preference) {
    /* A faint gold and navy tint drifts on the band over half a minute: a read that is live. */
    .rr-band::before { content: ""; position: absolute; inset: -30%; background: radial-gradient(640px 320px at 18% 30%, rgba(200, 155, 60, .07), transparent 62%), radial-gradient(520px 420px at 78% 80%, rgba(20, 32, 61, .05), transparent 60%); animation: rr-drift 28s ease-in-out infinite alternate; pointer-events: none; }
    /* The morning arrives in reading order: where, what to do, on what, for which nights. */
    .rr-crumb { animation: rise .6s var(--motion-ease) backwards; }
    .rr-head { animation: rise .6s var(--motion-ease) .06s backwards; }
    .rr-notice, .rr-verdict { animation: rise .7s var(--motion-ease) .16s backwards; }
    .rr-evi > div { animation: rise .6s var(--motion-ease) .34s backwards; }
    .rr-evi > div:nth-child(2) { animation-delay: .42s; }
    .rr-evi > div:nth-child(3) { animation-delay: .5s; }
    .rr-night { animation: rise .7s var(--motion-ease) .3s backwards; transition: border-color .2s; }
    .rr-night:nth-child(2) { animation-delay: .4s; }
    .rr-night:nth-child(3) { animation-delay: .5s; }
    .rr-mini .rr-d { animation: pop .5s var(--motion-ease) calc(.55s + var(--i) * .06s) backwards; }
    .rr-mini .rr-me { animation: pop .55s var(--motion-ease) .75s backwards; }
    /* The gold diamond pings, slowly: this is us, on the radar. Nothing else does. */
    .rr-mini .rr-me::after, .rr-srow.is-me .rr-sdot::after { content: ""; position: absolute; inset: -5px; border-radius: 7px; border: 2px solid var(--rr-gold); opacity: 0; animation: ping 3s ease-out infinite; }
    .rr-main > .rr-panel, .rr-stack > .rr-panel { animation: rise .7s var(--motion-ease) .38s backwards; }
    .rr-stack > .rr-panel:nth-child(1) { animation-delay: .48s; }
    .rr-stack > .rr-panel:nth-child(2) { animation-delay: .58s; }
    /* The street's rows arrive in price order, the cheapest first. A switch
       then slides each dot and its fill along the track, and the middle line
       and its label with them; a row that changes rank is moved to its new
       place by the script (FLIP), the same element. */
    .rr-srow { animation: rise .5s var(--motion-ease) calc(.45s + var(--o) * 60ms) backwards; transition: background .25s; }
    .rr-sdot { transition: left .55s var(--motion-ease), background .3s, box-shadow .3s, transform .2s ease; }
    .rr-sfill { transition: width .55s var(--motion-ease), background .3s; }
    .rr-smid, .rr-midlabel b { transition: left .55s var(--motion-ease); }
    .rr-tip { transition: opacity .12s; }
    /* Each line of who moved draws itself, then its last read lands. */
    .rr-mover .rp-draw { animation: draw 1.1s ease-out calc(.6s + var(--i) * .12s) backwards; }
    .rr-mover .rp-dot { animation: fadein .35s ease-out calc(1.5s + var(--i) * .12s) backwards; }
    /* The tape's sold-outs grow in, day by day. */
    .rr-so i.is-on { transform-origin: bottom; animation: grow .45s var(--motion-ease) calc(.7s + var(--d) * .04s + var(--i) * .05s) backwards; }
    .rr-matrix tbody tr { animation: fadein .35s ease-out calc(var(--i) * 45ms) backwards; }
    /* A pane, a night's table or a day's line fades in as it is chosen. */
    .rr-pane:not([hidden]), .rr-bynight:not([hidden]), .rr-movers:not([hidden]) { animation: fadein .3s ease-out; }
    .rr-tapedetail:not([hidden]) { animation: fadein .35s ease-out; }
    /* A control gives under the finger. */
    .rr-seg, .rr-tab, .rr-day { transition: transform .12s ease, background .15s, color .15s, border-color .15s; }
    .rr-seg:active, .rr-tab:active, .rr-day:active { scale: .96; }
    .rr-btn { transition: translate .15s ease, box-shadow .15s ease; }
    .rr-btn:hover { translate: 0 -1px; }
    .rr-btn:active { translate: 0; scale: .98; }
}
@keyframes rr-drift { from { translate: 0 0; } to { translate: 9% 12%; } }
/* rr:end */
