/* =====================================================================
   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.
   ===================================================================== */
:root {
    --navy: #14203D;
    --navy-deep: #0E172E;
    --navy-light: #1E2D52;
    --navy-lighter: #2E4172;
    --gold: #C89B3C;
    --gold-light: #E3C27A;
    --gold-dark: #A97F2C;
    --gold-bg: #FBF3E1;
    --ink: #1B1F27;
    --muted: #667085;
    --muted-light: #98A2B3;
    --border: #E4E7EC;
    --border-strong: #D5D9E0;
    --bg: #F4F5F7;
    --surface: #FFFFFF;
    --surface-2: #F9FAFB;
    --success: #1A8F4E;
    --success-bg: #E6F6ED;
    --danger: #D64545;
    --danger-bg: #FBEAEA;
    --warning: #B7791F;
    --warning-bg: #FCF3DC;
    --info: #2563AF;
    --info-bg: #E8F1FC;
    --neutral-bg: #EEF0F4;
    --radius: 12px;
    --radius-sm: 8px;
    --shadow-sm: 0 1px 2px rgba(16,26,51,0.04), 0 4px 14px rgba(16,26,51,0.04);
    --shadow-md: 0 12px 30px rgba(16,26,51,0.10);
    --shadow-lg: 0 18px 48px rgba(8,15,31,0.22);
    --sidebar-w: 264px;
    --sidebar-rail: 76px;
    --topbar-h: 56px;
    --tabbar-h: 62px;
    --serif: Didot, 'Bodoni MT', 'Playfair Display', 'Palatino Linotype', Georgia, 'Times New Roman', serif;
    --sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
}

* { 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: 15px;
    -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; }

/* ---------------- 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-light); 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-dark) 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: 11px;
    width: 100%; min-height: 40px; padding: 8px 11px;
    border-radius: 10px; border: none; background: none;
    color: rgba(255,255,255,0.74); text-decoration: none;
    font: inherit; font-size: 0.9rem; 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: 19px; height: 19px; 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-light); 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-dark); 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-dark); }
.tabbar .tab-ico { display: grid; place-items: center; width: 44px; height: 26px; border-radius: 999px; }
.tabbar a.active .tab-ico { background: var(--gold-bg); }

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

/* ---------------- 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;
}

.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: linear-gradient(180deg, var(--gold), var(--gold-light));
    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-dark); 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); }
.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; }

/* ---------------- 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: employee list ----------------
   Lifted from payroll/templates/payroll/employee_list.html on 2026-09-05
   (WO-019 B6); the rules are unchanged. */
.employee-filters { display: grid; grid-template-columns: minmax(220px, 1.4fr) repeat(4, minmax(150px, .75fr)) auto; gap: 12px; align-items: end; }
.employee-table { min-width: 1040px; }
.employee-table thead th { position: sticky; top: 0; z-index: 1; }
.table-swipe-note { display: none; color: var(--muted); font-size: .82em; margin: 0 0 8px; }
@media (max-width: 980px) { .employee-filters { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 620px) {
    .employee-filters { grid-template-columns: 1fr; }
    .table-swipe-note { display: block; }
}

/* ---------------- 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-dark); }
.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-dark);
}
.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-light);
}
.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; }
.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-dark); }
.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-dark); 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; } }

/* ---------------- 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); }
/* 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-dark); }

/* 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-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-dark { color: var(--gold-dark); }
