/* ============================================================
   WOM Studio · Client Portal
   Deep-navy theme: dark blue-black ground, navy surfaces,
   cool-white text, one vivid blue accent (#006eff), generous
   rounding, Archivo type.
   ============================================================ */

@font-face {
    font-family: 'Archivo';
    src: url('../fonts/archivo.woff2') format('woff2');
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
}

:root {
    /* The sticky bar's height. Declared here because the landing backdrop is
       positioned directly under it, and the two must never drift apart. */
    --nav-h: 62px;
    --bg: #080b12;
    --bg-2: #0a0e17;
    --surface: #0e1420;
    --surface-2: #121a28;
    --surface-3: #182236;
    --line: rgba(255, 255, 255, 0.08);
    --line-2: rgba(255, 255, 255, 0.14);
    --text: #f5f8fd;
    --text-2: #9aa6bd;
    --text-3: #6c7793;
    --accent: #006eff;
    --accent-2: #3d8bff;
    --accent-3: #66a6ff;
    --accent-soft: rgba(0, 110, 255, 0.16);
    --accent-line: rgba(0, 110, 255, 0.36);
    --warn: #d9a84e;
    --success: #7fb58a;
    --success-soft: rgba(127, 181, 138, 0.14);
    --danger: #e06c5f;
    --danger-soft: rgba(224, 108, 95, 0.14);
    --info: #8fa0c8;
    --info-soft: rgba(143, 160, 200, 0.14);
    --paper: #f6f4ee;
    --paper-line: #ddd8ca;
    --paper-ink: #26272b;
    --white: #f5f8fd;
    --radius: 16px;
    --radius-sm: 11px;
    --radius-lg: 22px;
    --radius-xl: 28px;
    --shadow: 0 1px 2px rgba(0, 0, 0, 0.5), 0 26px 60px -30px rgba(0, 0, 0, 0.9);
    --font-ui: "Archivo", "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
    --font-display: "Archivo", "Arial Black", "Segoe UI", system-ui, sans-serif;
    --font-script: "Segoe Script", "Brush Script MT", "Lucida Handwriting", cursive;
    --font-mono: ui-monospace, "Cascadia Mono", Consolas, Menlo, monospace;
}

* { box-sizing: border-box; }
[hidden] { display: none !important; }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
html { -webkit-text-size-adjust: 100%; }
body {
    margin: 0;
    background: var(--bg);
    color: var(--text);
    font-family: var(--font-ui);
    font-size: 15px;
    line-height: 1.55;
}
img { max-width: 100%; }
a { color: var(--accent-2); text-decoration: none; }
a:hover { color: var(--accent-3); }
code { font-family: var(--font-mono); font-size: 0.85em; background: var(--surface-2); border: 1px solid var(--line); border-radius: 4px; padding: 1px 5px; }
:focus-visible { outline: 2px solid var(--accent-2); outline-offset: 2px; border-radius: 3px; }
::selection { background: var(--accent); color: #fff; }

.ic { vertical-align: -3px; flex: none; }

/* ---------------------------------------------------------- brand */

.brand { display: flex; align-items: center; gap: 11px; color: var(--text); }
.brand:hover { color: var(--text); }
.brand-logo { height: 26px; width: auto; display: block; flex: none; }
.install-brand .brand-logo { height: 32px; }
.brand-word { font-family: var(--font-display); font-size: 17px; letter-spacing: 0.02em; white-space: nowrap; }
.brand-word em { font-style: normal; color: var(--text-2); font-size: 13px; letter-spacing: 0.24em; text-transform: uppercase; margin-left: 2px; }

.eyebrow {
    font-size: 11px; font-weight: 600; letter-spacing: 0.22em; text-transform: uppercase;
    color: var(--accent-2); margin-bottom: 6px;
}

/* ---------------------------------------------------------- type */

.page-title { font-family: var(--font-display); font-size: 30px; font-weight: 800; letter-spacing: -0.015em; margin: 0; line-height: 1.2; }
.page-sub { color: var(--text-2); margin: 6px 0 0; max-width: 62ch; }

/* ------------------------------------------------- admin generics (shared) */
/* The app-style admin shell (sidebar, topbar, nav, collapse, account, drawer)
   lives in its own block near the end of this file. These are the shared bits
   the shell + every admin page reuse. */

.avatar {
    display: inline-flex; align-items: center; justify-content: center;
    width: 30px; height: 30px; border-radius: 50%;
    background: var(--surface-3); border: 1px solid var(--line-2);
    color: var(--accent-2); font-family: var(--font-display); font-size: 14px; flex: none;
}
.page-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 20px; margin-bottom: 26px; }
.page-body { display: flex; flex-direction: column; gap: 20px; }

/* ---------------------------------------- City-style top nav bar */

.topnav {
    position: sticky; top: 0; z-index: 50;
    background: rgba(8, 11, 18, 0.72);
    border-bottom: 1px solid var(--line);
    -webkit-backdrop-filter: saturate(150%) blur(14px); backdrop-filter: saturate(150%) blur(14px);
}
/* Where blur isn't supported, use a near-opaque bar so nav text stays legible. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .topnav { background: rgba(8, 11, 18, 0.96); }
}
/* Two layouts from one DOM, decided by what the two side elements flex to.
   Desktop: side-l is empty and takes no space, so the mark sits hard left with
   the options beside it and side-r flexes to push the account controls right.
   The mobile half of this is in the 860px block further down. */
/* Shorter and quieter than it was, with the options CENTRED rather than sitting
   against the mark. The links take the flex now and the right-hand side takes
   none, which is what pushes them into the middle; the 860px block below still
   hands both sides an equal flex, so the mobile layout is untouched. */
/* Full width, not a 1400px column. The bar spans the whole page so the mark
   and the account controls sit near the edges rather than floating in from
   them — the padding is all that keeps them off the glass. Its height is a
   variable because the landing's backdrop starts directly below it, and two
   numbers that must agree should not be typed twice. */
.topnav-inner {
    max-width: none; margin: 0 auto; padding: 0 clamp(18px, 2.4vw, 46px);
    height: var(--nav-h, 62px); display: flex; align-items: center; gap: 0;
}
.topnav-side { min-width: 0; display: flex; align-items: center; gap: 10px; height: 100%; }
.topnav-side-l { flex: none; justify-content: flex-start; }
.topnav-side-r { flex: none; justify-content: flex-end; }
.topnav-brand { display: inline-flex; align-items: center; flex: none; color: var(--text); position: relative; }
.topnav-brand:hover { color: var(--text); }
.topnav-brand img { height: 32px; width: auto; display: block; }
/* Centred on the PAGE, not on the space left over.
   Sharing the row with the mark and the account controls meant the links
   centred between them — and since those two sides are never the same width,
   "centred" landed wherever the difference put it. Taking them out of flow and
   pinning them to 50% makes the middle the actual middle, whatever grows on
   either side. Only above 980px: below that the sides close in and an absolute
   block would sit on top of them. */
.topnav-links { display: flex; align-items: center; gap: 2px; height: 100%; flex: 1 1 auto; justify-content: center; margin-left: 24px; }
@media (min-width: 981px) {
    .topnav-inner { position: relative; }
    .topnav-links {
        position: absolute; left: 50%; transform: translateX(-50%);
        flex: none; margin-left: 0;
    }
    /* The links no longer take the flex, so the right-hand side has to. */
    .topnav-side-r { flex: 1 1 0; }
}
.nav-slot {
    position: relative; display: inline-flex; align-items: center; gap: 8px;
    padding: 0 13px; height: 100%;
    color: var(--text-2); font-weight: 500; font-size: 13.5px; white-space: nowrap;
    background: transparent; border: 0; cursor: pointer;
    transition: color 0.18s;
}
.nav-slot .ic { color: var(--text-2); opacity: 0.85; transition: color 0.18s; }
.nav-slot:hover { color: var(--text); }
.nav-slot:hover .ic { color: var(--text); }
.nav-slot.active { color: var(--text); }
.nav-slot.active .ic { color: var(--text); }
.nav-slot.active::after {
    content: ""; position: absolute; left: 13px; right: 13px; bottom: 0; height: 2px;
    background: var(--accent);
}
.topnav-right { margin-left: auto; display: flex; align-items: center; gap: 10px; }
.nav-login {
    display: inline-flex; align-items: center; gap: 8px;
    background: rgba(255, 255, 255, 0.03); color: var(--text); font: 500 13.5px var(--font-ui);
    padding: 8px 14px; border-radius: 6px; border: 1px solid var(--line-2); cursor: pointer;
    transition: border-color 0.18s, background 0.18s, color 0.18s;
}
/* The CTA is set in mono — the one place the reference does it, and it reads as
   a control rather than a sentence. `.topnav .nav-join` rather than `.nav-join`
   on purpose: the bare class ties with `.btn-sm`, which is declared later in
   this file and would win on source order. */
.topnav .nav-join {
    font-family: var(--font-mono); font-size: 12px; font-weight: 500;
    letter-spacing: 0.02em; padding: 9px 15px; border-radius: 6px;
}
.nav-login:hover { border-color: var(--accent); background: var(--accent-soft); color: var(--text); }
.nav-login .ic { color: var(--text-2); }

/* nav dropdowns (Products, FAQ Info) */
.nav-drop { position: relative; display: inline-flex; align-items: center; height: 100%; }
.nav-drop-trigger svg:last-child { opacity: 0.7; transition: transform 0.2s; }
.nav-drop.open .nav-drop-trigger svg:last-child { transform: rotate(180deg); }
.nav-drop-menu {
    position: absolute; top: calc(100% - 8px); left: 0; z-index: 60; min-width: 214px; padding: 7px;
    background: var(--surface); border: 1px solid var(--line-2); border-radius: 14px; box-shadow: var(--shadow);
    opacity: 0; visibility: hidden; transform: translateY(6px);
    transition: opacity 0.18s, transform 0.18s, visibility 0s 0.18s;
}
/* [hidden] is what the shared menu JS toggles; the class drives the animation.
   Both are needed: the attribute keeps a closed menu out of the a11y tree even
   before the transition finishes. */
.nav-drop-menu[hidden] { display: none; }
.nav-drop.open .nav-drop-menu {
    opacity: 1; visibility: visible; transform: translateY(0);
    transition: opacity 0.18s, transform 0.18s, visibility 0s 0s;
}
/* Hover-to-open only where there is a real pointer. On touch this rule used to
   be the ONLY way to open a dropdown, which is why they could not be opened. */
@media (hover: hover) and (pointer: fine) {
    .nav-drop:hover .nav-drop-menu, .nav-drop:focus-within .nav-drop-menu {
        display: block; opacity: 1; visibility: visible; transform: translateY(0);
        transition: opacity 0.18s, transform 0.18s, visibility 0s 0s;
    }
    .nav-drop:hover .nav-drop-trigger svg:last-child,
    .nav-drop:focus-within .nav-drop-trigger svg:last-child { transform: rotate(180deg); }
}
.nav-drop-item { display: flex; align-items: center; gap: 11px; padding: 9px 11px; border-radius: 9px; color: var(--text-2); font-size: 14px; font-weight: 600; white-space: nowrap; }
.nav-drop-item .ic { color: var(--text-3); }
.nav-drop-item:hover { background: rgba(255, 255, 255, 0.06); color: var(--text); }
.nav-drop-item:hover .ic { color: var(--accent-2); }
.nav-drop-item.active { color: var(--text); background: var(--accent-soft); }
.nav-drop-item.active .ic { color: var(--accent-2); }

/* ---- mobile menu -------------------------------------------------------
   Hidden on desktop, where .topnav-links does the work. Below 860px the
   dropdowns are display:none, so this is the only route to Products and the
   legal pages. */
.navmenu { position: relative; display: none; }
.navmenu-trigger {
    display: inline-flex; align-items: center; justify-content: center;
    width: 40px; height: 40px; border-radius: 11px; cursor: pointer;
    background: var(--surface); border: 1px solid var(--line-2); color: var(--text);
    transition: border-color 0.16s, background 0.16s;
}
.navmenu-trigger:hover { border-color: var(--accent); background: var(--accent-soft); }
.navmenu.open .navmenu-trigger { border-color: var(--accent); background: var(--accent-soft); }
.navmenu-pop {
    position: absolute; top: calc(100% + 10px); left: 0; z-index: 60;
    min-width: 244px; max-height: calc(100vh - 96px); overflow-y: auto; padding: 8px;
    background: var(--surface); border: 1px solid var(--line-2);
    border-radius: 14px; box-shadow: var(--shadow);
}
.navmenu-pop[hidden] { display: none; }
.navmenu-group {
    display: flex; align-items: center; gap: 9px;
    padding: 10px 11px 5px; color: var(--text-3);
    font-size: 11px; font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase;
}
.navmenu-group .ic { color: var(--text-3); }
.navmenu-item {
    display: flex; align-items: center; gap: 11px; padding: 10px 11px; border-radius: 9px;
    color: var(--text-2); font-size: 14.5px; font-weight: 600;
}
.navmenu-item .ic { color: var(--text-3); flex: none; }
.navmenu-item:hover { background: rgba(255, 255, 255, 0.06); color: var(--text); }
.navmenu-item.danger { color: var(--danger, #f0566a); }
/* Splits who you are from where you can go. */
.navmenu-sep { height: 1px; margin: 6px 0; background: var(--line-2); }
/* The sign-in entry is a <button> so it can open the panel; it has to sit flush
   with the <a> items around it rather than inheriting the browser's button box. */
button.navmenu-item { width: 100%; text-align: left; background: transparent; border: 0; font: inherit; cursor: pointer; }
.navmenu-item:hover .ic { color: var(--accent-2); }
.navmenu-item.active { color: var(--text); background: var(--accent-soft); }
.navmenu-item.active .ic { color: var(--accent-2); }

/* standout Commissions button in the nav */
.nav-cta { display: inline-flex; align-items: center; gap: 8px; margin-left: 6px;
    background: linear-gradient(180deg, var(--accent-2), var(--accent)); color: #fff; font-weight: 700; font-size: 14.5px;
    padding: 9px 18px; border-radius: 999px; box-shadow: 0 8px 20px -10px color-mix(in srgb, var(--accent) 60%, transparent);
    transition: transform 0.18s, box-shadow 0.22s; }
.nav-cta:hover { transform: translateY(-1px); box-shadow: 0 12px 26px -10px color-mix(in srgb, var(--accent) 75%, transparent); color: #fff; }
.nav-cta .ic { color: #fff; }

.usermenu { position: relative; }
.usermenu-trigger {
    display: inline-flex; align-items: center; gap: 9px;
    background: var(--surface); border: 1px solid var(--line-2); border-radius: 999px;
    padding: 5px 12px 5px 6px; cursor: pointer; color: var(--text);
    font: 600 13.5px var(--font-ui); transition: border-color 0.15s, background 0.15s;
}
.usermenu-trigger:hover { border-color: var(--text-3); background: var(--surface-2); }
.usermenu-trigger .avatar { width: 28px; height: 28px; font-size: 13px; }
.usermenu-name { max-width: 150px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.usermenu-caret { display: inline-flex; color: var(--text-3); transition: transform 0.2s; }
.usermenu.open .usermenu-caret { transform: rotate(180deg); }
.usermenu-pop {
    position: absolute; top: calc(100% + 9px); right: 0; z-index: 65;
    min-width: 230px; max-width: calc(100vw - 24px);
    background: var(--surface); border: 1px solid var(--line-2);
    border-radius: 13px; box-shadow: var(--shadow); padding: 7px;
    animation: menu-in 0.16s ease-out;
}
.usermenu-pop[hidden] { display: none; }
@keyframes menu-in { from { opacity: 0; transform: translateY(-6px); } }
.usermenu-head { display: flex; align-items: center; gap: 11px; padding: 8px 10px 12px; border-bottom: 1px solid var(--line); margin-bottom: 6px; }
.usermenu-id { min-width: 0; line-height: 1.3; }
.usermenu-id strong { display: block; font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.usermenu-id small { color: var(--text-3); font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: block; }
.usermenu-item {
    display: flex; align-items: center; gap: 11px;
    padding: 9px 11px; border-radius: 8px; color: var(--text-2);
    font-size: 13.5px; font-weight: 500;
}
.usermenu-item .ic { color: var(--text-3); }
.usermenu-item:hover { background: var(--surface-2); color: var(--text); }
.usermenu-item:hover .ic { color: var(--text-2); }
.usermenu-item.danger:hover { color: var(--danger); background: var(--danger-soft); }
.usermenu-item.danger:hover .ic { color: var(--danger); }
.usermenu-sep { height: 1px; background: var(--line); margin: 6px 4px; }
.avatar-lg { width: 40px; height: 40px; font-size: 17px; flex: none; }

.portal-main { max-width: 1400px; margin: 0 auto; padding: 32px 28px 80px; }
.portal-head { margin-bottom: 24px; }
.portal-foot { text-align: center; color: var(--text-3); font-size: 12.5px; letter-spacing: 0.06em; padding: 26px 20px 34px; border-top: 1px solid var(--line); }

@media (max-width: 560px) {
    .topnav-inner { gap: 8px; }
    .usermenu-name { display: none; }
    .usermenu-trigger { padding: 5px; }
}

.notice-bar {
    display: flex; align-items: center; gap: 10px;
    background: var(--accent-soft); border: 1px solid var(--accent-line);
    color: var(--accent-2); border-radius: var(--radius); padding: 12px 16px; margin-bottom: 20px;
}

/* ---------------------------------------------------------- auth shell */

.shell-auth { display: flex; min-height: 100vh; align-items: center; justify-content: center; padding: 30px 16px; }
.auth-wrap { position: relative; width: 100%; max-width: 420px; }
.auth-glow {
    position: fixed; inset: 0; pointer-events: none;
    background:
        radial-gradient(600px 340px at 50% 0%, rgba(4, 102, 200, 0.14), transparent 70%),
        radial-gradient(500px 400px at 85% 100%, rgba(160, 142, 232, 0.05), transparent 70%);
}
.auth-card {
    position: relative;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 16px;
    box-shadow: var(--shadow);
    padding: 34px 34px 28px;
}
.installer-card { max-width: 480px; margin: 0 auto; }
.auth-wrap:has(.installer-card) { max-width: 480px; }
.install-brand { display: flex; align-items: center; gap: 11px; margin-bottom: 24px; font-family: var(--font-display); font-size: 17px; }
.auth-title { font-family: var(--font-display); font-size: 26px; font-weight: 800; letter-spacing: -0.01em; margin: 0 0 6px; }
.auth-sub { color: var(--text-2); margin: 0 0 22px; font-size: 14px; }
.auth-foot { color: var(--text-3); font-size: 12.5px; text-align: center; margin: 18px 0 0; }
.install-done-mark {
    width: 52px; height: 52px; border-radius: 50%; display: flex; align-items: center; justify-content: center;
    background: var(--success-soft); border: 1px solid var(--success); color: var(--success);
    font-size: 24px; margin-bottom: 16px;
}

.steps { display: flex; gap: 4px; list-style: none; padding: 0; margin: 0 0 24px; }
.step { flex: 1; display: flex; align-items: center; gap: 7px; font-size: 12px; color: var(--text-3); }
.step-dot {
    width: 22px; height: 22px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center;
    border: 1px solid var(--line-2); font-size: 11px; flex: none;
}
.step.active { color: var(--accent-2); }
.step.active .step-dot { border-color: var(--accent-2); background: var(--accent-soft); color: var(--accent-2); }
.step.done { color: var(--success); }
.step.done .step-dot { border-color: var(--success); color: var(--success); }

.req-list { display: flex; flex-direction: column; margin-bottom: 20px; border: 1px solid var(--line); border-radius: var(--radius-sm); overflow: hidden; }
.req-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 10px 14px; font-size: 13.5px; background: var(--surface-2); }
.req-row + .req-row { border-top: 1px solid var(--line); }

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

.btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 8px;
    font: 700 14px/1 var(--font-ui);
    padding: 12px 18px; border-radius: 12px;
    border: 1px solid transparent; cursor: pointer; white-space: nowrap;
    transition: background 0.18s, border-color 0.18s, color 0.18s, transform 0.18s cubic-bezier(0.2, 0.7, 0.2, 1), box-shadow 0.22s;
    text-decoration: none;
}
.btn:active { transform: translateY(1px); }
/* Primary = vivid blue, the studio's headline action. */
.btn-primary {
    background: linear-gradient(180deg, var(--accent-2), var(--accent)); color: #fff; border-color: transparent;
    box-shadow: 0 12px 30px -14px color-mix(in srgb, var(--accent) 60%, transparent), inset 0 1px 0 rgba(255, 255, 255, 0.28);
}
.btn-primary:hover { background: linear-gradient(180deg, color-mix(in srgb, var(--accent-2) 80%, #fff), color-mix(in srgb, var(--accent) 88%, #fff)); color: #fff; transform: translateY(-2px); box-shadow: 0 18px 40px -16px color-mix(in srgb, var(--accent) 75%, transparent), inset 0 1px 0 rgba(255, 255, 255, 0.34); }
.btn-primary:disabled { opacity: 0.4; cursor: not-allowed; box-shadow: none; transform: none; }
/* Accent = same blue family, kept as an alias for older markup. */
.btn-accent {
    background: linear-gradient(180deg, var(--accent-2), var(--accent));
    color: #fff; border-color: transparent;
    box-shadow: 0 12px 30px -14px color-mix(in srgb, var(--accent) 60%, transparent), inset 0 1px 0 rgba(255, 255, 255, 0.28);
}
.btn-accent:hover { background: linear-gradient(180deg, color-mix(in srgb, var(--accent-2) 80%, #fff), color-mix(in srgb, var(--accent) 88%, #fff)); color: #fff; transform: translateY(-2px); }
/* Dark secondary — supports an optional two-line label (icon + subtext). */
.btn-dark { background: var(--surface-2); color: var(--text); border-color: var(--line-2); }
.btn-dark:hover { color: var(--text); border-color: var(--line-2); background: var(--surface-3); transform: translateY(-2px); }
.btn-2l { display: inline-flex; flex-direction: column; gap: 2px; line-height: 1.15; text-align: left; }
.btn-2l small { font-weight: 500; font-size: 12px; color: var(--text-2); }
/* Accent-outlined button (e.g. showcase "View Product"). */
.btn-line { background: transparent; border-color: var(--accent); color: var(--text); }
.btn-line:hover { background: var(--accent-soft); border-color: var(--accent); color: var(--text); transform: translateY(-2px); }
.btn-ghost { background: transparent; color: var(--text-2); border-color: var(--line-2); }
.btn-ghost:hover { color: var(--text); border-color: var(--text-3); background: rgba(255, 255, 255, 0.05); }
.btn-danger { background: var(--danger-soft); color: var(--danger); border-color: rgba(224, 108, 95, 0.4); }
.btn-danger:hover { background: rgba(224, 108, 95, 0.22); color: #f0897d; }
/* Red kept strictly for genuine danger / overdue emphasis. */
.btn-red {
    background: linear-gradient(180deg, #e0463a, #c8271b);
    color: #fff; border-color: rgba(0, 0, 0, 0.4);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.22), 0 6px 18px -8px rgba(200, 39, 27, 0.6);
}
.btn-red:hover { background: linear-gradient(180deg, #ea5749, #d5301f); color: #fff; transform: translateY(-2px); }
.btn-danger-ghost:hover { color: var(--danger) !important; border-color: rgba(224, 108, 95, 0.5) !important; }
.btn-sm { padding: 8px 12px; font-size: 13px; border-radius: 10px; }
.btn-pill { border-radius: 999px; }
.btn-block { width: 100%; }

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

.field { display: block; margin-bottom: 15px; }
.field > span { display: block; font-size: 12.5px; font-weight: 600; letter-spacing: 0.04em; color: var(--text-2); margin-bottom: 6px; }
.field > span small { color: var(--text-3); font-weight: 400; }
.field input, .field textarea, .field select {
    width: 100%;
    background: var(--bg-2);
    border: 1px solid var(--line-2);
    border-radius: var(--radius-sm);
    color: var(--text);
    font: 400 14.5px/1.4 var(--font-ui);
    padding: 10px 13px;
    transition: border-color 0.15s, box-shadow 0.15s;
}
.field textarea { resize: vertical; }
.field input:focus, .field textarea:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.field input::placeholder, .field textarea::placeholder { color: var(--text-3); }

/* ---- the base every form control gets ----
   There was no global rule for inputs or textareas either — only `.field input`
   — so any control outside a .field fell back to the operating system's widget:
   a white box with black text in a dark panel.

   Wrapped in :where() so it carries ZERO specificity. Every existing rule
   (.search-box input, .projnew input, .tip-other, .field input …) therefore
   still wins without needing to be touched or reordered, which a plain
   `input[type="text"]` selector would not allow — that ties with `.field input`
   and would quietly repaint half the forms depending on source order. */
:where(
    input[type="text"], input[type="search"], input[type="email"], input[type="password"],
    input[type="number"], input[type="url"], input[type="tel"], input[type="date"],
    input[type="datetime-local"], input[type="time"], input[type="month"], input:not([type]),
    textarea
) {
    background: var(--bg-2);
    border: 1px solid var(--line-2);
    border-radius: var(--radius-sm);
    color: var(--text);
    font: 400 14px/1.4 var(--font-ui);
    padding: 9px 11px;
}
:where(input, textarea)::placeholder { color: var(--text-3); }
:where(input, textarea):focus-visible { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
/* A file input draws its own button, which is the OS's until it is told
   otherwise — the game-type background picker is the one that shows. */
:where(input[type="file"]) { color: var(--text-2); font: 400 13px/1.4 var(--font-ui); max-width: 100%; }
input[type="file"]::file-selector-button {
    margin-right: 10px; padding: 6px 11px; cursor: pointer;
    background: var(--surface-2); color: var(--text-2);
    border: 1px solid var(--line-2); border-radius: 8px;
    font: 600 12.5px/1 var(--font-ui);
}
input[type="file"]::file-selector-button:hover { background: var(--surface-3); color: var(--text); }

/* ---- every select, not just the ones inside a .field ----
   Only `.field select` was ever styled, so a select anywhere else fell back to
   the operating system's widget: a white box with black text sitting in a dark
   panel. That is most of them — filters, the artwork picker, the merge form.

   The native appearance is kept on purpose rather than replaced with
   appearance:none and a background-image chevron. Browsers draw that arrow in
   the computed `color`, so it comes right for free — whereas a background-image
   would be clobbered by the eight places that set a smaller `padding`
   shorthand, and each one would need a matching right-inset to stop the text
   running under the arrow. */
select {
    background-color: var(--bg-2);
    color: var(--text);
    border: 1px solid var(--line-2);
    border-radius: var(--radius-sm);
    font: 400 14px/1.4 var(--font-ui);
    padding: 9px 11px;
    cursor: pointer;
    transition: border-color 0.15s, box-shadow 0.15s;
}
select:hover:not(:disabled) { border-color: var(--line-3, rgba(255, 255, 255, 0.22)); }
select:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
select:disabled { opacity: 0.55; cursor: not-allowed; }
/* The open list is a separate surface the OS paints, and it keeps the system
   palette unless the options are given one of their own. */
select option { background: var(--surface); color: var(--text); }
select option:disabled { color: var(--text-3); }
.field-inline { display: flex; gap: 8px; }
.field-inline input { flex: 1; }
.form-row-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.form-row-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
.field-note { color: var(--text-3); font-size: 13px; margin: 8px 0 14px; }
.field-note a { color: var(--accent-2); }

.check { display: flex; align-items: flex-start; gap: 10px; font-size: 13.5px; color: var(--text-2); cursor: pointer; padding: 6px 0; }
.check input { accent-color: var(--accent); width: 16px; height: 16px; margin-top: 1px; flex: none; }
.check small { color: var(--text-3); }
.check-all { border-bottom: 1px dashed var(--line-2); margin-bottom: 6px; padding-bottom: 9px; font-weight: 600; color: var(--text); }

.feature-set { border: 1px solid var(--line); border-radius: var(--radius); padding: 14px 16px 10px; margin: 0 0 16px; }
.feature-set legend { font-size: 11px; font-weight: 600; letter-spacing: 0.18em; text-transform: uppercase; color: var(--text-3); padding: 0 6px; }

.switch { display: flex; align-items: center; gap: 12px; cursor: pointer; padding: 8px 0; }
.switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.switch-track {
    width: 40px; height: 22px; border-radius: 11px; flex: none; position: relative;
    background: var(--surface-3); border: 1px solid var(--line-2);
    transition: background 0.18s, border-color 0.18s;
}
.switch-track::after {
    content: ""; position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; border-radius: 50%;
    background: var(--text-3); transition: transform 0.18s, background 0.18s;
}
.switch input:checked + .switch-track { background: var(--accent); border-color: var(--accent); }
.switch input:checked + .switch-track::after { transform: translateX(18px); background: #fff; }
.switch input:focus-visible + .switch-track { outline: 2px solid var(--accent); outline-offset: 2px; }
.switch-label { display: flex; flex-direction: column; line-height: 1.3; }
.switch-label strong { font-size: 14px; font-weight: 600; }
.switch-label small { color: var(--text-3); font-size: 12.5px; }

.recipient-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 0 14px; max-height: 220px; overflow-y: auto; }
.recipient-grid .check small { font-size: 12px; }

.alert { border-radius: var(--radius-sm); padding: 11px 14px; font-size: 13.5px; margin-bottom: 16px; }
.alert-danger { background: var(--danger-soft); border: 1px solid rgba(224, 108, 95, 0.4); color: #f0a49b; }

/* ---------------------------------------------------------- chips */

.chip {
    display: inline-flex; align-items: center; gap: 5px;
    font-size: 11.5px; font-weight: 600; letter-spacing: 0.05em;
    padding: 4px 9px; border-radius: 999px; white-space: nowrap;
}
.chip-success { background: var(--success-soft); color: var(--success); border: 1px solid rgba(127, 181, 138, 0.35); }
.chip-danger { background: var(--danger-soft); color: var(--danger); border: 1px solid rgba(224, 108, 95, 0.35); }
.chip-accent { background: var(--accent-soft); color: var(--accent-2); border: 1px solid var(--accent-line); }
/* Amber, matching the "due within three days" band used on the client side. */
.chip-warn { background: rgba(217, 168, 78, 0.14); color: var(--warn); border: 1px solid rgba(217, 168, 78, 0.4); }
.chip-info { background: var(--info-soft); color: var(--info); border: 1px solid rgba(160, 142, 232, 0.35); }
.chip-muted { background: var(--surface-2); color: var(--text-2); border: 1px solid var(--line-2); }

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

.card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 22px 24px; }
.card-flush { padding: 0; overflow: hidden; }
/* A flush card drops the card's own padding so a table can reach its edges. A
   HEADER inside one still needs it, or the title sits hard against the border
   and the right-aligned meta text runs into it. Only analytics puts a head in a
   flush card today — everywhere else wraps a bare table — so this adds the
   padding where it was missing rather than changing anything that had it. */
.card-flush > .card-head { padding: 20px 20px 0; margin-bottom: 14px; }
/* A line of explanation inside a flush card, which has none of its own. */
.card-flush > .pad-note { padding: 0 20px 18px; margin: 0; }
.card-flush > .card-head + .pad-note { padding-top: 0; }
.card-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 0 0 16px; }
.card-head h2 { font-family: var(--font-display); font-size: 17px; font-weight: 700; letter-spacing: -0.01em; margin: 0; }
.card-empty { color: var(--text-3); font-size: 14px; margin: 4px 0; }
.card-danger { border-color: rgba(224, 108, 95, 0.35); }
.card-danger .card-head h2 { color: var(--danger); }
.card-update-ok { border-color: rgba(127, 181, 138, 0.4); }

.def-list { margin: 0; display: flex; flex-direction: column; gap: 10px; }
.def-list > div { display: flex; flex-direction: column; gap: 1px; }
.def-list dt { font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--text-3); }
.def-list dd { margin: 0; font-size: 14px; }
.mono { font-family: var(--font-mono); font-size: 12.5px; }
.wrap { word-break: break-all; }

/* ---------------------------------------------------------- stats & dash */

.stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 14px; }
.stat-card {
    display: flex; align-items: center; gap: 14px;
    background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
    padding: 18px 20px;
}
.stat-ic {
    display: flex; align-items: center; justify-content: center;
    width: 42px; height: 42px; border-radius: 50%; flex: none;
    background: var(--surface-2); border: 1px solid var(--line-2); color: var(--accent-2);
}
.stat-num { font-family: var(--font-display); font-size: 26px; font-weight: 800; line-height: 1.1; font-variant-numeric: tabular-nums; }
.stat-label { color: var(--text-3); font-size: 12.5px; letter-spacing: 0.04em; }
.stat-attn { border-color: var(--accent-line); background: linear-gradient(180deg, rgba(4, 102, 200, 0.1), var(--surface)); }
.stat-attn .stat-ic { border-color: var(--accent-line); }

.dash-cols { display: grid; grid-template-columns: 1.6fr 1fr; gap: 20px; align-items: start; }

.activity-list { list-style: none; margin: 0; padding: 0; }
.activity-list li { display: flex; align-items: center; gap: 12px; padding: 9px 0; border-bottom: 1px solid var(--line); font-size: 13.5px; }
.activity-list li:last-child { border-bottom: none; }
.act-ic { color: var(--text-3); display: flex; flex: none; }
.act-text { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.act-time { color: var(--text-3); font-size: 12px; flex: none; }

.quick-actions { display: flex; flex-direction: column; gap: 10px; }
.quick-action {
    display: flex; align-items: center; gap: 14px;
    padding: 13px 15px; border: 1px solid var(--line); border-radius: var(--radius-sm);
    background: var(--surface-2); color: var(--accent-2);
    transition: border-color 0.15s, background 0.15s;
}
.quick-action:hover { border-color: var(--accent-line); background: var(--surface-3); }
.quick-action span { display: flex; flex-direction: column; line-height: 1.3; }
.quick-action strong { color: var(--text); font-size: 14px; }
.quick-action small { color: var(--text-3); font-size: 12.5px; }

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

.table { width: 100%; border-collapse: collapse; font-size: 14px; }
.table th {
    text-align: left; font-size: 11px; font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase;
    color: var(--text-3); padding: 12px 16px; border-bottom: 1px solid var(--line);
}
.table td { padding: 13px 16px; border-bottom: 1px solid var(--line); vertical-align: middle; }
.table tbody tr:last-child td { border-bottom: none; }
.table tbody tr:hover td { background: rgba(255, 255, 255, 0.015); }
.table-title { color: var(--text); font-weight: 600; }
.table-title:hover { color: var(--accent-2); }
.table-sub { color: var(--text-3); font-size: 12.5px; margin-top: 1px; }
.table-actions { white-space: nowrap; }
.table-actions .btn, .table-actions form { vertical-align: middle; }
.t-right { text-align: right; }
.inline { display: inline-block; }
.progress-done { color: var(--success); font-weight: 600; font-variant-numeric: tabular-nums; }
.progress-open { color: var(--text-2); font-variant-numeric: tabular-nums; }
.card-flush .table { min-width: 640px; }
.card-flush { overflow-x: auto; }

/* ---------------------------------------------------------- toolbars */

.toolbar, .list-tools { display: flex; align-items: center; justify-content: space-between; gap: 14px; flex-wrap: wrap; }
.search-box {
    display: flex; align-items: center; gap: 8px;
    background: var(--surface); border: 1px solid var(--line-2); border-radius: var(--radius-sm);
    padding: 8px 12px; color: var(--text-3); min-width: 240px;
}
.search-box input { background: none; border: none; color: var(--text); font: 400 14px var(--font-ui); width: 100%; }
.search-box input:focus { outline: none; }
.search-box:focus-within { border-color: var(--accent); }

.chip-filters { display: flex; gap: 8px; flex-wrap: wrap; }
.chip-filter {
    display: inline-flex; align-items: center; gap: 7px;
    background: var(--surface); border: 1px solid var(--line-2); border-radius: 999px;
    color: var(--text-2); font: 600 13px var(--font-ui); padding: 8px 14px; cursor: pointer;
    transition: border-color 0.15s, color 0.15s, background 0.15s;
}
.chip-filter span { color: var(--text-3); font-variant-numeric: tabular-nums; }
.chip-filter:hover { border-color: var(--text-3); color: var(--text); }
.chip-filter.active { background: var(--accent-soft); border-color: var(--accent-line); color: var(--accent-2); }
.chip-filter.active span { color: var(--accent-2); }

.crumb { display: flex; align-items: center; gap: 12px; margin: -8px 0 0; flex-wrap: wrap; }
.crumb > a:first-child { display: inline-flex; align-items: center; gap: 6px; color: var(--text-2); font-size: 13.5px; }
.crumb > a:first-child:hover { color: var(--accent-2); }

/* ---------------------------------------------------------- doc list (portal) */

.doc-list { display: flex; flex-direction: column; gap: 10px; }
.doc-row {
    display: flex; align-items: center; gap: 16px;
    background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
    padding: 16px 18px; color: var(--text);
    transition: border-color 0.15s, background 0.15s, transform 0.1s;
}
.doc-row:hover { border-color: var(--accent-line); background: var(--surface-2); color: var(--text); transform: translateY(-1px); }
.doc-glyph {
    display: flex; align-items: center; justify-content: center;
    width: 44px; height: 44px; border-radius: var(--radius-sm); flex: none;
    background: var(--surface-2); border: 1px solid var(--line-2); color: var(--accent-2);
}
.doc-row-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.doc-row-title { font-family: var(--font-display); font-size: 16px; font-weight: 700; }
.doc-row-desc { color: var(--text-2); font-size: 13.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.doc-row-meta { color: var(--text-3); font-size: 12px; letter-spacing: 0.03em; }
.doc-row-side { display: flex; align-items: center; gap: 12px; color: var(--text-3); flex: none; }
.doc-row[hidden] { display: none; }

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

.empty-state {
    text-align: center; padding: 70px 24px;
    border: 1px dashed var(--line-2); border-radius: var(--radius);
    display: flex; flex-direction: column; align-items: center; gap: 6px;
}
.empty-seal {
    width: 64px; height: 64px; border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    background: var(--surface); border: 1px solid var(--line-2); color: var(--accent-2);
    margin-bottom: 10px;
}
.empty-state h2 { font-family: var(--font-display); font-size: 20px; margin: 0; }
.empty-state p { color: var(--text-3); margin: 0 0 16px; max-width: 42ch; }

/* ---------------------------------------------------------- modal */

.modal { position: fixed; inset: 0; z-index: 100; display: flex; align-items: center; justify-content: center; padding: 20px; }
.modal[hidden] { display: none; }
.modal-backdrop { position: absolute; inset: 0; background: rgba(5, 6, 8, 0.72); -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px); }
.modal-card {
    position: relative; width: 100%; max-width: 560px; max-height: calc(100vh - 40px); overflow-y: auto;
    background: var(--surface); border: 1px solid var(--line-2); border-radius: 16px;
    box-shadow: var(--shadow); padding: 22px 24px;
    animation: modal-in 0.18s ease-out;
}
@keyframes modal-in { from { opacity: 0; transform: translateY(10px) scale(0.98); } }
.modal-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 16px; }
.modal-head h3 { font-family: var(--font-display); font-size: 18px; font-weight: 700; margin: 0; }
.modal-x {
    background: none; border: none; color: var(--text-3); cursor: pointer;
    padding: 6px; border-radius: 6px; display: flex;
}
.modal-x:hover { color: var(--text); background: var(--surface-2); }
.modal-foot { display: flex; justify-content: flex-end; gap: 10px; margin-top: 18px; }
/* The edit form carries name, notes, project and audience, so it needs more
   room than a confirm dialog. .modal-card already scrolls past the viewport. */
.modal-wide { max-width: 620px; }
/* A 300px client list inside a modal that is itself scrolling gives two nested
   scrollbars. Shorter here, and the search box above it does the finding. */
.modal .pick-list { max-height: 190px; }

/* ---------------------------------------------------------- tabs */

.tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--line); margin-bottom: 16px; }
.tab {
    background: none; border: none; border-bottom: 2px solid transparent;
    color: var(--text-2); font: 600 14px var(--font-ui);
    padding: 9px 14px; cursor: pointer; margin-bottom: -1px;
}
.tab:hover { color: var(--text); }
.tab.active { color: var(--accent-2); border-bottom-color: var(--accent-2); }
.tab-panel[hidden] { display: none; }

/* ---------------------------------------------------------- dropzone */

.dropzone {
    position: relative; border: 1.5px dashed var(--line-2); border-radius: var(--radius);
    background: var(--bg-2); padding: 26px 18px; text-align: center;
    margin-bottom: 16px; cursor: pointer;
    transition: border-color 0.15s, background 0.15s;
}
.dropzone:hover, .dropzone.drag { border-color: var(--accent-2); background: var(--accent-soft); }
.dropzone input[type="file"] { position: absolute; inset: 0; opacity: 0; cursor: pointer; width: 100%; }
.dz-idle { display: flex; flex-direction: column; align-items: center; gap: 5px; color: var(--text-3); pointer-events: none; }
.dz-idle strong { color: var(--text-2); font-size: 14.5px; }
.dz-idle span { font-size: 12.5px; }
.dz-idle .ic { color: var(--accent-2); margin-bottom: 3px; }
.dz-file {
    display: flex; align-items: center; justify-content: center; gap: 10px;
    color: var(--accent-2); font-weight: 600; font-size: 14px; position: relative; z-index: 2; pointer-events: none;
}
.dz-file .dz-clear { pointer-events: auto; background: none; border: none; color: var(--text-3); cursor: pointer; display: flex; padding: 4px; }
.dz-file .dz-clear:hover { color: var(--danger); }
.dz-name { max-width: 300px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dz-size { color: var(--text-3); font-weight: 400; font-size: 12.5px; }
.dropzone-compact { padding: 16px 14px; }

/* Over the server's limit. Caught in the browser, because letting it upload
   anyway means the server kills the request mid-body and the browser reports
   ERR_HTTP2_PROTOCOL_ERROR — a dead tab with no clue what went wrong. */
.dropzone.dz-over { border-color: var(--danger); background: rgba(255, 77, 79, 0.06); }
.dropzone.dz-over .dz-file { color: var(--danger); }
.dz-warn {
    display: flex; align-items: flex-start; gap: 8px; text-align: left;
    margin-top: 12px; padding: 10px 12px; position: relative; z-index: 2;
    border: 1px solid var(--danger); border-radius: 10px;
    background: rgba(255, 77, 79, 0.08); color: var(--text);
    font-size: 12.5px; line-height: 1.45;
}
.dz-warn svg { flex: none; color: var(--danger); margin-top: 1px; }

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

.toasts { position: fixed; top: 18px; right: 18px; z-index: 200; display: flex; flex-direction: column; gap: 10px; max-width: 380px; }
.toast {
    display: flex; align-items: flex-start; gap: 10px;
    background: var(--surface-2); border: 1px solid var(--line-2); border-radius: var(--radius-sm);
    box-shadow: var(--shadow); padding: 13px 15px; font-size: 13.5px;
    animation: toast-in 0.22s ease-out;
}
@keyframes toast-in { from { opacity: 0; transform: translateX(16px); } }
.toast.out { opacity: 0; transition: opacity 0.25s; }
.toast-success { border-left: 3px solid var(--success); }
.toast-danger { border-left: 3px solid var(--danger); }
.toast-warning { border-left: 3px solid var(--warn); }
.toast-credentials { border-left: 3px solid var(--accent); }
.toast-body { flex: 1; min-width: 0; }
.toast-x { background: none; border: none; color: var(--text-3); cursor: pointer; padding: 2px; display: flex; flex: none; }
.toast-x:hover { color: var(--text); }
.cred-line { display: flex; align-items: center; gap: 8px; margin-top: 6px; font-family: var(--font-mono); font-size: 12.5px; background: var(--bg-2); border: 1px solid var(--line); border-radius: 6px; padding: 6px 9px; }
.cred-line code { background: none; border: none; padding: 0; flex: 1; overflow: hidden; text-overflow: ellipsis; }
.cred-copy { background: none; border: none; color: var(--accent-2); cursor: pointer; display: flex; padding: 2px; }
.cred-copy:hover { color: var(--accent-3); }

/* ---------------------------------------------------------- edit layouts */

.edit-cols { display: grid; grid-template-columns: 1.7fr 1fr; gap: 20px; align-items: start; }
.edit-col-main, .edit-col-side { display: flex; flex-direction: column; gap: 20px; min-width: 0; }
.access-form { margin-top: 16px; border-top: 1px solid var(--line); padding-top: 16px; }
.access-form .btn { margin-top: 12px; }

/* ---------------------------------------------------------- update log */

.update-log {
    background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius-sm);
    font-family: var(--font-mono); font-size: 12.5px; line-height: 1.7; color: var(--text-2);
    padding: 14px 16px; margin: 0; max-height: 320px; overflow: auto; white-space: pre-wrap;
}

/* ---------------------------------------------------------- viewer */

.shell-viewer { background: var(--bg); }
.viewer-bar {
    position: sticky; top: 0; z-index: 50;
    display: flex; align-items: center; gap: 18px;
    background: rgba(11, 12, 15, 0.92); -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
    border-bottom: 1px solid var(--line); padding: 12px 22px;
}
.viewer-back { display: inline-flex; align-items: center; gap: 8px; color: var(--text-2); font-size: 13.5px; flex: none; }
.viewer-back:hover { color: var(--accent-2); }
.viewer-title { flex: 1; min-width: 0; display: flex; align-items: center; gap: 12px; }
.viewer-title strong { font-family: var(--font-display); font-size: 16px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.viewer-chips { display: flex; gap: 8px; flex: none; }
.viewer-actions { display: flex; gap: 10px; flex: none; }
.viewer-main { max-width: 940px; margin: 0 auto; padding: 36px 20px 120px; }
.viewer-admin-note {
    display: flex; align-items: center; gap: 8px;
    color: var(--text-3); font-size: 12.5px; letter-spacing: 0.04em;
    margin-bottom: 16px; justify-content: center;
}
.viewer-missing { text-align: center; padding: 100px 20px; }
.viewer-missing h1 { font-family: var(--font-display); }
.viewer-missing p { color: var(--text-2); margin-bottom: 20px; }

/* ------------------------------------------------- the document paper */

.doc-paper {
    background: var(--paper); color: var(--paper-ink);
    border-radius: 4px;
    box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.55), 0 30px 70px -30px rgba(0, 0, 0, 0.9);
    padding: 64px 72px;
    font-family: var(--font-ui); font-size: 15px; line-height: 1.7;
    overflow-wrap: break-word;
}
.doc-paper p { margin: 0 0 0.9em; }
.doc-paper h1, .doc-paper h2, .doc-paper h3, .doc-paper h4, .doc-paper h5, .doc-paper h6 {
    font-family: var(--font-display); color: #1d1e22; line-height: 1.25;
    margin: 1.4em 0 0.5em; font-weight: 800; letter-spacing: -0.01em;
}
.doc-paper h1 { font-size: 28px; }
.doc-paper h2 { font-size: 22px; }
.doc-paper h3 { font-size: 18px; }
.doc-paper h4, .doc-paper h5, .doc-paper h6 { font-size: 15.5px; }
.doc-paper .doc-title { font-size: 32px; margin-top: 0; }
.doc-paper .doc-subtitle { color: #5a5c63; font-size: 17px; margin-top: -0.4em; }
.doc-paper a { color: #0353a4; text-decoration: underline; }
.doc-paper ul, .doc-paper ol { margin: 0 0 1em; padding-left: 1.6em; }
.doc-paper li { margin-bottom: 0.35em; }
.doc-paper blockquote {
    margin: 1em 0; padding: 0.5em 1.2em; border-left: 3px solid var(--accent);
    background: rgba(4, 102, 200, 0.07); color: #4b4c52; font-style: italic;
}
.doc-paper .wom-table { border-collapse: collapse; width: 100%; margin: 1.2em 0; font-size: 14px; }
.doc-paper .wom-table td { border: 1px solid var(--paper-line); padding: 8px 11px; vertical-align: top; }
.doc-paper .wom-table p { margin: 0; }

/* Tables written in the editor (the contract templates) had no styling at all
   and rendered as unbordered browser defaults. .wom-table above only covers
   tables produced by the .docx converter. */
.doc-paper table { border-collapse: collapse; width: 100%; margin: 1.2em 0; font-size: 14px; }
.doc-paper table th,
.doc-paper table td { border: 1px solid var(--paper-line); padding: 8px 11px; vertical-align: top; text-align: left; }
.doc-paper table th { background: rgba(0, 0, 0, 0.035); font-weight: 700; }
.doc-paper table p { margin: 0 0 0.4em; }
.doc-paper table p:last-child { margin-bottom: 0; }

/* The signature block is the one table that must be two equal halves: it reads
   as a pair, and letting the columns size to their content makes whichever side
   has the longer name look like the more important party. `table-layout: fixed`
   with no column widths splits the available space evenly. */
.doc-paper table:has(.sig-slot) { table-layout: fixed; }
.doc-paper table:has(.sig-slot) td { width: 50%; }
.doc-paper .wom-img { display: inline-block; height: auto; margin: 0.4em 0; }
.doc-paper .wom-tab { display: inline-block; width: 36px; }
.doc-paper .wom-page-break { display: block; border-top: 1px dashed var(--paper-line); margin: 2.4em -24px; }
.doc-paper .wom-img-missing { color: #9a9b9f; font-style: italic; }
.doc-paper-fallback { text-align: center; padding: 80px 40px; }
.doc-paper-fallback h2 { margin-top: 0; }
.doc-paper-fallback p { color: #5a5c63; margin-bottom: 24px; }

/* ------------------------------------------------- signature certificate */

.sig-certificate {
    margin-top: 22px;
    background: var(--surface); border: 1px solid var(--line); border-top: 2px solid var(--accent);
    border-radius: var(--radius); padding: 20px 24px;
}
.sig-cert-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 14px; }
.sig-cert-head .eyebrow { margin: 0; }
.sig-cert-body { display: flex; gap: 24px; align-items: flex-start; flex-wrap: wrap; }
.sig-cert-image {
    background: #fdfcf9; border: 1px solid var(--paper-line); border-radius: 6px;
    padding: 10px 18px; min-width: 220px; max-width: 320px;
    display: flex; align-items: center; justify-content: center; min-height: 80px;
}
.sig-cert-image img { max-height: 90px; }
.sig-cert-image em { color: #9a9b9f; font-size: 13px; }
.sig-cert-meta { flex: 1; min-width: 240px; margin: 0; display: grid; grid-template-columns: 1fr 1fr; gap: 12px 20px; }
.sig-cert-meta > div { display: flex; flex-direction: column; gap: 1px; }
.sig-cert-meta dt { font-size: 10.5px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--text-3); }
.sig-cert-meta dd { margin: 0; font-size: 13.5px; }

/* ------------------------------------------------- signing ceremony */

.sign-bar {
    position: fixed; bottom: 22px; left: 50%; transform: translateX(-50%);
    z-index: 60; display: flex; align-items: center; gap: 18px;
    background: var(--surface-2); border: 1px solid var(--accent-line);
    border-radius: 999px; padding: 10px 12px 10px 22px;
    box-shadow: var(--shadow); max-width: calc(100vw - 32px);
}
.sign-bar-text { display: inline-flex; align-items: center; gap: 9px; font-size: 14px; color: var(--accent-2); white-space: nowrap; }
.sign-bar .btn { border-radius: 999px; }

.modal-sign { max-width: 520px; }
.pad-wrap { position: relative; margin-bottom: 10px; }
#sign-pad, #studio-pad {
    display: block; width: 100%;
    background: #fdfcf9; border: 1px solid var(--paper-line); border-radius: 8px;
    cursor: crosshair; touch-action: none;
}
#sign-pad { height: 180px; }
#studio-pad { height: 140px; }
.pad-baseline {
    position: absolute; left: 28px; right: 28px; bottom: 38px;
    border-bottom: 1.5px dashed #c9c3b2; pointer-events: none;
}
.type-preview {
    position: relative; background: #fdfcf9; border: 1px solid var(--paper-line); border-radius: 8px;
    height: 110px; display: flex; align-items: center; justify-content: center;
    margin-bottom: 10px; overflow: hidden;
}
.type-preview span { font-family: var(--font-script); font-size: 34px; color: #1c2733; padding: 0 20px; white-space: nowrap; }
.type-preview .pad-baseline { bottom: 24px; }

/* ---------------------------------------------------------- responsive */

@media (max-width: 960px) {
    .dash-cols, .edit-cols { grid-template-columns: 1fr; }
}

@media (max-width: 640px) {
    .doc-paper { padding: 30px 22px; }
    .form-row-2 { grid-template-columns: 1fr; }
    /* Two, not one: three short hex fields still read fine side by side at
       this width, and stacking them would push the note off the card. */
    .form-row-3 { grid-template-columns: 1fr 1fr; }
    .page-head { flex-direction: column; align-items: flex-start; }
    .viewer-bar { flex-wrap: wrap; gap: 10px; padding: 10px 14px; }
    .viewer-title { order: 3; width: 100%; }
    .viewer-main { padding: 20px 12px 130px; }
    .sign-bar { width: calc(100vw - 24px); justify-content: space-between; padding-left: 16px; }
    .sign-bar-text { white-space: normal; font-size: 13px; }
    .doc-row-side .chip { display: none; }
    .search-box { min-width: 0; flex: 1; }
}
/* After the 960px block, deliberately: a narrower query that appears BEFORE
   it in the file loses to it at every width they both match. */
@media (max-width: 560px) { .form-row-3 { grid-template-columns: 1fr; } }

/* ---------------------------------------------------------- payments */

.notice-warn { background: rgba(217, 168, 78, 0.1); border-color: rgba(217, 168, 78, 0.4); color: #e0b76a; }
.notice-warn a { color: #edc985; text-decoration: underline; }
.notice-danger { background: rgba(224, 108, 95, 0.1); border-color: rgba(224, 108, 95, 0.45); color: #eb8d82; }
.notice-danger strong { color: #fff; }
.notice-danger a { color: #f2a79e; text-decoration: underline; }

/* payments — global collection pause */
.pause-card .switch { padding-bottom: 14px; }
.pause-card .field { margin-bottom: 10px; }
.pause-card.is-paused { border-color: rgba(224, 108, 95, 0.45); background: linear-gradient(180deg, rgba(224, 108, 95, 0.05), var(--surface)); }
.pause-card .field-note svg { color: var(--success); vertical-align: -2px; }

/* pay-by-bank-transfer instructions on an unpaid invoice */
/* Full-width inside .pay-row: flex-basis for the desktop flex row, grid-column
   for the mobile grid. Without the basis it gets squeezed inline beside the amount. */
.xfer { flex: 0 0 100%; width: 100%; grid-column: 1 / -1; margin-top: 4px; border: 1px solid var(--line); border-radius: 12px; background: var(--surface-2); overflow: hidden; }
.xfer > summary { display: flex; align-items: center; gap: 8px; padding: 10px 14px; cursor: pointer; font-size: 13px; font-weight: 600; color: var(--text-2); list-style: none; }
.xfer > summary::-webkit-details-marker { display: none; }
.xfer > summary:hover { color: var(--text); }
.xfer > summary svg { color: var(--accent-2); }
.xfer[open] > summary { border-bottom: 1px solid var(--line); }
.xfer-body { padding: 14px; }
.xfer-lead { color: var(--text-2); font-size: 13px; margin: 0 0 12px; line-height: 1.5; }
.xfer-grid { display: flex; flex-direction: column; gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: 9px; overflow: hidden; }
.xfer-row { display: flex; align-items: center; justify-content: space-between; gap: 14px; padding: 9px 12px; background: var(--surface); font-size: 13px; }
.xfer-row span { color: var(--text-3); }
.xfer-row b { font-family: var(--font-mono); font-size: 13px; letter-spacing: 0.02em; }
.xfer-ref b { color: var(--accent-2); }
.xfer-note { color: var(--text-3); font-size: 12px; line-height: 1.5; margin: 10px 0 0; }
.xfer-paused { display: flex; align-items: center; gap: 9px; padding: 10px 14px; color: var(--text-2); font-size: 12.5px; }
.xfer-paused svg { color: var(--warn); flex: none; }

.section-title {
    display: flex; align-items: center; gap: 9px;
    font-family: var(--font-display); font-size: 17px; font-weight: 700; letter-spacing: -0.01em; margin: 0;
}
.section-title .ic { color: var(--accent-2); }
.pay-section { margin-bottom: 26px; }
.pay-section-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 12px; }
.pay-list { display: flex; flex-direction: column; gap: 9px; }
.pay-row {
    display: flex; align-items: center; gap: 15px; flex-wrap: wrap;
    background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
    padding: 14px 18px; transition: border-color 0.15s;
}
.pay-row:hover { border-color: var(--line-2); }
.pay-row.pay-unpaid { border-color: var(--accent-line); background: linear-gradient(180deg, rgba(4, 102, 200, 0.06), var(--surface)); }
.pay-glyph {
    display: flex; align-items: center; justify-content: center;
    width: 42px; height: 42px; border-radius: 11px; flex: none;
    background: var(--surface-2); border: 1px solid var(--line-2); color: var(--accent-2);
}.pay-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.pay-title { font-weight: 600; font-size: 14.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pay-meta { color: var(--text-3); font-size: 12.5px; }
.pay-amount { font-family: var(--font-display); font-weight: 800; font-size: 17px; font-variant-numeric: tabular-nums; flex: none; white-space: nowrap; }
/* A row now, because an auto-collecting payment shows its "Auto" marker AND a
   Pay button side by side rather than one instead of the other. Rows with a
   single child lay out exactly as they did. */
.pay-action { flex: none; display: flex; align-items: center; gap: 10px; }
.pay-action form { margin: 0; }
.pay-row.pay-overdue { border-color: rgba(224, 108, 95, 0.5); background: linear-gradient(180deg, rgba(224, 108, 95, 0.07), var(--surface)); }
.pay-overdue .pay-glyph { color: var(--danger); border-color: rgba(224, 108, 95, 0.4); }
.due-overdue { color: var(--danger); font-weight: 600; }

.chip-plan { background: var(--surface-3); color: var(--text-2); border: 1px solid var(--line-2); font-size: 10.5px; padding: 2px 7px; letter-spacing: 0.02em; vertical-align: 1px; }

/* ------------------------------------------------- payment-plan builder */

.plan-builder { border: 1px solid var(--line); border-radius: var(--radius); padding: 14px 16px; margin-bottom: 16px; background: var(--bg-2); }
.plan-builder-row { display: flex; align-items: flex-end; gap: 10px; flex-wrap: wrap; margin-bottom: 12px; }
.plan-builder-row .field { margin-bottom: 0; }
.plan-builder-row .field:nth-child(1) { flex: 1 1 110px; }
.plan-builder-row .field:nth-child(2) { flex: 0 0 84px; }
.plan-builder-row .field:nth-child(3) { flex: 1 1 130px; }
.plan-builder-row .field:nth-child(4) { flex: 0 0 110px; }
.plan-builder-row .btn { flex: none; }
.plan-table { width: 100%; border-collapse: collapse; }
.plan-table th { text-align: left; font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--text-3); padding: 4px 6px; }
.plan-table th:first-child { width: 28px; }
.plan-table td { padding: 3px 6px; vertical-align: middle; }
.plan-table .plan-num { color: var(--text-3); font-variant-numeric: tabular-nums; text-align: center; }
.plan-table input { width: 100%; background: var(--surface); border: 1px solid var(--line-2); border-radius: 6px; color: var(--text); font: 400 13.5px var(--font-ui); padding: 7px 9px; }
.plan-table input:focus { outline: none; border-color: var(--accent-2); }
.plan-remove { padding: 5px 7px; color: var(--text-3); }
.plan-remove:hover { color: var(--danger); border-color: rgba(224, 108, 95, 0.5); }
.plan-foot { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 10px; }
.plan-sum { color: var(--accent-2); font-weight: 600; font-size: 13px; font-variant-numeric: tabular-nums; }

/* ------------------------------------------------------- receipt page */

.receipt-paper { max-width: 620px; margin: 0 auto; padding: 48px 52px; }
.receipt-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 20px; }
.receipt-logo { height: 40px; width: auto; }
.receipt-head-right { text-align: right; }
.receipt-word { font-family: var(--font-display); font-size: 26px; font-weight: 800; letter-spacing: -0.01em; color: #1d1e22; text-transform: uppercase; }
.receipt-number { color: #8b8d94; font-size: 12px; margin-top: 2px; }
.receipt-rule { height: 2px; background: var(--accent); margin: 20px 0 24px; }
.receipt-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; margin-bottom: 22px; }
.receipt-cols strong { color: #1d1e22; font-size: 14px; }
.receipt-label { font-size: 10.5px; letter-spacing: 0.16em; text-transform: uppercase; color: #9a9b9f; margin-bottom: 5px; }
.receipt-muted { color: #5a5c63; font-size: 13px; line-height: 1.5; }
.receipt-meta { margin-bottom: 8px; }
.receipt-meta > div { color: #1d1e22; font-size: 13.5px; }
.receipt-table { width: 100%; border-collapse: collapse; margin: 10px 0 6px; }
.receipt-table th { text-align: left; font-size: 9.5px; letter-spacing: 0.12em; text-transform: uppercase; color: #9a9b9f; padding: 8px 0; border-bottom: 1px solid var(--paper-line); background: transparent; }
.receipt-table td { padding: 14px 0; color: #26272b; font-size: 13.5px; border-bottom: 1px solid var(--paper-line); }
.receipt-table tfoot td { border-bottom: none; padding-top: 16px; }
.receipt-table tfoot .receipt-subtotal td { padding: 5px 0 0; color: #5a5c63; font-size: 12.5px; }
.receipt-addr { font-style: normal; white-space: pre-line; color: #5a5c63; font-size: 13px; line-height: 1.5; margin-top: 2px; }
/* Trading disclosures live below a rule at the foot, where a reader expects
   them — stacked under FROM they ran to eight lines and left BILLED TO empty. */
.receipt-legal { margin-top: 22px; padding-top: 14px; border-top: 1px solid var(--paper-line); }
.receipt-terms { margin: 0 0 4px; font-size: 11.5px; color: #85878e; line-height: 1.6; }
.receipt-terms:last-child { margin-bottom: 0; }
.receipt-terms a { color: #0353a4; }
.receipt-thanks { margin-top: 8px; color: #5a5c63; }
.receipt-total-label { font-weight: 700; color: #1d1e22; }
.receipt-total { font-family: var(--font-display); font-weight: 800; font-size: 18px; color: var(--accent); }
.receipt-table .t-right { text-align: right; }
.receipt-foot { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-top: 26px; flex-wrap: wrap; }
.receipt-paid-stamp {
    display: inline-flex; align-items: center; gap: 6px;
    border: 1.5px solid var(--success); color: var(--success);
    font-weight: 800; letter-spacing: 0.14em; font-size: 13px; padding: 6px 14px; border-radius: 6px;
}
/* The reference is a machine string; label it and let it wrap rather than
   running off the edge, which is what a single long mono line was doing. */
.receipt-ref { display: flex; flex-direction: column; align-items: flex-end; gap: 2px; min-width: 0; text-align: right; }
.receipt-ref small { font-size: 9.5px; letter-spacing: 0.14em; text-transform: uppercase; color: #9a9b9f; }
.receipt-ref code { font-family: var(--font-mono); font-size: 11px; color: #6f7178; overflow-wrap: anywhere; }

@media (max-width: 560px) {
    .receipt-paper { padding: 30px 24px; }
    .pay-row { flex-wrap: wrap; }
    .pay-amount { order: 2; }
    .pay-action { order: 3; margin-left: auto; }
}

/* ------------------------------------------------ page transition */

.page-transition {
    position: fixed; inset: 0; z-index: 900; background: var(--bg);
    display: flex; align-items: center; justify-content: center; pointer-events: none;
    animation: pt-cover 0.5s ease-out 0.04s both;
}
.page-transition img { width: 132px; max-width: 42vw; animation: pt-logo 0.5s ease-out both; }
@keyframes pt-cover { 0% { opacity: 1; } 55% { opacity: 1; } 100% { opacity: 0; visibility: hidden; } }
@keyframes pt-logo { 0% { opacity: 0; transform: scale(0.86); } 45% { opacity: 1; transform: scale(1); } 100% { opacity: 0.85; transform: scale(1.03); } }

/* ------------------------------------------------------- the homepage intro

   The mark powers on where it lives. A bright line slides across the middle of
   the nav bar, the logo blooms out of it, and only then do the options arrive
   either side while the page below fades up through scanlines.

   Nothing here covers the page. .pt-crt is a transparent layer carrying only
   the lines, so the content underneath stays visible and clickable throughout —
   which is the whole difference from the full-screen version this replaces.

   Every duration reads --pt-dur, set on the overlay from the admin setting,
   with the same default repeated on .intro-crt because the nav is NOT inside
   that element and cannot inherit from it. */

/* Fallback only — the body carries the real value inline from the admin
   setting. This is what the sequence runs at if that attribute is ever absent. */
.intro-crt { --pt-dur: 3000ms; }

/* the line, sliding across the middle of the bar */
.intro-crt .topnav-brand::before {
    content: ""; position: absolute; top: 50%; left: 50%;
    width: min(320px, 60vw); height: 2px; z-index: 2;
    /* Essential, not tidiness: this is ~390px wide once scaled and centred on
       the logo, so without it the beam sits invisibly at opacity 0 across the
       middle of the bar and swallows the clicks meant for the links either
       side of the mark. Caught by hit-testing the finished state. */
    pointer-events: none;
    background: linear-gradient(90deg, transparent, #cfefff 14%, #fff 50%, #cfefff 86%, transparent);
    box-shadow: 0 0 20px 3px rgba(140, 215, 255, 0.7);
    animation: pt-beam var(--pt-dur) cubic-bezier(0.2, 0.75, 0.2, 1) both;
}
@keyframes pt-beam {
    0%   { opacity: 0; transform: translate(-260%, -50%) scaleX(0.06); }
    5%   { opacity: 1; transform: translate(-210%, -50%) scaleX(0.06); }
    16%  { opacity: 1; transform: translate(-50%, -50%) scaleX(1); }
    21%  { opacity: 0.86; transform: translate(-50%, -50%) scaleX(0.97); }
    26%  { opacity: 1; transform: translate(-50%, -50%) scaleX(1.02); }
    34%  { opacity: 0.45; transform: translate(-50%, -50%) scaleX(1.16); }
    44%  { opacity: 0; transform: translate(-50%, -50%) scaleX(1.22); }
    100% { opacity: 0; transform: translate(-50%, -50%) scaleX(1.22); }
}

/* the mark, unfolding out of the line. Same four filter functions in every
   keyframe, and brightness only ever falls — both are asserted in the tests. */
.intro-crt .topnav-brand img { animation: pt-crt-logo var(--pt-dur) cubic-bezier(0.2, 0.75, 0.2, 1) both; }
@keyframes pt-crt-logo {
    0%, 24% { opacity: 0; transform: scaleY(0.04);
              filter: brightness(7) blur(4px) drop-shadow(6px 0 0 rgba(255, 32, 96, 0)) drop-shadow(-6px 0 0 rgba(0, 224, 255, 0)); }
    30%     { opacity: 1; transform: scaleY(0.1);
              filter: brightness(7) blur(4px) drop-shadow(6px 0 0 rgba(255, 32, 96, 0.5)) drop-shadow(-6px 0 0 rgba(0, 224, 255, 0.5)); }
    38%     { opacity: 1; transform: scaleY(1.1);
              filter: brightness(3.4) blur(1.6px) drop-shadow(3px 0 0 rgba(255, 32, 96, 0.5)) drop-shadow(-3px 0 0 rgba(0, 224, 255, 0.5)); }
    45%     { opacity: 0.84; transform: scaleY(0.98);
              filter: brightness(1.5) blur(0) drop-shadow(1px 0 0 rgba(255, 32, 96, 0.3)) drop-shadow(-1px 0 0 rgba(0, 224, 255, 0.3)); }
    52%     { opacity: 1; transform: scaleY(1);
              filter: brightness(1) blur(0) drop-shadow(0 0 0 rgba(255, 32, 96, 0)) drop-shadow(0 0 0 rgba(0, 224, 255, 0)); }
    100%    { opacity: 1; transform: scaleY(1);
              filter: brightness(1) blur(0) drop-shadow(0 0 0 rgba(255, 32, 96, 0)) drop-shadow(0 0 0 rgba(0, 224, 255, 0)); }
}

/* ...and only then the rest of the bar. The options sit to the right of the
   mark on desktop, so they unfurl rightwards out of it; the burger and the
   account controls come in from the edges they live on. */
.intro-crt .topnav-side-l { animation: nav-side-l var(--pt-dur) cubic-bezier(0.2, 0.8, 0.2, 1) both; }
.intro-crt .topnav-links { animation: nav-side-l var(--pt-dur) cubic-bezier(0.2, 0.8, 0.2, 1) both; }
.intro-crt .topnav-side-r { animation: nav-side-r var(--pt-dur) cubic-bezier(0.2, 0.8, 0.2, 1) both; }
@keyframes nav-side-l {
    0%, 50% { opacity: 0; transform: translateX(-26px); }
    72%     { opacity: 1; transform: translateX(0); }
    100%    { opacity: 1; transform: translateX(0); }
}
@keyframes nav-side-r {
    0%, 50% { opacity: 0; transform: translateX(26px); }
    72%     { opacity: 1; transform: translateX(0); }
    100%    { opacity: 1; transform: translateX(0); }
}

/* the page below, fading up through the lines */
.intro-crt main, .intro-crt .site-foot { animation: intro-page var(--pt-dur) ease-out both; }
@keyframes intro-page {
    0%, 26% { opacity: 0; }
    64%     { opacity: 1; }
    100%    { opacity: 1; }
}

/* the lines themselves: a transparent layer over everything, covering nothing */
.page-transition.pt-crt {
    background: none;
    animation: pt-cover-crt var(--pt-dur, 3000ms) ease-out both;
}
@keyframes pt-cover-crt { 0%, 74% { opacity: 1; } 100% { opacity: 0; visibility: hidden; } }
.pt-crt::before,
.pt-crt::after { content: ""; position: absolute; inset: 0; pointer-events: none; }
.pt-crt::before {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)'/%3E%3C/svg%3E");
    background-size: 160px 160px;
    animation: pt-noise var(--pt-dur, 3000ms) steps(6, end) both;
}
@keyframes pt-noise {
    0%   { opacity: 0.13; background-position: 0 0; }
    30%  { opacity: 0.10; background-position: 41px 17px; }
    60%  { opacity: 0.06; background-position: -27px 52px; }
    100% { opacity: 0;    background-position: 15px 33px; }
}
.pt-crt::after {
    background:
        linear-gradient(180deg, rgba(190, 235, 255, 0) 0%, rgba(190, 235, 255, 0.10) 45%, rgba(190, 235, 255, 0.17) 50%, rgba(190, 235, 255, 0.10) 55%, rgba(190, 235, 255, 0) 100%),
        repeating-linear-gradient(180deg, rgba(0, 0, 0, 0.34) 0 1px, rgba(0, 0, 0, 0) 1px 3px);
    background-size: 100% 26%, 100% 3px;
    background-repeat: no-repeat, repeat;
    animation: pt-scan var(--pt-dur, 3000ms) ease-out both,
               pt-roll calc(var(--pt-dur, 3000ms) * 0.42) linear 0s 2 normal both;
}
@keyframes pt-scan { 0% { opacity: 0.5; } 60% { opacity: 0.3; } 88% { opacity: 0.2; } 100% { opacity: 0; } }
@keyframes pt-roll {
    0%   { background-position: 0 -40%, 0 0; }
    100% { background-position: 0 140%, 0 0; }
}

/* ------------------------------------------------------ tips and reviews

   The review star is the one yellow thing in the interface, which is the whole
   reason it works as a signal: it sits next to a receipt icon in the same ghost
   button, and the colour is what distinguishes "here is what you paid" from
   "tell us how it went". */
.btn-star .ic { color: #f6c445; }
.btn-star:hover { border-color: rgba(246, 196, 69, 0.5); background: rgba(246, 196, 69, 0.12); }
.btn-star:hover .ic { color: #ffd873; }

/* The rating control. Rendered in reverse order in the markup so that a plain
   sibling selector can light every star to the LEFT of the hovered one — with
   the stars in reading order, CSS has no way to look backwards. */
.star-pick { border: 0; padding: 0; margin: 0 0 18px; }
.star-pick legend { font-size: 12.5px; font-weight: 600; letter-spacing: 0.04em; color: var(--text-2); margin-bottom: 8px; padding: 0; }
.star-row { display: inline-flex; flex-direction: row-reverse; gap: 4px; }
.star-row input { position: absolute; opacity: 0; width: 1px; height: 1px; pointer-events: none; }
.star-row label {
    font-size: 30px; line-height: 1; cursor: pointer; color: var(--line-2);
    transition: color 0.12s, transform 0.12s;
}
.star-row label:hover,
.star-row label:hover ~ label,
.star-row input:checked ~ label { color: #f6c445; }
.star-row label:hover { transform: scale(1.12); }
/* Keyboard users get the same ring the rest of the site uses; without this the
   control is invisible to them, since the real input is off-screen. */
.star-row input:focus-visible + label { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 4px; }

.review-card { max-width: 640px; }
.review-form .form-actions { display: flex; gap: 10px; margin-top: 18px; }

/* The admin list. Filled stars for the score, the remainder greyed rather than
   dropped, so four out of five reads as four out of five at a glance instead of
   as four stars of an unknown total. */
/* ------------------------------------------------------------ client jobs

   One card per job, laid out so the three things you check — is there a
   contract, has the money come in, has it been reviewed — sit on one line and
   can be read down the page without opening anything. */
.jobs-bar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 18px; }
.jobs-filters { display: flex; gap: 6px; flex-wrap: wrap; margin-right: auto; }
.jobs-bar input[type="search"] { width: 220px; }

/* Recording a job. Collapsed once there are jobs to look at, open when the
   page is empty — with nothing on it, "how do I add one" is the only question
   the page has to answer. */
.job-new { margin-bottom: 16px; }
.job-new > summary { cursor: pointer; font-weight: 700; font-size: 14px; display: flex; align-items: center; gap: 8px; list-style: none; }
.job-new > summary::-webkit-details-marker { display: none; }
.job-new > summary .ic { color: var(--accent-2); }
.job-new-form { margin-top: 16px; }
.job-attach { display: flex; gap: 6px; align-items: center; width: 100%; }
.job-attach select { flex: 1 1 auto; min-width: 0; font-size: 12.5px; padding: 6px 8px; }

/* ================================================================= clients

   The client is the hub: their jobs, contracts, payments and history are tabs
   on one profile rather than four screens, and everything is created from
   there. What follows is the list, the profile, and the two row partials
   (a job, a payment) that appear in several places and must look the same in
   all of them. */

.avatar-sm { width: 22px; height: 22px; font-size: 10px; }
.avatar-xl { width: 56px; height: 56px; font-size: 21px; }

/* ---- the list ---- */
.toolbar-search { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; flex: 1; min-width: 0; }
.toolbar-search select { font-size: 13px; padding: 7px 10px; }

.client-totals { display: flex; gap: 18px; flex-wrap: wrap; margin: 0 0 14px; font-size: 12.5px; color: var(--text-3); }
.client-totals strong { color: var(--text-2); }
.client-totals-owed strong { color: var(--warn); }

.client-table td { vertical-align: middle; }
.client-cell { display: flex; align-items: center; gap: 10px; min-width: 0; text-decoration: none; }
.client-cell-who { display: flex; flex-direction: column; min-width: 0; line-height: 1.3; }
.client-avatar { flex: none; }
.client-owed { color: var(--warn); font-weight: 650; font-size: 13px; }

/* ---- the profile header ---- */
.client-head {
    display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
    background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-lg);
    padding: 18px 20px; margin-bottom: 14px;
}
.client-head-avatar { flex: none; }
.client-head-id { flex: 1 1 260px; min-width: 0; }
.client-head-name { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; font-size: 20px; margin: 0 0 10px; }
.client-head-stats { display: flex; gap: 26px; flex-wrap: wrap; }
.client-head-stats span { display: flex; flex-direction: column; gap: 2px; }
.client-head-stats small { font-size: 10.5px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-3); }
.client-head-stats strong { font-size: 16px; color: var(--text); }
.client-head-actions { display: flex; gap: 8px; flex-wrap: wrap; flex: none; margin-left: auto; }

/* ---- tabs within the profile ----
   Sub-navigation, so visibly lighter than the sidebar: these switch a view,
   they do not move you somewhere else. */
.subtabs { display: flex; gap: 2px; flex-wrap: wrap; border-bottom: 1px solid var(--line); margin-bottom: 18px; }
.subtab {
    position: relative; padding: 9px 14px; font-size: 13.5px; font-weight: 600;
    color: var(--text-3); text-decoration: none; border-radius: 8px 8px 0 0;
}
.subtab:hover { color: var(--text); background: var(--surface-2); }
.subtab.is-active { color: var(--text); }
.subtab.is-active::after {
    content: ''; position: absolute; left: 10px; right: 10px; bottom: -1px;
    height: 2px; border-radius: 2px 2px 0 0; background: var(--accent);
}
.subtab-badge {
    display: inline-flex; align-items: center; justify-content: center; min-width: 17px; height: 17px;
    padding: 0 5px; margin-left: 4px; border-radius: 999px;
    background: var(--accent-soft); color: var(--accent-2); font-size: 10.5px; font-weight: 700;
}

.client-cols { display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: 16px; align-items: start; }
.client-col-main { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
.client-col-side { display: flex; flex-direction: column; gap: 14px; position: sticky; top: calc(var(--topbar-h, 0px) + 20px); }
.client-split { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 14px; }
.client-project-h { display: inline-flex; align-items: center; gap: 8px; color: var(--proj, var(--text)); }

.client-attn { border-color: var(--accent-line); }
.attn-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; font-size: 13px; color: var(--text-2); }
.attn-list li { display: flex; align-items: center; gap: 8px; }
.attn-list svg { color: var(--accent-2); flex: none; }

.projlist { list-style: none; margin: 0 0 12px; padding: 0; display: flex; flex-direction: column; gap: 7px; }
.projlist li { display: flex; align-items: center; justify-content: space-between; gap: 10px; font-size: 13px; }
.projlist-name { display: inline-flex; align-items: center; gap: 7px; color: var(--proj, var(--text-2)); min-width: 0; }
.projnew { display: flex; gap: 6px; padding-top: 10px; border-top: 1px solid var(--line); }
.projnew input { flex: 1; min-width: 0; font-size: 12.5px; padding: 6px 9px; }

/* ---- the shared row partials ---- */
.joblist, .doclist, .paylist { display: flex; flex-direction: column; gap: 6px; }

.jobrow {
    display: flex; align-items: center; gap: 12px; padding: 10px 12px;
    border: 1px solid transparent; border-radius: 10px; background: var(--bg-2); text-decoration: none;
}
.jobrow:hover { border-color: var(--line-2); background: var(--surface-2); }
.jobrow.is-draft { border-style: dashed; border-color: var(--line-2); background: none; }
.jobrow-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.jobrow-title { font-size: 14px; font-weight: 650; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.jobrow-sub { font-size: 11.5px; color: var(--text-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.jobrow-next { color: var(--warn); }
.jobrow .chip { flex: none; }

.docrow, .payrow {
    display: flex; align-items: center; gap: 11px; padding: 9px 12px;
    border: 1px solid transparent; border-radius: 10px; background: var(--bg-2); text-decoration: none;
}
a.docrow:hover { border-color: var(--line-2); background: var(--surface-2); }
.docrow-ic, .payrow-ic { color: var(--text-3); flex: none; display: inline-flex; }
.docrow-main, .payrow-main { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
.payrow-amt { font-size: 13px; font-weight: 650; color: var(--text); flex: none; }
.payrow.pay-draft { opacity: 0.75; border-style: dashed; border-color: var(--line-2); background: none; }
.docrow .chip, .payrow .chip { flex: none; }

/* ---- per-payment actions ----
   Behind a menu rather than a row of buttons. These are occasional corrections
   — mark it paid, void it, change the link — and five controls on every line
   would bury the one thing the row exists to tell you, which is where the
   money is. */
.payrow-menu { position: relative; flex: none; }
.payrow-menu-btn {
    display: inline-flex; align-items: center; justify-content: center;
    width: 28px; height: 28px; border-radius: 8px;
    border: 1px solid transparent; background: none; color: var(--text-3); cursor: pointer;
}
.payrow-menu-btn:hover { background: var(--surface-2); border-color: var(--line); color: var(--text); }
.payrow-menu.open .payrow-menu-btn { background: var(--surface-2); border-color: var(--line-2); color: var(--text); }
.payrow-menu-pop {
    position: absolute; right: 0; top: calc(100% + 6px); z-index: 60; min-width: 216px;
    background: var(--surface); border: 1px solid var(--line-2); border-radius: 11px;
    padding: 5px; box-shadow: var(--shadow);
}
.payrow-menu-pop form { display: block; }
.payrow-menu-pop button, .payrow-menu-pop a {
    width: 100%; display: flex; align-items: center; gap: 9px;
    padding: 8px 10px; border: 0; border-radius: 8px; background: none;
    font-size: 13px; font-weight: 500; color: var(--text-2); text-align: left;
    cursor: pointer; text-decoration: none;
}
.payrow-menu-pop button:hover, .payrow-menu-pop a:hover { background: var(--surface-2); color: var(--text); }
.payrow-menu-pop svg { color: var(--text-3); flex: none; }
.payrow-menu-pop small { color: var(--text-3); font-weight: 400; }
.payrow-menu-pop .is-danger { color: var(--warn); }
.payrow-menu-pop .is-danger svg { color: var(--warn); }
.payrow-menu-pop .is-danger:hover { background: color-mix(in srgb, var(--warn) 12%, transparent); }

/* ---- documents, grouped by the job that owns them ----
   A contract on its own tells you little; the same contract under "Responder
   Core" beside its addendum tells you what was agreed and when it changed. */
.doc-group-h {
    display: flex; align-items: center; gap: 8px; margin: 14px 0 7px;
    font-size: 11px; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
    color: var(--accent-2); text-decoration: none;
}
.doc-group-h:first-of-type { margin-top: 4px; }
.doc-group-h .table-sub { margin-left: auto; letter-spacing: 0; text-transform: none; font-weight: 500; }
.doc-group-h:hover { color: var(--accent-3); }
.doc-group-loose { color: var(--text-3); }

/* ---- activity, by day ----
   The shape matters more than the entries: a burst on one day then a fortnight
   of silence is the thing worth seeing, and a flat run of rows hides it. */
.actday { display: flex; align-items: center; gap: 10px; margin: 16px 0 4px; }
.actday:first-of-type { margin-top: 0; }
.actday-label { font-size: 11px; font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase; color: var(--text-3); }
.actday-count {
    font-size: 10.5px; color: var(--text-3); background: var(--bg-2);
    border: 1px solid var(--line); border-radius: 999px; padding: 1px 7px;
}
.actrow-ic { color: var(--text-3); flex: none; display: inline-flex; margin-top: 1px; }

/* ---- studio notes ---- */
.notesform textarea {
    width: 100%; resize: vertical; font-size: 13px; line-height: 1.55;
    padding: 9px 10px; margin-bottom: 8px;
    background: var(--bg-2); border: 1px solid var(--line); border-radius: 9px; color: var(--text);
}
.notesform textarea:focus { outline: none; border-color: var(--accent); background: var(--surface-2); }
.notesform textarea::placeholder { color: var(--text-3); }
.actlist { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.actrow { display: flex; gap: 12px; padding: 9px 0; border-bottom: 1px solid var(--line); }
.actrow:last-child { border-bottom: 0; }
.actrow-dot { width: 7px; height: 7px; margin-top: 6px; border-radius: 50%; background: var(--line-2); flex: none; }
.actrow-main { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.actrow-text { font-size: 13px; color: var(--text-2); }

/* ---- the admin dashboard ----
   Stalls above totals: a total is something to know, a stall is something to
   do, and the doing should not be underneath the knowing. */
.attn-bar { display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 16px; }
.attn-item {
    display: flex; align-items: center; gap: 10px; padding: 10px 14px;
    border: 1px solid var(--line); border-radius: 12px; background: var(--surface);
    text-decoration: none; font-size: 13px; color: var(--text-2);
}
.attn-item:hover { border-color: var(--line-2); background: var(--surface-2); color: var(--text); }
.attn-n { font-size: 17px; font-weight: 700; color: var(--text); }
.attn-danger { border-color: color-mix(in srgb, var(--warn) 40%, var(--line)); }
.attn-danger .attn-n { color: var(--warn); }
.attn-accent { border-color: var(--accent-line); }
.attn-accent .attn-n { color: var(--accent-2); }

.workgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 10px; }
.workcard { display: flex; flex-direction: column; gap: 8px; padding: 12px; border: 1px solid var(--line); border-radius: 11px; background: var(--bg-2); }
.workcard.is-draft { border-style: dashed; background: none; }
.workcard-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; }
.workcard-title { font-size: 13.5px; font-weight: 650; color: var(--text); text-decoration: none; min-width: 0; }
.workcard-title:hover { color: var(--accent-2); }
.workcard-client { display: inline-flex; align-items: center; gap: 7px; font-size: 12px; color: var(--text-3); text-decoration: none; }
.workcard-client:hover { color: var(--text); }
.workcard-foot { display: flex; align-items: center; justify-content: space-between; gap: 8px; flex-wrap: wrap; }
.workcard-owed { font-size: 12px; color: var(--warn); font-weight: 600; }

.proj-list-h { margin: 4px 0 12px; display: flex; align-items: center; gap: 8px; }

@media (max-width: 1000px) {
    .client-cols { grid-template-columns: 1fr; }
    .client-col-side { position: static; }
}
@media (max-width: 620px) {
    .client-head-actions { margin-left: 0; width: 100%; }
    .client-head-stats { gap: 16px; }
    .subtabs { overflow-x: auto; flex-wrap: nowrap; scrollbar-width: none; }
    .subtabs::-webkit-scrollbar { display: none; }
    .subtab { white-space: nowrap; }
}
/* ------------------------------------------------------------- the board

   Clients across, their work down. A card per client because that is the unit
   somebody actually thinks in — "where is Dan up to" is one card, not a scan of
   a list. Projects are sections inside it, so filing is visible rather than a
   chip you cannot act on.

   auto-fill with a min track, not a fixed column count: the number of clients
   is whatever it is, and a wide screen should use the room rather than leave a
   two-column layout stretched across it. */
.board { display: grid; grid-template-columns: repeat(auto-fill, minmax(360px, 1fr)); gap: 14px; align-items: start; }

.board-card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-lg); overflow: hidden; }
.board-card:target { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }

.board-head { display: flex; align-items: center; gap: 10px; padding: 13px 15px; border-bottom: 1px solid var(--line); }
.board-avatar { flex: none; }
.board-who { display: flex; flex-direction: column; min-width: 0; line-height: 1.3; }
.board-name { font-weight: 700; font-size: 14px; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.board-email { font-size: 11.5px; color: var(--text-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.board-stats { margin-left: auto; display: flex; gap: 5px; flex-wrap: wrap; justify-content: flex-end; flex: none; }

.board-body { padding: 6px 12px 12px; display: flex; flex-direction: column; gap: 4px; }

/* A project takes its own colour on the left edge, so two projects for the
   same client are told apart without reading their names. */
.board-project { padding: 8px 0 2px; }
.board-project + .board-project { border-top: 1px solid var(--line); }
.board-project-head { display: flex; align-items: center; gap: 8px; padding: 2px 3px 7px; }
.board-project-name {
    display: inline-flex; align-items: center; gap: 6px;
    font-size: 11px; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
    color: var(--proj, var(--text-2)); min-width: 0;
}
.board-project-name svg { flex: none; }
.board-project-count { margin-left: auto; font-size: 11px; color: var(--text-3); flex: none; }
.board-project-none .board-project-name { color: var(--text-3); }

.board-jobs { display: flex; flex-direction: column; gap: 4px; }
.board-job {
    display: flex; align-items: center; gap: 10px;
    padding: 8px 10px; border-radius: 9px; border: 1px solid transparent;
    background: var(--bg-2); text-decoration: none; min-width: 0;
}
.board-job:hover { border-color: var(--line-2); background: var(--surface-2); }
/* Dashed, the same way a draft job card was: not finished, not sent. */
.board-job.is-draft { border-style: dashed; border-color: var(--line-2); background: none; }
.board-job-main { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
.board-job-title { font-size: 13.5px; font-weight: 600; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.board-job-sub { font-size: 11.5px; color: var(--text-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* What this draft is waiting for — the reason to click it. */
.board-job-next { color: var(--warn); }
.board-job .chip { flex: none; }

.board-empty { font-size: 12.5px; color: var(--text-3); margin: 2px 3px 6px; }

/* Both creations sit on the client they belong to, collapsed so the card stays
   readable and one click from open. */
.board-foot { display: flex; gap: 8px; flex-wrap: wrap; padding: 10px 12px; border-top: 1px solid var(--line); background: var(--bg-2); }
.board-add { flex: 1 1 auto; min-width: 0; }
.board-add > summary {
    cursor: pointer; list-style: none; display: inline-flex; align-items: center; gap: 6px;
    font-size: 12px; font-weight: 600; color: var(--text-3);
}
.board-add > summary::-webkit-details-marker { display: none; }
.board-add > summary:hover { color: var(--text); }
.board-add[open] > summary { color: var(--text-2); margin-bottom: 8px; }
.board-add-form { display: flex; gap: 6px; flex-wrap: wrap; }
.board-add-form input, .board-add-form select {
    flex: 1 1 120px; min-width: 0; font-size: 12.5px; padding: 6px 9px;
    background: var(--surface); border: 1px solid var(--line); border-radius: 8px; color: var(--text);
}
.board-add-form input:focus, .board-add-form select:focus { outline: none; border-color: var(--accent); }
.board-add-form button { flex: none; }

.jobs-count { font-size: 12.5px; color: var(--text-3); }

@media (max-width: 560px) {
    .board { grid-template-columns: 1fr; }
}
.job-list { display: flex; flex-direction: column; gap: 12px; }
.job-card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-lg); padding: 16px 18px; }
/* Landed on from the status buttons, which redirect back to the row. */
.job-card:target { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.job-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.job-id { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; min-width: 0; }
.job-title { font-weight: 700; font-size: 15.5px; color: var(--text); }
.job-ref { font-family: var(--font-mono); font-size: 11.5px; color: var(--text-3); }
.job-meta { display: flex; flex-wrap: wrap; gap: 6px 16px; margin-top: 8px; font-size: 12.5px; color: var(--text-3); }
.job-meta a { color: var(--text-2); }
.job-meta .ic { vertical-align: -2px; }
/* The project chip borrows the project's own colour when it has one, so a job
   is recognisable as belonging to the same client work as its siblings. */
.job-project { display: inline-flex; align-items: center; gap: 5px; color: var(--proj, var(--text-2)); }

.job-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin-top: 14px; }
.job-cell { display: flex; flex-direction: column; align-items: flex-start; gap: 5px;
    background: var(--bg-2); border: 1px solid var(--line); border-radius: 10px; padding: 10px 12px; }
.job-cell-label { font-size: 10.5px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--text-3); }
.job-cell-note { font-size: 12.5px; color: var(--text-3); }
.job-money { font-size: 13.5px; color: var(--text-2); }
.job-owed { color: var(--warn); }
.job-review-stars { color: #f6c445; font-size: 14px; letter-spacing: 1px; }

.job-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }
/* The one you press most gets the accent, without becoming a primary button —
   it is still one of several things you might do to this row. */
.btn-complete { border-color: var(--accent-line); color: var(--accent-3); }
.btn-complete:hover { background: var(--accent-soft); color: var(--accent-3); }

/* A draft is not yet anybody else's business, and the list should say so
   before you read a word of it. Dashed, because the thing is not finished. */
.job-card-draft { border-style: dashed; border-color: var(--line-2); }
.job-card-draft .job-title { color: var(--text-2); }
/* What is missing before this can be sent, in the colour of a thing to do. */
.job-cell-todo { color: var(--warn); }

/* ---------------------------------------------------- the job workspace */

/* Two columns: the work down the left in the order it happens, the things you
   act on once down the right. Collapses to one column early — the send panel
   below a half-built job reads as the next step, which is exactly right. */
.job-cols { display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: 16px; align-items: start; }
.job-col-main { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.job-col-side { display: flex; flex-direction: column; gap: 16px; position: sticky; top: 88px; }

/* The pipeline as a track. It is read far more often than it is clicked, so it
   is a statement of where the job is rather than a set of controls — the
   paperwork stages are not the admin's to pick. */
.job-track-card { margin-bottom: 16px; }
.job-track { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.job-step { display: inline-flex; align-items: center; gap: 7px; font-size: 12.5px; color: var(--text-3); }
.job-step + .job-step::before { content: ""; width: 18px; height: 1px; background: var(--line-2); margin-right: 7px; }
.job-step-dot { width: 18px; height: 18px; border-radius: 50%; border: 1.5px solid var(--line-2);
    display: inline-flex; align-items: center; justify-content: center; flex: none; }
.job-step-done .job-step-dot { background: var(--accent-soft); border-color: var(--accent-line); color: var(--accent-3); }
.job-step-done .job-step-label { color: var(--text-2); }
.job-step-now .job-step-dot { background: var(--accent); border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.job-step-now .job-step-label { color: var(--text); font-weight: 700; }

/* The contract block. */
.job-doc { display: flex; flex-direction: column; gap: 4px; }
.job-doc-name { font-weight: 650; font-size: 14px; color: var(--text); display: inline-flex; align-items: center; gap: 7px; }
.job-doc-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.job-doc-pick { display: flex; flex-wrap: wrap; gap: 8px; margin: 12px 0; }
.job-attach-form { display: flex; align-items: flex-end; gap: 8px; flex-wrap: wrap; }
.job-attach-form .field { flex: 1 1 240px; margin: 0; }

/* Payments. `Held` rows are deliberately quiet: they are real rows to you and
   nothing at all to the client, and shouting them would misrepresent that. */
.job-pay-table { margin-top: 4px; }
.job-add { margin-top: 14px; border-top: 1px solid var(--line); padding-top: 12px; }
.job-add > summary { cursor: pointer; font-weight: 650; font-size: 13px; display: flex; align-items: center; gap: 7px; list-style: none; color: var(--text-2); }
.job-add > summary::-webkit-details-marker { display: none; }
.job-add > summary .ic { color: var(--accent-2); }
.job-pay-form { margin-top: 14px; }
.job-hr { border: 0; border-top: 1px solid var(--line); margin: 18px 0 4px; }

/* The next step. One button that says what it does, because "every settable
   status as an identical ghost button" told you what was possible and nothing
   about what was next — so "is this finished?" had no obvious answer. */
.job-next { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; padding: 4px 0 12px; }
.job-next-note { flex: 1 1 220px; min-width: 0; font-size: 12.5px; color: var(--text-3); line-height: 1.5; }
.job-next form { flex: none; }

/* Going backwards is a correction, not the normal direction of travel, so the
   full set is folded away rather than sitting beside the one you want. */
.job-restage { border-top: 1px solid var(--line); padding-top: 10px; }
.job-restage > summary {
    cursor: pointer; list-style: none; display: inline-flex; align-items: center; gap: 6px;
    font-size: 12px; font-weight: 600; color: var(--text-3);
}
.job-restage > summary::-webkit-details-marker { display: none; }
.job-restage > summary:hover { color: var(--text); }
.job-restage[open] > summary { margin-bottom: 10px; }

/* An addendum is a contract on the same job, so it is indented under the
   agreement rather than sitting beside it as an equal. */
.job-doc + .job-doc { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line); }
.job-doc-addendum { padding-left: 14px; border-left: 2px solid var(--line-2); }
.job-doc-name { flex-wrap: wrap; }
.job-doc-name .chip { flex: none; }

/* Combining. Sits with the other options because it is the same kind of
   decision — one that changes what this job is. */
/* Stacked, and the button full width. Combining is two steps — choose, then
   confirm — and side by side the select ate the row while the button sat small
   and ghosted at the end of it, which reads as "picking the job is the action".
   It is not: nothing happens until the button is pressed. */
/* width and align-self are explicit because the container it sits in wins on
   specificity: `.job-danger .job-option` (two classes) sets align-items to
   flex-start and beats `.job-option-merge`, so the form was sized to its
   content rather than to the panel. */
.job-merge-form { display: flex; flex-direction: column; gap: 8px; margin-top: 10px;
    width: 100%; align-self: stretch; }
.job-merge-form select { width: 100%; min-width: 0; font-size: 13px; padding: 8px 10px; }
.job-merge-form button { width: 100%; justify-content: center; }
.job-option-merge { flex-direction: column; align-items: stretch; }
.job-status-row { display: flex; flex-wrap: wrap; gap: 8px; }

/* Send. The one action this whole screen builds up to, so it sits at the top
   of the sidebar and is the only primary button on the page. */
.job-send-card { border-color: var(--accent-line); }
.job-deliver-form { margin-top: 12px; }
.job-newproj { margin-top: 14px; border-top: 1px solid var(--line); padding-top: 14px; }

.job-client { display: flex; flex-direction: column; gap: 2px; margin: 0 0 12px; }
.job-dl { display: flex; flex-direction: column; gap: 8px; margin: 0; }
.job-dl > div { display: flex; justify-content: space-between; gap: 12px; font-size: 12.5px; }
.job-dl dt { color: var(--text-3); margin: 0; }
.job-dl dd { color: var(--text-2); margin: 0; text-align: right; }

/* ------------------------------------------------- adopting existing work */

/* Work that predates jobs, offered for adoption. Sits above the job list
   because it is a thing to clear, not a thing to browse — and disappears
   entirely once there is nothing left to bring in. */
.job-adopt { margin-bottom: 16px; }
.job-adopt > summary { cursor: pointer; font-weight: 700; font-size: 14px; display: flex; align-items: center; gap: 8px; list-style: none; }
.job-adopt > summary::-webkit-details-marker { display: none; }
.job-adopt > summary .ic { color: var(--accent-2); }
.job-adopt-table { margin: 14px 0; }
.job-adopt form { margin-top: 4px; }

.job-loose-list { display: flex; flex-direction: column; gap: 8px; margin-top: 12px; }
.job-loose-row { display: flex; align-items: center; justify-content: space-between; gap: 12px;
    background: var(--bg-2); border: 1px solid var(--line); border-radius: 10px; padding: 9px 12px; }
.job-loose-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }

/* ------------------------------------------------------------ job options */

/* Withdraw, hide and delete. Laid out as rows with the consequence written
   next to each, because the difference between them is the whole decision and
   three similar-looking buttons would hide it. */
.job-danger .job-option { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px;
    padding: 12px 0; border-top: 1px solid var(--line); }
.job-danger .job-option:first-of-type { border-top: 0; padding-top: 4px; }
.job-option-body { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.job-option-body strong { font-size: 13.5px; color: var(--text); }
.job-option-body small { font-size: 12px; color: var(--text-3); line-height: 1.5; }
/* Unavailable, and saying why — not a greyed-out button with no explanation. */
.job-option-off .job-option-body strong { color: var(--text-3); }
.job-danger .job-option form { flex: none; }
@media (max-width: 1080px) {
    .job-cols { grid-template-columns: 1fr; }
    .job-col-side { position: static; }
}

@media (max-width: 760px) {
    .job-grid { grid-template-columns: 1fr; }
    .jobs-bar input[type="search"] { width: 100%; }
}

.review-list { display: flex; flex-direction: column; gap: 2px; }
.review-item { padding: 16px 0; border-top: 1px solid var(--line); }
.review-item:first-child { border-top: 0; }
.review-item-head { display: flex; align-items: baseline; flex-wrap: wrap; gap: 10px; }
.review-stars { color: #f6c445; font-size: 15px; letter-spacing: 1px; }
.review-stars-off { color: var(--line-2); }
.review-job { font-weight: 700; color: var(--text); }
.review-by { color: var(--text-3); font-size: 12.5px; }
.review-body { margin: 10px 0 0; color: var(--text-2); font-size: 14px; line-height: 1.6; max-width: 72ch; }
.review-actions { display: flex; gap: 8px; margin-top: 12px; }

/* The tip panel. Quiet on purpose: it sits under the payments a client already
   owes, and a donation prompt that shouts next to an invoice reads as pressure. */
/* The tip card. `.side-card` deliberately carries no padding of its own — each
   card supplies its own body — so this provides one at the same 14px gutter the
   head above it uses, and the two line up. */
.tip-body { padding: 14px; }
.tip-blurb { color: var(--text-2); font-size: 12.5px; line-height: 1.55; margin: 0 0 12px; }

/* Three presets across, the custom box filling the row beneath. A fixed
   three-column grid rather than wrapping flex: with flex the row broke wherever
   the widths happened to land, which is what put "Other" and a lone blue square
   on their own line looking like an accident. */
.tip-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.tip-preset {
    /* An explicit height, because a <button> and an <input> with identical
       padding, font and border still come out different sizes — measured 36.8
       against 41.3 — and the row only reads as one set of choices if they
       match exactly. box-sizing is border-box site-wide, so this is the whole
       box. */
    height: 40px; padding: 0 8px;
    font: 700 13.5px/1 var(--font-ui); border-radius: 10px;
    border: 1px solid var(--line-2); background: var(--surface-2); color: var(--text);
    cursor: pointer; text-align: center; transition: border-color 0.15s, background 0.15s;
}
/* The button centres its label with flex; the input does it natively, and
   would ignore align-items anyway. */
button.tip-preset { display: inline-flex; align-items: center; justify-content: center; }
.tip-preset:hover { border-color: var(--accent); background: var(--accent-soft); }
/* "Other amount" spans the row beneath the presets. It is a button now, not an
   input: every amount is chosen in the dialog, so the card has nothing to type
   into and nothing that could be submitted half-filled. */
.tip-other {
    grid-column: 1 / -1;
    display: inline-flex; align-items: center; justify-content: center; gap: 6px;
    color: var(--text-2); font-weight: 600;
}
.tip-other svg { flex: 0 0 auto; }

/* The same amounts inside the dialog. Wrapping flex here rather than the card's
   fixed three columns: the dialog is wider, the count is whatever the studio
   configured, and there is no input sharing the row to line up with.

   Centred, so that a count which does not divide evenly into the width leaves a
   balanced last row rather than one orphan hard against the left edge. The
   heading above it is left-aligned with everything else in the dialog; this row
   is a set of choices and reads as one. */
.tip-choices { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; }
.tip-choice {
    /* Narrower than it looks like it needs: five of these plus their gaps come
       to about 460px inside a 512px dialog, which is what keeps the row on one
       line at the default set of amounts. */
    height: 40px; min-width: 68px; padding: 0 12px;
    display: inline-flex; align-items: center; justify-content: center;
    font: 700 14px/1 var(--font-ui); border-radius: 10px;
    border: 1px solid var(--line-2); background: var(--surface-2); color: var(--text);
    cursor: pointer; transition: border-color .15s, background .15s, color .15s;
}
.tip-choice:hover { border-color: var(--accent); background: var(--accent-soft); }
/* Lit when it matches what is in the amount box — set by the box as much as by
   the button, so typing 25 lights the £25 preset too. */
.tip-choice.is-on { border-color: var(--accent); background: var(--accent-soft); color: var(--accent-2); }

#tip-amount { font: 700 16px/1 var(--font-ui); font-variant-numeric: tabular-nums; }

/* What they have already given, under a rule at the foot of the card.
   A real border rather than a spacer: the card asks for something above it and
   reports below it, and those are different jobs that should look it. */
.tip-history { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--line); }
.tip-history-head {
    display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
    margin-bottom: 9px; font-size: 12px; color: var(--text-3);
}
.tip-history-head strong { color: var(--success); font-size: 13px; font-variant-numeric: tabular-nums; }

/* Capped and scrolling. A generous tipper should not push the rest of the
   sidebar off the screen, and the receipts are all still reachable. */
.tip-history-list {
    list-style: none; margin: 0; padding: 0;
    display: flex; flex-direction: column; gap: 10px;
    max-height: 232px; overflow-y: auto;
}
.tip-history-list > li {
    padding: 9px 11px; border-radius: 10px;
    background: var(--surface-2); border: 1px solid var(--line);
}
.tip-history-main { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.tip-history-amt { font-weight: 700; font-size: 13.5px; font-variant-numeric: tabular-nums; }
.tip-history-when { font-size: 11.5px; color: var(--text-3); white-space: nowrap; }
/* The note is the client's own words, so it wraps rather than truncating. */
.tip-history-note {
    margin: 5px 0 0; font-size: 12px; line-height: 1.5; color: var(--text-2);
    overflow-wrap: anywhere;
}
.tip-history-receipt {
    display: inline-flex; align-items: center; gap: 5px; margin-top: 7px;
    font-size: 11.5px; color: var(--text-3); text-decoration: none;
}
.tip-history-receipt:hover { color: var(--accent-3); }
.tip-history-receipt svg { flex: 0 0 auto; }

/* Beside a Pay button rather than under it: narrow, quiet, clearly optional.
   It carries no default value, so an untouched form charges exactly the
   invoice. */
.tip-inline { width: 78px; font-size: 13px; padding: 6px 8px; margin-right: 6px; }
@media (max-width: 560px) { .tip-inline { width: 64px; } }
/* Beside a Pay button rather than under it: narrow, quiet, and clearly
   optional. It carries no default value, so an untouched form charges
   exactly the invoice. */
.tip-inline { width: 78px; font-size: 13px; padding: 6px 8px; margin-right: 6px; }
@media (max-width: 560px) { .tip-inline { width: 64px; } }

/* ---------------------------------------------- impersonation bar */

.impersonate-bar {
    position: fixed; left: 50%; bottom: 18px; transform: translateX(-50%);
    z-index: 300; display: flex; align-items: center; gap: 14px;
    background: linear-gradient(180deg, #c08528, #9c6712); color: #fff;
    border: 1px solid rgba(0, 0, 0, 0.35); border-radius: 999px;
    padding: 8px 10px 8px 18px; box-shadow: var(--shadow); max-width: calc(100vw - 24px);
    animation: toast-in 0.25s ease-out;
}
.impersonate-text { display: inline-flex; align-items: center; gap: 8px; font-size: 13.5px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.impersonate-return { margin: 0; flex: none; }
.impersonate-btn { background: rgba(255, 255, 255, 0.16); color: #fff; border: 1px solid rgba(255, 255, 255, 0.32); border-radius: 999px; }
.impersonate-btn:hover { background: rgba(255, 255, 255, 0.26); color: #fff; }

/* --------------------------------------------------- dashboard v2 */

.dash-hero { margin-bottom: 22px; }
.dash-hello { font-family: var(--font-display); font-size: 32px; font-weight: 800; letter-spacing: -0.025em; margin: 6px 0; line-height: 1.1; }
.dash-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(158px, 1fr)); gap: 12px; margin-bottom: 32px; }
.dash-stat {
    display: flex; align-items: center; gap: 13px;
    background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 14px 16px;
    transition: border-color 0.15s, transform 0.15s;
}
.dash-stat:hover { border-color: var(--line-2); transform: translateY(-2px); }
.dash-stat-ic { display: flex; align-items: center; justify-content: center; width: 40px; height: 40px; border-radius: 11px; flex: none; background: var(--surface-2); border: 1px solid var(--line-2); color: var(--accent-2); }
.dash-stat-num { font-family: var(--font-display); font-size: 22px; font-weight: 800; line-height: 1.05; font-variant-numeric: tabular-nums; letter-spacing: -0.01em; }
.dash-stat-label { color: var(--text-3); font-size: 12px; margin-top: 1px; }
.dash-stat-attn { border-color: var(--accent-line); }
.dash-stat-attn .dash-stat-ic { border-color: var(--accent-line); }
.dash-stat-over { border-color: rgba(224, 108, 95, 0.4); background: linear-gradient(180deg, rgba(224, 108, 95, 0.06), var(--surface)); }
.dash-stat-over .dash-stat-ic { color: var(--danger); border-color: rgba(224, 108, 95, 0.4); }
.dash-stat-over .dash-stat-num { font-size: 16px; }
.dash-stat-over .dash-stat-label { color: var(--danger); }

/* each dashboard section is its own bordered panel */
.dash-section { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-lg); padding: 18px 20px 10px; margin-bottom: 20px; }
.dash-section-head { display: flex; align-items: center; justify-content: space-between; gap: 14px 20px; margin-bottom: 12px; flex-wrap: wrap; }
.dash-section-head .list-tools { flex: 1; min-width: 220px; margin: 0; }
.section-link { display: inline-flex; align-items: center; gap: 4px; color: var(--text-2); font-size: 13px; font-weight: 600; }
.section-link:hover { color: var(--accent-2); }
/* rows inside a panel are flat + divider-separated (no cards-in-cards) */
.dash-section .doc-list, .dash-section .pay-list, .dash-section .commission-list { gap: 0; }
.dash-section .doc-row, .dash-section .pay-row, .dash-section .commission-row {
    background: transparent; border: 0; border-bottom: 1px solid var(--line); border-radius: 0; padding: 13px 4px; transform: none;
}
.dash-section .doc-row:hover, .dash-section .pay-row:hover, .dash-section .commission-row:hover { background: rgba(255, 255, 255, 0.03); transform: none; color: var(--text); }
.dash-section .doc-list .doc-row:last-child, .dash-section .pay-list .pay-row:last-child, .dash-section .commission-list .commission-row:last-child { border-bottom: 0; }
.dash-section .pay-row.pay-unpaid { border-left: 3px solid var(--accent); padding-left: 12px; }
.dash-section .pay-row.pay-overdue { border-left: 3px solid var(--danger); padding-left: 12px; }

/* two-column dashboard body: documents (main) + a payments rail */
.dash-grid { display: grid; grid-template-columns: 1fr; column-gap: 24px; align-items: start; }
.dash-col { min-width: 0; }
.dash-col-main > .dash-section:last-child,
.dash-col-rail > .dash-section:last-child { margin-bottom: 0; }

@media (min-width: 921px) {
    /* Equal halves. Was minmax(0,1fr) 344px, which gave documents the whole
       remainder and squeezed payments into a rail too narrow for a title, an
       amount and a Pay button. */
    .dash-grid:not(.dash-grid-single) { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }

    /* Each payment is a compact card: glyph + title on top, amount and action
       in a footer row. Keeps a long agreement title from ever competing with
       the button for the same line. */
    .dash-col-rail .pay-list { gap: 0; }
    .dash-col-rail .pay-row {
        /* col 2 MUST floor at 0, not min-content: .pay-title is white-space:
           nowrap, so its min-content is the full untruncated title and the row
           grows past the column instead of ellipsising. That was the clipping. */
        display: grid; grid-template-columns: 40px minmax(0, 1fr) auto;
        align-items: center; column-gap: 12px; row-gap: 13px; padding: 15px 16px;
    }
    .dash-col-rail .pay-glyph { grid-column: 1; grid-row: 1; align-self: start; }
    .dash-col-rail .pay-main { grid-column: 2 / -1; grid-row: 1; }
    .dash-col-rail .pay-amount { grid-column: 2; grid-row: 2; justify-self: start; }
    .dash-col-rail .pay-action { grid-column: 3; grid-row: 2; justify-self: end; }
    .dash-col-rail .pay-action form { display: flex; }
    .dash-col-rail .pay-action .btn { white-space: nowrap; }
}

/* ---- admin payments: client → project → payments ------------------------
   Same shape the client sees on their own dashboard, so a conversation about a
   payment is about the same thing on both sides. */
.pay-client {
    border: 1px solid var(--line); border-radius: var(--radius);
    background: var(--surface); overflow: hidden; margin-bottom: 16px;
}
.pay-client-due  { border-color: var(--accent-line); }
.pay-client-over { border-color: rgba(224, 108, 95, 0.5); }
/* The whole bar is the toggle. list-style/marker off because the caret beside
   the name is the affordance, and a native triangle would sit outside the flex
   row and break the two-column head. */
.pay-client-head {
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    flex-wrap: wrap; padding: 12px 16px; cursor: pointer; list-style: none;
    background: var(--surface-2); border-bottom: 1px solid var(--line);
}
.pay-client-head::-webkit-details-marker { display: none; }
.pay-client-head:hover .pay-client-name { color: var(--accent-2); }
/* Closed, the head IS the card, so a bottom border would read as a rule ending
   in nothing. */
.pay-client:not([open]) > .pay-client-head { border-bottom: 0; }
.pay-client-caret { display: inline-flex; color: var(--text-3); transition: transform 0.15s ease; }
.pay-client[open] .pay-client-caret { transform: rotate(90deg); }
@media (prefers-reduced-motion: reduce) { .pay-client-caret { transition: none; } }
.pay-client-due .pay-client-head  { background: rgba(4, 102, 200, 0.08); }
.pay-client-over .pay-client-head { background: rgba(224, 108, 95, 0.09); }
.pay-client-id { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.pay-client-name { display: flex; align-items: center; gap: 8px; font-size: 14.5px; font-weight: 700; }
.pay-client-name svg { color: var(--accent-2); flex: none; }
.pay-client-sub { font-size: 12px; color: var(--text-3); }
.pay-client-meta { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }

.pay-proj + .pay-proj { border-top: 1px solid var(--line); }
.pay-proj-head {
    display: flex; align-items: center; justify-content: space-between; gap: 10px;
    padding: 8px 16px; background: rgba(255, 255, 255, 0.014);
}
.pay-proj-name {
    display: flex; align-items: center; gap: 7px;
    font-size: 11.5px; font-weight: 700; letter-spacing: 0.07em;
    text-transform: uppercase; color: var(--text-3);
}
.pay-proj-name svg { color: var(--text-3); }
.pay-proj-due { font-size: 12px; color: var(--text-2); font-variant-numeric: tabular-nums; }
.pay-proj-due.is-over { color: var(--danger); font-weight: 700; }
/* The section header carries the client, so these tables are narrower and the
   column headings would be noise repeated per project. */
.pay-table thead { display: none; }
.pay-table td { padding: 10px 14px; }

/* ---- payments: selection bar -------------------------------------------
   Sticky, because the table is long and the thing you are about to charge may
   be scrolled off screen when you click. */
.pick-bar {
    position: sticky; top: calc(var(--topbar-h, 0px) + 12px); z-index: 20;
    display: flex; align-items: center; justify-content: space-between; gap: 14px;
    flex-wrap: wrap; margin-bottom: 14px; padding: 11px 16px;
    border: 1px solid var(--accent); border-radius: var(--radius);
    background: var(--accent-soft); box-shadow: var(--shadow);
}
.pick-bar[hidden] { display: none; }
.pick-bar-count small { display: block; font-size: 11.5px; color: var(--text-3); margin-top: 1px; }
/* Checkboxes exist only in selection mode. Permanently visible ones invite a
   stray click on the one page where a click takes money. */
.pick-col { display: none; }
body.is-picking .pick-col { display: table-cell; }
.pay-toolbar { margin-bottom: 10px; }
.pay-toolbar[hidden] { display: none; }

/* ---- compact collection toggle ---------------------------------------- */
.collect-bar {
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    flex-wrap: wrap; margin-bottom: 16px; padding: 9px 14px;
    border: 1px solid var(--line-2); border-radius: var(--radius); background: var(--surface);
}
.collect-bar.is-off { border-color: rgba(224, 108, 95, 0.5); background: rgba(224, 108, 95, 0.06); }
.collect-bar-label { display: flex; align-items: center; gap: 9px; font-size: 13.5px; flex-wrap: wrap; }
.collect-bar-label svg { color: var(--accent-2); }
.collect-bar-right { display: flex; align-items: center; gap: 10px; }
.collect-more { position: relative; }
.collect-more summary {
    cursor: pointer; list-style: none; font-size: 12.5px; color: var(--text-3);
    padding: 3px 8px; border-radius: 7px;
}
.collect-more summary::-webkit-details-marker { display: none; }
.collect-more summary:hover { color: var(--text); background: var(--surface-2); }
.collect-more-pop {
    position: absolute; right: 0; top: calc(100% + 8px); z-index: 40; width: 340px; padding: 14px;
    background: var(--surface); border: 1px solid var(--line-2); border-radius: 12px; box-shadow: var(--shadow);
}
.collect-more-pop p { font-size: 12.5px; color: var(--text-2); margin: 0 0 9px; line-height: 1.55; }
.switch-sm .switch-track { transform: scale(0.85); }

/* ---- row overflow menu -------------------------------------------------
   The less-used per-row actions live here rather than as five icons on every
   row. They are not gone: each is the only way to do its job. */
.row-more { position: relative; display: inline-flex; }
.row-more-pop {
    position: absolute; right: 0; top: calc(100% + 6px); z-index: 40; min-width: 208px; padding: 6px;
    background: var(--surface); border: 1px solid var(--line-2); border-radius: 11px; box-shadow: var(--shadow);
    display: flex; flex-direction: column; text-align: left;
}
.row-more-pop[hidden] { display: none; }
.row-more-pop form { margin: 0; }
.row-more-item {
    display: flex; align-items: center; gap: 9px; width: 100%;
    padding: 8px 10px; border: 0; border-radius: 8px; background: none; cursor: pointer;
    color: var(--text-2); font: 600 13px var(--font-ui); text-align: left;
}
.row-more-item:hover { background: rgba(255, 255, 255, 0.06); color: var(--text); }
.row-more-item svg { color: var(--text-3); flex: none; }
.row-more-item:hover svg { color: var(--accent-2); }
.row-more-item.is-on { color: var(--accent-2); }
.row-more-item.is-on svg { color: var(--accent-2); }
.pick-bar-count { font-size: 13.5px; color: var(--text-2); }
.pick-bar-count strong { color: var(--text); font-variant-numeric: tabular-nums; }
.pick-bar-actions { display: flex; align-items: center; gap: 8px; }
.pick-col { width: 34px; text-align: center; }
.pick-col input { cursor: pointer; }
/* A row that cannot be picked shows a dash, not an empty cell — an empty cell
   looks like a checkbox that failed to render. */
.pick-na { color: var(--text-3); opacity: 0.5; cursor: help; }
.toolbar-note { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--text-3); }
.toolbar-note svg { flex: none; }
#pick-start[disabled] { opacity: 0.5; cursor: not-allowed; }

/* Per-environment credential groups (Revolut sandbox / live). */
.env-set {
    border: 1px solid var(--line-2); border-radius: var(--radius);
    padding: 6px 14px 14px; margin: 0 0 14px;
}
.env-set-active { border-color: var(--accent-line); background: rgba(4, 102, 200, 0.04); }
.env-set legend {
    display: flex; align-items: center; gap: 8px; padding: 0 8px;
    font-size: 13px; font-weight: 700; color: var(--text);
}

/* ---- save-a-card page ---------------------------------------------------
   Revolut's createCardField injects its own iframes into whatever element it is
   given. An unstyled div collapses to a single thin line with the number, expiry
   and CVC crushed together, so the container has to set the height, padding and
   border that the fields sit inside. */
.savecard { max-width: 520px; margin: 0 auto; padding: 8px 0 40px; }
.savecard-head { text-align: center; margin-bottom: 22px; }
.savecard-badge {
    display: inline-flex; align-items: center; justify-content: center;
    width: 52px; height: 52px; border-radius: 15px; margin-bottom: 12px;
    background: var(--accent-soft); color: var(--accent-2); border: 1px solid var(--accent-line);
}
.savecard-head h1 { font-family: var(--font-display); font-size: 27px; font-weight: 800; letter-spacing: -0.02em; margin: 0 0 6px; }
.savecard-head p { color: var(--text-2); font-size: 14.5px; margin: 0; }
.savecard-head strong { color: var(--text); }

.savecard-box {
    border: 1px solid var(--line-2); border-radius: 16px;
    background: var(--surface); padding: 20px;
}
.savecard-sum {
    display: flex; align-items: center; justify-content: space-between; gap: 14px;
    padding: 13px 15px; margin-bottom: 20px;
    border-radius: var(--radius); background: var(--surface-2); border: 1px solid var(--line);
}
.savecard-sum-what { display: flex; flex-direction: column; gap: 2px; font-size: 14px; font-weight: 600; min-width: 0; }
.savecard-sum-what small { font-size: 12px; font-weight: 400; color: var(--text-3); }
.savecard-sum-amt { font-family: var(--font-display); font-size: 20px; font-weight: 800; font-variant-numeric: tabular-nums; white-space: nowrap; }

.savecard-label {
    display: block; font-size: 12px; font-weight: 700; letter-spacing: 0.07em;
    text-transform: uppercase; color: var(--text-3); margin-bottom: 8px;
}
.savecard-label-2 { margin-top: 16px; }
/* Matches .savecard-field exactly, so the name sits in the same kind of box as
   the Revolut-hosted fields rather than looking bolted on. */
.savecard-input {
    width: 100%; padding: 15px 16px;
    border: 1px solid var(--line-2); border-radius: 12px; background: var(--bg-2);
    color: var(--text); font: 400 15px var(--font-ui);
    transition: border-color 0.16s, box-shadow 0.16s;
}
.savecard-input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.savecard-once { text-align: center; margin-top: 16px; }
.savecard-once button {
    background: none; border: 0; cursor: pointer; padding: 4px;
    color: var(--text-3); font: 400 12.5px var(--font-ui); text-decoration: underline;
}
.savecard-once button:hover { color: var(--text-2); }
/* min-height + padding are what stop Revolut's iframes collapsing into a line. */
.savecard-field {
    min-height: 54px; padding: 15px 16px;
    border: 1px solid var(--line-2); border-radius: 12px; background: var(--bg-2);
    transition: border-color 0.16s, box-shadow 0.16s;
}
.savecard-field:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.savecard-field iframe { width: 100% !important; min-height: 24px; }
.savecard-error { margin: 10px 0 0; color: var(--danger); font-size: 13px; }
.savecard-error[hidden] { display: none; }
.savecard-go { margin-top: 18px; padding: 14px; font-size: 15px; }
.savecard-points { list-style: none; margin: 18px 0 0; padding: 0; }
.savecard-points li {
    display: flex; align-items: flex-start; gap: 9px;
    font-size: 12.5px; color: var(--text-3); line-height: 1.5; padding: 4px 0;
}
.savecard-points svg { color: var(--success); flex: none; margin-top: 2px; }
.savecard-back { text-align: center; margin-top: 18px; font-size: 13px; }

/* ---- card-on-file banner -------------------------------------------------
   Sits above everything else. Red until a card is saved, green once it is —
   the state is the whole message, so it is carried by colour and icon rather
   than requiring the sentence to be read. */
.card-state-form { margin: 0; }
/* Rendered as a <button> when it submits the setup POST, so the button's own
   defaults have to be cleared or it inherits a centred, bordered look. */
.card-state {
    display: flex; align-items: center; gap: 14px; width: 100%;
    padding: 13px 16px; margin-bottom: 18px; text-align: left;
    border: 1px solid var(--line-2); border-radius: var(--radius);
    background: var(--surface); color: var(--text);
    font: inherit; cursor: pointer;
    transition: border-color 0.16s, background 0.16s;
}
.card-state-ic {
    display: flex; align-items: center; justify-content: center; flex: none;
    width: 38px; height: 38px; border-radius: 11px;
}
.card-state-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.card-state-text strong { font-size: 14.5px; }
.card-state-text small { font-size: 12.5px; color: var(--text-3); line-height: 1.45; }
.card-state-cta {
    display: inline-flex; align-items: center; gap: 6px; flex: none;
    font-size: 13px; font-weight: 700; white-space: nowrap;
}

.card-state.is-off {
    border-color: rgba(224, 108, 95, 0.55);
    background: linear-gradient(180deg, rgba(224, 108, 95, 0.10), var(--surface));
}
.card-state.is-off:hover { border-color: var(--danger); background: rgba(224, 108, 95, 0.14); color: var(--text); }
.card-state.is-off .card-state-ic { background: rgba(224, 108, 95, 0.16); color: var(--danger); }
.card-state.is-off .card-state-cta { color: var(--danger); }

.card-state.is-on {
    border-color: rgba(127, 181, 138, 0.45);
    background: linear-gradient(180deg, rgba(127, 181, 138, 0.09), var(--surface));
}
.card-state.is-on:hover { border-color: var(--success); color: var(--text); }
.card-state.is-on .card-state-ic { background: rgba(127, 181, 138, 0.16); color: var(--success); }
.card-state.is-on .card-state-cta { color: var(--text-3); }

/* Nothing owed, so a card cannot be saved yet. Informational, not a prompt —
   a red call to action that leads nowhere is worse than a quiet note. */
.card-state.is-idle { cursor: default; }
.card-state.is-idle .card-state-ic { background: var(--surface-2); color: var(--text-3); }
.card-state.is-idle .card-state-text strong { color: var(--text-2); }

@media (max-width: 620px) {
    .card-state { flex-wrap: wrap; }
    .card-state-cta { width: 100%; justify-content: center; padding-top: 4px; }
}

/* ---- dashboard hero ------------------------------------------------------
   Its own panel rather than text floating on the page background, centred so
   the greeting reads as addressed to the person. */
.side-card { border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); overflow: hidden; }
.side-card-head {
    display: flex; align-items: center; justify-content: space-between; gap: 10px;
    padding: 11px 14px; background: var(--surface-2); border-bottom: 1px solid var(--line);
}
.side-card-head h2 { display: flex; align-items: center; gap: 8px; margin: 0; font-size: 14px; font-weight: 700; }
.side-card-head h2 svg { color: var(--accent-2); }
.side-empty { padding: 24px 18px; text-align: center; color: var(--text-3); }
.side-empty svg { color: var(--text-3); opacity: 0.5; }
.side-empty p { font-size: 12.5px; line-height: 1.55; margin: 10px 0 12px; }
.buy-list { display: flex; flex-direction: column; }
.buy-row { display: grid; grid-template-columns: 40px minmax(0, 1fr) auto; gap: 11px; align-items: center; padding: 11px 14px; }
.buy-row + .buy-row { border-top: 1px solid var(--line); }
.buy-thumb { width: 40px; height: 40px; border-radius: 9px; overflow: hidden; background: var(--surface-2); border: 1px solid var(--line-2); }
.buy-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.buy-thumb-none { display: flex; align-items: center; justify-content: center; color: var(--text-3); }
.buy-main { min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.buy-name { font-size: 13px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.buy-sub { font-size: 11.5px; color: var(--text-3); }
.buy-actions { display: flex; gap: 5px; }

/* ---- client dashboard: project → documents → payments -------------------
   The whole point is density. A payment used to be a ~90px card; here it is a
   single ~34px line sitting beside the document it belongs to, so a project
   with three instalments fits in the space one payment used to take. */

/* ==================================================== the client dashboard

   Rebuilt because the page described the same work three times: a strip of job
   rows, then a strip of things needing attention naming those same jobs, then
   the full tree containing them again. Five jobs read as fifteen.

   One list now, and one place per fact. Actions live at the top because that is
   what somebody came to do; the list below reports STATE, and asks nothing, so
   nothing is requested twice. Each job collapses — a client with five jobs and
   four instalments apiece was reading forty rows to find one — and any job that
   needs them opens itself, so nothing waiting is ever behind a click. */

.dh-head { margin-bottom: 22px; }
.dh-eyebrow { font-size: 11px; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase; color: var(--accent-2); }
.dh-hello { margin: 6px 0 4px; font-size: 30px; font-weight: 800; letter-spacing: -0.02em; }
.dh-sub { margin: 0; font-size: 14.5px; color: var(--text-2); }
.dh-sub strong { color: var(--text); }

/* ---- the page: work, then a side menu ----
   The menu holds the two things that are not work — what a client can download,
   and the tip jar. Neither belongs among the projects: one is a cupboard you
   open when you want something out of it, the other is an offer that should
   never interrupt anything. */
.dh-shell { display: grid; grid-template-columns: minmax(0, 1fr); gap: 18px; align-items: start; }
.dh-main { min-width: 0; }
.dh-side { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
@media (min-width: 1040px) {
    .dh-shell { grid-template-columns: minmax(0, 1fr) 290px; }
    .dh-side { position: sticky; top: 20px; }
}

/* Said once, at the top, instead of on every payment. A column of identical
   "AUTO" chips is one sentence printed twenty times. */
.dh-autonote {
    display: flex; align-items: center; gap: 11px; width: 100%; text-align: left;
    margin: 0 0 18px; padding: 11px 15px; border-radius: 11px;
    font-size: 13px; text-decoration: none; cursor: pointer;
    background: var(--surface); border: 1px solid rgba(127, 181, 138, 0.35); color: var(--text-2);
}
.dh-autonote > svg:first-child { color: var(--success); flex: none; }
.dh-autonote span { flex: 1; min-width: 0; }
.dh-autonote strong { color: var(--text); }
.dh-autonote:hover { background: var(--surface-2); }
.dh-autonote.is-off { border-color: var(--accent-line); }
.dh-autonote.is-off > svg:first-child { color: var(--accent-2); }

/* ---- the project wall ----
   Two columns via multi-column rather than grid. A grid row is as tall as its
   tallest cell, so one project with eight jobs left a half-screen hole beside a
   project with one — and the next card started below the hole rather than in
   it. Columns pack, and a card simply refuses to be split. */
.dh-grid { display: flex; flex-direction: column; gap: 16px; margin-bottom: 18px; }
@media (min-width: 1240px) {
    .dh-grid { display: block; column-count: 2; column-gap: 16px; }
    .dh-proj {
        break-inside: avoid; -webkit-column-break-inside: avoid;
        width: 100%; margin: 0 0 16px;
    }
}
.dh-empty { margin-top: 8px; }

/* ---- a project ----
   The artwork is a band across the top, ruled off from the work below it. It
   used to wash down the whole card behind the job rows, which put a picture
   underneath the one thing on the card you actually have to read. Confining it
   also means the rows sit on flat surface, so their hover and their overdue
   tint are the only things that change colour down there. */
.dh-proj {
    display: flex; flex-direction: column; min-width: 0; overflow: hidden;
    border-radius: 14px; border: 1px solid var(--line);
    background: var(--surface);
}
.dh-proj.is-loose { border-style: dashed; }

.dh-proj-head {
    position: relative; isolation: isolate; overflow: hidden;
    display: flex; align-items: flex-start; justify-content: space-between; gap: 14px;
    padding: 16px 16px 14px; min-height: 74px;
    border-bottom: 1px solid var(--line);
}
/* Two pseudo-elements rather than one stacked background, so the image can be
   dimmed on its own — a single background-image list would tie its opacity to
   the gradient's, and there would be no way to have strong colour over faint
   art. */
.dh-proj.has-art .dh-proj-head::before {
    content: ''; position: absolute; inset: 0; z-index: -2;
    background-image: var(--art);
    background-size: cover; background-position: center;
    opacity: 0.42;
}
/* Strongest at the top left, where the name sits, and darkest at the foot of
   the band so the divider reads as an edge rather than a seam. rgba() over
   three numbers rather than color-mix(): an unsupported color-mix() drops the
   whole declaration and leaves the artwork undimmed under the text, which is
   the one failure worth designing out. */
.dh-proj-head::after {
    content: ''; position: absolute; inset: 0; z-index: -1;
    background:
        linear-gradient(150deg,
            rgba(var(--game-rgb), 0.72) 0%,
            rgba(var(--game-rgb), 0.34) 52%,
            rgba(var(--game-rgb), 0.12) 100%),
        linear-gradient(to bottom, transparent 45%, rgba(0, 0, 0, 0.34) 100%);
}
/* No artwork, no theatre: a quiet tinted band, so an undressed project does not
   read as a broken dressed one. */
.dh-proj:not(.has-art) .dh-proj-head::after {
    background: linear-gradient(150deg, rgba(var(--game-rgb), 0.3) 0%, rgba(var(--game-rgb), 0.08) 100%);
}

.dh-proj-name {
    margin: 0; min-width: 0; font-size: 18px; font-weight: 800; letter-spacing: -0.015em;
    color: var(--text); text-shadow: 0 1px 10px rgba(0, 0, 0, 0.5);
    overflow-wrap: anywhere;
}
.dh-proj-money { display: flex; flex-direction: column; align-items: flex-end; gap: 2px; flex: none; text-align: right; }
.dh-proj-budget {
    font-size: 16px; font-weight: 800; letter-spacing: -0.01em; color: var(--text);
    font-variant-numeric: tabular-nums; text-shadow: 0 1px 10px rgba(0, 0, 0, 0.5);
}
.dh-proj-due { font-size: 12px; color: var(--text-2); font-variant-numeric: tabular-nums; }
.dh-proj-due.is-over { color: var(--warn); font-weight: 700; }
/* ---- a job, as one line ----
   Four things: what it is, when it started, what it is worth, and a button for
   each thing you can do with it. Everything that used to be nested under an
   expanded row is now either one of those buttons or in the side menu. */
.dh-jobs { list-style: none; margin: 0; padding: 0 8px 8px; display: flex; flex-direction: column; gap: 2px; }
.dh-jrow {
    display: grid; grid-template-columns: 8px minmax(0, 1fr) auto auto auto;
    align-items: center; gap: 10px;
    padding: 8px 9px; border-radius: 9px; min-width: 0;
}
.dh-jrow:hover { background: var(--surface-2); }
.dh-jrow.is-over { background: rgba(224, 108, 95, 0.07); }

/* The stage, as a dot. A client wants it at a glance far more often than they
   want to read it, and a column of words would cost the row its fourth. */
.dh-jdot { width: 8px; height: 8px; border-radius: 50%; background: var(--text-3); flex: none; }
.dh-jdot.chip-info { background: var(--accent); }
.dh-jdot.chip-accent { background: var(--accent-2); }
.dh-jdot.chip-success { background: var(--success); }
.dh-jdot.chip-muted { background: var(--text-3); }

.dh-jrow-title {
    font-size: 13.5px; font-weight: 600; color: var(--text); min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dh-jrow-date { font-size: 11.5px; color: var(--text-3); white-space: nowrap; flex: none; }
.dh-jrow-money {
    font-size: 13px; font-weight: 700; color: var(--text-2);
    font-variant-numeric: tabular-nums; white-space: nowrap; flex: none;
}
.dh-jrow.is-over .dh-jrow-money { color: var(--warn); }

/* ---- the buttons ---- */
.dh-jrow-acts { display: inline-flex; align-items: center; gap: 3px; flex: none; }
.dh-jact-form { margin: 0; display: inline-flex; }
.dh-jact {
    display: inline-flex; align-items: center; justify-content: center;
    width: 28px; height: 28px; border-radius: 8px; flex: none; cursor: pointer;
    border: 1px solid transparent; background: none; color: var(--text-3);
    transition: background 0.14s, color 0.14s, border-color 0.14s;
}
.dh-jact:hover { background: var(--surface-3); color: var(--text); border-color: var(--line-2); }
/* Something waiting on the client reads as a button, not as an icon. */
.dh-jact.is-act { background: var(--accent-soft); color: var(--accent-3); border-color: var(--accent-line); }
.dh-jact.is-over { background: rgba(224, 108, 95, 0.16); color: var(--danger); border-color: rgba(224, 108, 95, 0.45); }
/* A review is a favour, not a debt, so it asks warmly rather than urgently. */
.dh-jact.is-warm { background: rgba(246, 196, 69, 0.14); color: #f6c445; border-color: rgba(246, 196, 69, 0.4); }
.dh-jact.is-inert { cursor: default; opacity: 0.55; }
.dh-jact.is-inert:hover { background: none; border-color: transparent; color: var(--text-3); }

/* ---- a job that opens ----
   Payments live behind a disclosure because most of the time the answer is
   "nothing is due", and a schedule printed under every job is how a list stops
   being read. The caret replaced a pay icon that could only ever point at one
   instalment and could not say when, how much, or whether it collects itself. */
.dh-job { min-width: 0; }
.dh-jrow.is-open-able { cursor: pointer; list-style: none; }
.dh-jrow.is-open-able::-webkit-details-marker { display: none; }
.dh-jcaret { display: inline-flex; color: var(--text-3); flex: none; transition: transform 0.16s; }
.dh-job[open] .dh-jcaret { transform: rotate(180deg); }
.dh-job[open] > .dh-jrow { background: var(--surface-2); }

/* Hidden explicitly, not left to the browser. An explicit `display` on a
   <details> child overrides the UA rule that hides closed content, so the panel
   would still be laid out and merely clipped — present to a screen reader, and
   costing height, while looking collapsed. */
.dh-job:not([open]) .dh-pays { display: none; }

.dh-pays {
    display: flex; flex-direction: column; gap: 1px;
    margin: 1px 0 6px; padding: 4px 0 2px 26px;
    border-left: 2px solid var(--line); margin-left: 12px;
}
.dh-pay {
    display: grid; grid-template-columns: minmax(0, 1fr) auto auto;
    align-items: center; gap: 10px; padding: 6px 8px 6px 0; border-radius: 8px;
}
.dh-pay-copy { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.dh-pay-title { font-size: 12.5px; font-weight: 600; color: var(--text-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dh-pay-when { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; color: var(--text-3); }
.dh-pay-when svg { flex: none; }
.dh-pay-amt {
    font-size: 12.5px; font-weight: 700; color: var(--text-2);
    font-variant-numeric: tabular-nums; white-space: nowrap;
}
.dh-pay-act { display: inline-flex; align-items: center; justify-content: flex-end; min-width: 62px; }
.dh-pay-act form { margin: 0; }
.dh-pay-noact { font-size: 11px; color: var(--text-3); }

/* One scale for urgency, so the line and the button it carries agree:
   red once overdue, amber from three days out, green once paid. */
.dh-pay-overdue .dh-pay-when { color: var(--danger); font-weight: 700; }
.dh-pay-urgent .dh-pay-when { color: var(--warn); font-weight: 600; }
.dh-pay-paid .dh-pay-when { color: var(--success); }
/* Paid lines step back — the work is done, so they should not compete with what
   still needs doing. Not hidden: a client checking what they paid needs them. */
.dh-pay-paid { opacity: 0.66; }
.dh-pay-paid:hover { opacity: 1; }
.dh-pay-paid .dh-pay-title { font-weight: 500; }
/* ---- downloads ---- */
.dh-dl { display: flex; flex-direction: column; padding: 5px; }
.dh-dl-row {
    display: flex; align-items: center; gap: 10px; min-width: 0;
    padding: 8px 9px; border-radius: 9px; color: var(--text-2); text-decoration: none;
}
.dh-dl-row:hover { background: var(--surface-2); color: var(--text); }
.dh-dl-row > svg:first-child { color: var(--accent-2); flex: none; }
.dh-dl-row > svg:last-child { color: var(--text-3); flex: none; }
.dh-dl-copy { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
.dh-dl-copy strong { font-size: 13px; font-weight: 600; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dh-dl-copy small { font-size: 11px; color: var(--text-3); }

@media (max-width: 620px) {
    .dh-hello { font-size: 25px; }
    .dh-proj-head { padding: 13px 13px 11px; min-height: 62px; }
    .dh-proj-name { font-size: 16.5px; }
    .dh-jobs { padding: 0 6px 6px; }
    .dh-jrow { gap: 8px; padding: 8px 7px; }
    /* The date is the first thing to go: it is context, and the other three
       columns are the answer to a question. */
    .dh-jrow-date { display: none; }
}
.proj-list { display: flex; flex-direction: column; gap: 16px; }
.proj {
    border: 1px solid var(--line); border-radius: var(--radius);
    background: var(--surface); overflow: hidden;
}
.proj-due { border-color: var(--accent-line); }
.proj-over { border-color: rgba(224, 108, 95, 0.5); }
.proj-head {
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    flex-wrap: wrap; padding: 11px 16px;
    background: var(--surface-2); border-bottom: 1px solid var(--line);
}
.proj-due .proj-head { background: rgba(4, 102, 200, 0.08); }
.proj-over .proj-head { background: rgba(224, 108, 95, 0.09); }
.proj-name { display: flex; align-items: center; gap: 9px; margin: 0; font-size: 14.5px; font-weight: 700; min-width: 0; }
.proj-name svg { color: var(--accent-2); flex: none; }
.proj-sum { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }

/* Document on the left, its payments on the right. */
.proj-row { display: grid; grid-template-columns: minmax(0, 300px) minmax(0, 1fr); gap: 0; }
.proj-row + .proj-row { border-top: 1px solid var(--line); }
.proj-doc { padding: 12px 16px; border-right: 1px solid var(--line); min-width: 0; }
.proj-doc-title {
    display: flex; align-items: flex-start; gap: 8px;
    color: var(--text); font-weight: 600; font-size: 13.5px; line-height: 1.35;
}
.proj-doc-title svg { color: var(--text-3); flex: none; margin-top: 1px; }
a.proj-doc-title:hover { color: var(--accent-2); }
a.proj-doc-title:hover svg { color: var(--accent-2); }
.proj-doc-meta { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 7px; }
.proj-doc-dl { display: inline-flex; align-items: center; gap: 4px; color: var(--text-3); font-size: 11.5px; }
.proj-doc-dl:hover { color: var(--accent-2); }
.proj-pays { display: flex; flex-direction: column; min-width: 0; }
.proj-nopay { padding: 12px 16px; color: var(--text-3); font-size: 12.5px; }
.btn-xs { padding: 4px 9px; font-size: 12px; border-radius: 7px; gap: 5px; }

/* The urgency scale that used to live here went with the payment-line
   partial. The dashboard now carries urgency on the pay button itself
   (.dh-jact.is-over / .is-act), and the .due-badge colours further down
   are still used by the autopay page. */

/* ---- files filed under a project ---------------------------------------- */
.proj-files { border-top: 1px solid var(--line); background: rgba(255, 255, 255, 0.012); }
.proj-files-head {
    display: flex; align-items: center; gap: 8px; padding: 9px 16px;
    font-size: 11px; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-3);
}
.proj-files-head svg { color: var(--accent-2); }
.proj-files-n {
    background: var(--surface-3); border: 1px solid var(--line-2); border-radius: 999px;
    padding: 0 6px; font-size: 10.5px; letter-spacing: 0; color: var(--text-2);
}
.proj-file { display: grid; grid-template-columns: 28px minmax(0, 1fr) auto; gap: 10px; align-items: center; padding: 8px 16px; color: var(--text-2); }
.proj-file + .proj-file { border-top: 1px solid var(--line); }
.proj-file:hover { background: rgba(255, 255, 255, 0.03); color: var(--text); }
.proj-file-ic { color: var(--text-3); display: flex; }
.proj-file:hover .proj-file-ic { color: var(--accent-2); }
.proj-file-main { min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.proj-file-name { font-size: 13px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.proj-file-sub { font-size: 11.5px; color: var(--text-3); }
.proj-file-dl { color: var(--text-3); display: flex; }
.proj-file:hover .proj-file-dl { color: var(--accent-2); }

@media (max-width: 760px) {
    /* Stacked, with the payments indented under their document. */
    .proj-row { grid-template-columns: 1fr; }
    .proj-doc { border-right: 0; border-bottom: 1px solid var(--line); padding-bottom: 10px; }}

/* ---- payments grouped by the document they belong to -------------------- */

.pay-group {
    border: 1px solid var(--line); border-radius: var(--radius);
    background: var(--surface); overflow: hidden;
}
.pay-group + .pay-group { margin-top: 14px; }
.pay-group-head {
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    flex-wrap: wrap; padding: 11px 16px;
    background: var(--surface-2); border-bottom: 1px solid var(--line);
}
.pay-group-title { font-weight: 700; font-size: 13.5px; min-width: 0; overflow-wrap: anywhere; }
.pay-group-title a { color: inherit; text-decoration: none; }
.pay-group-title a:hover { color: var(--accent-2); text-decoration: underline; }
.pay-group-sum {
    display: flex; align-items: center; gap: 8px;
    font-size: 12.5px; color: var(--text-3); white-space: nowrap;
}
.pay-group-sum strong { color: var(--text); font-variant-numeric: tabular-nums; }
.pay-group-due { border-color: var(--accent-line); }
.pay-group-due .pay-group-head { background: rgba(4, 102, 200, 0.08); }
.pay-group-over { border-color: rgba(224, 108, 95, 0.5); }
.pay-group-over .pay-group-head { background: rgba(224, 108, 95, 0.09); }

/* Inside a group the rows are dividers, not separate cards -- the group is the
   card. Without this every payment gets its own border inside a bordered box. */
.pay-group .pay-row {
    border: 0; border-radius: 0; background: transparent;
}
.pay-group .pay-row + .pay-row { border-top: 1px solid var(--line); }
.pay-group .pay-row:hover { background: rgba(255, 255, 255, 0.014); }
.pay-group .pay-row.pay-unpaid,
.pay-group .pay-row.pay-overdue { background: transparent; }

/* mobile: payment/purchase rows put the amount + action on their own line */
@media (max-width: 620px) {
    .dash-section .pay-row { display: grid; grid-template-columns: 42px minmax(0, 1fr) auto; column-gap: 12px; row-gap: 11px; align-items: center; }
    .dash-section .pay-glyph { grid-column: 1; grid-row: 1; align-self: start; }
    .dash-section .pay-main { grid-column: 2 / -1; grid-row: 1; }
    .dash-section .pay-amount { grid-column: 2; grid-row: 2; justify-self: start; }
    .dash-section .pay-action { grid-column: 3; grid-row: 2; justify-self: end; }
    .dash-section .pay-action form, .dash-section .pay-action .btn { white-space: nowrap; }
    .dash-hero-portal .dash-hero-cta { width: 100%; }
}

/* de-emphasised ("quiet") pay button; overdue ones use .btn-red */
.btn-quiet { color: var(--text-3); border-color: var(--line-2); background: transparent; font-weight: 500; }
.btn-quiet:hover { color: var(--text); border-color: var(--text-3); background: var(--surface-2); }

/* clearer due dates */
.due-badge { display: inline-flex; align-items: center; gap: 5px; font-weight: 600; padding: 2px 9px; border-radius: 999px; background: var(--surface-2); border: 1px solid var(--line-2); color: var(--text-2); font-size: 12px; }
.due-badge-soon { color: var(--accent-2); border-color: var(--accent-line); background: var(--accent-soft); }
.due-badge-over { color: var(--danger); border-color: rgba(224, 108, 95, 0.45); background: var(--danger-soft); }
/* Urgency scale, from due_phrase()'s `urgency`. Placed directly after the base
   .due-badge rule above so source order lets these win. */
.due-u-overdue { color: var(--danger); border-color: rgba(224, 108, 95, 0.45); background: var(--danger-soft); }.due-date { color: var(--text-3); font-size: 12px; margin-left: 8px; }

/* purchases */
.purchase-thumb { overflow: hidden; padding: 0; }
.purchase-thumb img { width: 100%; height: 100%; object-fit: cover; }
.pay-purchase .pay-glyph { color: var(--accent-2); }
.owned-note { display: inline-flex; align-items: center; gap: 8px; color: var(--success); font-weight: 600; font-size: 14px; margin-bottom: 12px; }
.dl-current { display: inline-flex; align-items: center; gap: 8px; color: var(--text-2); font-size: 13px; margin-bottom: 8px; }

@media (prefers-reduced-motion: reduce) {
    .page-transition { display: none; }
    /* Every part of the intro, off. The nav rules matter most: those elements
       START at opacity 0, so dropping the animation without also clearing the
       start state would hide the navigation permanently. */
    .intro-crt .topnav-brand::before { display: none; }
    .intro-crt .topnav-brand img,
    .intro-crt .topnav-side-l, .intro-crt .topnav-side-r, .intro-crt .topnav-links,
    .intro-crt main, .intro-crt .site-foot { animation: none; opacity: 1; transform: none; filter: none; }
}
@media (max-width: 560px) {
    .impersonate-bar { left: 12px; right: 12px; transform: none; max-width: none; }
}

/* ------------------------------------------------------------- store */

.shell-store { min-height: 100vh; display: flex; flex-direction: column; }
/* store layout: a left icon rail (work types) + the main content */
.store-shell { flex: 1; width: 100%; max-width: 1400px; margin: 0 auto; padding: 0 22px; display: flex; align-items: flex-start; gap: 10px; position: relative; z-index: 1; }
.store-rail { position: sticky; top: 86px; flex: none; width: 58px; display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 18px 0; }
.store-rail-item { position: relative; width: 46px; height: 46px; display: grid; place-items: center; border-radius: 13px; color: var(--text-2); border: 1px solid transparent; transition: color 0.16s, background 0.16s, border-color 0.16s; }
.store-rail-item:hover { color: var(--text); background: rgba(255, 255, 255, 0.05); }
.store-rail-item.active { color: var(--accent-2); background: var(--accent-soft); border-color: var(--accent-line); }
.store-rail-item::after {
    content: attr(data-tip); position: absolute; left: calc(100% + 12px); top: 50%; transform: translateY(-50%) translateX(-4px);
    white-space: nowrap; background: var(--surface); border: 1px solid var(--line-2); color: var(--text);
    font: 600 12.5px var(--font-ui); padding: 6px 11px; border-radius: 9px; box-shadow: var(--shadow);
    opacity: 0; visibility: hidden; transition: opacity 0.15s, transform 0.15s; pointer-events: none; z-index: 30;
}
.store-rail-item:hover::after { opacity: 1; visibility: visible; transform: translateY(-50%) translateX(0); }
.store-main { flex: 1 1 auto; min-width: 0; max-width: none; margin: 0; padding: 22px 4px 60px 22px; position: relative; z-index: 1; }
.store-usps { margin: 0 0 30px; }
.store-foot { text-align: center; color: var(--text-3); font-size: 12.5px; letter-spacing: 0.06em; padding: 26px 20px; border-top: 1px solid var(--line); }

@media (max-width: 720px) {
    .store-shell { flex-direction: column; padding: 0 16px; gap: 0; }
    .store-rail { position: static; flex-direction: row; width: 100%; overflow-x: auto; padding: 12px 0 6px; gap: 6px; }
    .store-rail-item::after { display: none; }
    .store-main { padding: 16px 0 44px; }
    .store-usps { grid-template-columns: repeat(3, 1fr); }
}

.store-hero { text-align: center; padding: 26px 0 34px; }
.store-hero .eyebrow { justify-content: center; display: inline-flex; align-items: center; gap: 7px; }
.store-hero-title { font-family: var(--font-display); font-size: clamp(28px, 5vw, 42px); font-weight: 800; letter-spacing: -0.02em; margin: 8px 0 10px; line-height: 1.1; }
.store-hero-sub { color: var(--text-2); font-size: 15.5px; max-width: 52ch; margin: 0 auto; }

.store-filters { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; margin-bottom: 30px; }
.store-filter {
    display: inline-flex; align-items: center; gap: 7px;
    background: var(--surface); border: 1px solid var(--line-2); border-radius: 999px;
    color: var(--text-2); font: 600 13px var(--font-ui); padding: 8px 15px;
    transition: border-color 0.15s, color 0.15s, background 0.15s;
}
.store-filter span { color: var(--text-3); font-variant-numeric: tabular-nums; }
.store-filter:hover { border-color: var(--text-3); color: var(--text); }
.store-filter.active { background: var(--accent-soft); border-color: var(--accent-line); color: var(--accent-2); }
.store-filter.active span { color: var(--accent-2); }

.product-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 20px; }
.product-card {
    display: flex; flex-direction: column;
    background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
    overflow: hidden; color: var(--text);
    transition: border-color 0.16s, transform 0.16s, box-shadow 0.16s;
}
.product-card:hover { border-color: var(--line-2); transform: translateY(-3px); box-shadow: var(--shadow); color: var(--text); }
.product-thumb {
    position: relative; display: block; aspect-ratio: 4 / 3; background: var(--surface-2);
    overflow: hidden; border-bottom: 1px solid var(--line);
}
.product-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 0.3s; }
.product-card:hover .product-thumb img { transform: scale(1.04); }
.product-thumb-empty { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; color: var(--text-3); }
.product-sale-flag {
    position: absolute; top: 11px; left: 11px;
    background: linear-gradient(180deg, #2b83dc, var(--accent)); color: #fff;
    font-size: 11px; font-weight: 700; letter-spacing: 0.03em; padding: 5px 10px; border-radius: 999px;
    box-shadow: 0 6px 16px -6px rgba(4, 102, 200, 0.55);
}
.product-body { display: flex; flex-direction: column; gap: 5px; padding: 15px 16px 17px; flex: 1; }
.product-cat { font-size: 10.5px; font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase; color: var(--accent-2); }
.product-name { font-family: var(--font-display); font-size: 16px; font-weight: 700; line-height: 1.25; }
.product-summary { color: var(--text-3); font-size: 13px; line-height: 1.45; flex: 1; }
.product-price { display: flex; align-items: baseline; gap: 9px; margin-top: 6px; }
.price-now { font-family: var(--font-display); font-weight: 800; font-size: 18px; color: var(--text); font-variant-numeric: tabular-nums; }
.price-was { color: var(--text-3); text-decoration: line-through; font-size: 13.5px; font-variant-numeric: tabular-nums; }

.store-crumb { display: flex; align-items: center; gap: 8px; color: var(--text-3); font-size: 13.5px; margin: 0 0 20px; flex-wrap: wrap; }
.store-crumb a { color: var(--text-2); display: inline-flex; align-items: center; gap: 6px; }
.store-crumb a:hover { color: var(--accent-2); }

.product-detail { display: grid; grid-template-columns: 1.1fr 1fr; gap: 34px; align-items: start; }
.product-detail-media {
    position: relative; aspect-ratio: 4 / 3; border-radius: var(--radius); overflow: hidden;
    background: var(--surface-2); border: 1px solid var(--line);
}
.product-detail-media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.product-detail-empty { position: static; display: flex; align-items: center; justify-content: center; height: 100%; color: var(--text-3); }
.product-detail-flag { top: 14px; left: 14px; font-size: 12.5px; padding: 6px 12px; }
.product-detail-info { min-width: 0; }
.product-detail-name { font-family: var(--font-display); font-size: 30px; font-weight: 800; letter-spacing: -0.015em; line-height: 1.15; margin: 8px 0 10px; }
.product-detail-summary { color: var(--text-2); font-size: 16px; line-height: 1.55; margin: 0 0 20px; }
.product-detail-price { display: flex; align-items: baseline; gap: 12px; margin-bottom: 22px; flex-wrap: wrap; }
.product-detail-price .price-now { font-size: 28px; }
.product-detail-price .price-was { font-size: 17px; }
.product-cta { border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); padding: 20px 0; margin-bottom: 22px; }
.product-cta-note { color: var(--text-3); font-size: 12.5px; margin: 10px 0 0; text-align: center; }
.product-detail-desc { color: var(--text-2); font-size: 14.5px; line-height: 1.7; }
.product-detail-desc p { margin: 0 0 0.9em; }

/* store admin bits */
.store-row { display: flex; align-items: center; gap: 12px; }
.store-row-thumb {
    width: 46px; height: 46px; border-radius: var(--radius-sm); flex: none; overflow: hidden;
    background: var(--surface-2); border: 1px solid var(--line-2);
    display: flex; align-items: center; justify-content: center; color: var(--text-3);
}
.store-row-thumb img { width: 100%; height: 100%; object-fit: cover; }
.thumb-current { border: 1px solid var(--line-2); border-radius: var(--radius-sm); overflow: hidden; margin-bottom: 10px; background: var(--surface-2); }
.thumb-current img { width: 100%; display: block; max-height: 200px; object-fit: contain; }
.cat-list { display: flex; flex-direction: column; gap: 8px; margin-bottom: 14px; }
.cat-row { display: flex; align-items: center; gap: 8px; }
.cat-rename { display: flex; align-items: center; gap: 8px; flex: 1; }
.cat-rename input { flex: 1; background: var(--bg-2); border: 1px solid var(--line-2); border-radius: var(--radius-sm); color: var(--text); font: 400 14px var(--font-ui); padding: 8px 11px; }
.cat-count { color: var(--text-3); font-size: 12px; font-variant-numeric: tabular-nums; min-width: 18px; text-align: center; }
.cat-add { border-top: 1px solid var(--line); padding-top: 14px; }

@media (max-width: 720px) {
    .product-detail { grid-template-columns: 1fr; gap: 22px; }
    .product-detail-name { font-size: 25px; }
}
@media (max-width: 640px) {
    .store-main { padding: 26px 16px 44px; }
    .store-hero { padding: 12px 0 22px; }
    .store-filters { gap: 6px; margin-bottom: 22px; }
    .store-filter { padding: 7px 12px; font-size: 12.5px; }
    .product-grid { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 14px; }
    .product-name { font-size: 15px; }
}

/* ------------------------------------------------- landing (product-led) */

/* A scope of its own, and near-black rather than the portal's blue-black.
   The public page reads as a software company; the room behind the login keeps
   the navy it has always had. Both are dark, so the handover is a shift in
   temperature rather than a change of building — and because every value here
   is scoped to .shell-landing, nothing outside it moves.

   THE WEIGHTS. Archivo is a variable font, and this page asks for 500–550
   where the old one asked for 900. That is the whole difference in register: a
   900-weight wall of type reads as a storefront, and confidence at this size
   comes from restraint and tracking rather than from mass. */
.shell-landing {
    --lp-bg:        #0B0B0D;
    --lp-surface:   #131316;
    --lp-raise:     rgba(255, 255, 255, 0.035);
    --lp-line:      rgba(255, 255, 255, 0.09);
    --lp-line-2:    rgba(255, 255, 255, 0.16);
    --lp-text:      #FAFAFA;
    --lp-2:         #A6A8AD;
    /* Chosen, not eyeballed: 5.05:1 on the page ground and 4.76:1 on the raised
       surface, so 11px mono labels still clear AA on both. #74777E, which is
       what this wanted to be by eye, measures 4.38 and 4.19. */
    --lp-3:         #7E818A;
    /* The site accent, not a copy of it. Appearance → accent colour rewrites
       --accent and friends on :root, and everything else in the portal follows
       it; these were hard-coded, so the landing was the one screen that did
       not. The hex is a fallback for the case where those are missing, never
       the value in normal use. */
    --lp-accent:    var(--accent, #006EFF);
    --lp-accent-2:  var(--accent-2, #3D8BFF);
    --lp-r:         8px;
    --lp-r-sm:      6px;

    min-height: 100vh; display: flex; flex-direction: column;
    background: var(--lp-bg); color: var(--lp-2);
}
.shell-landing main { flex: 1 0 auto; width: 100%; }
.lp-in { max-width: 1120px; margin: 0 auto; padding: 0 clamp(20px, 4vw, 32px); }

/* Page backdrop: a dot grid always, and behind the top of the page an
   admin-uploaded artwork under a fade.

   Anchored to the top of the PAGE, not the viewport. A map render behind the
   headline is atmosphere; the same render still sitting there behind a product
   shelf is noise. So the band scrolls away instead of following the viewport,
   and its fade finishes on the page ground rather than part way, which is what
   keeps the bottom edge from reading as a line across the page.

   The artwork and the two upper fade stops arrive inline from landing_backdrop()
   as --hero / --hero-top / --hero-mid. Nothing here assumes they exist: without
   .has-art this is only the grid, so a site with no upload is unaffected. */
/* Starts BELOW the bar, not behind it: the artwork reads as an image the page
   contains rather than one the nav is floating on, and the bar keeps its own
   ground while you scroll past it.

   Sized off the WIDTH rather than the viewport height. Against vh the band
   changed shape every time the window did — tall and close to square on a
   laptop, a thin letterbox on a short window — and `cover` cropped a different
   slice of the artwork each time. Against vw the crop is the same shape on
   every screen. The 62vw is the one number to nudge: larger is squarer and
   shows more of the image, smaller is more of a banner. */
.landing-glow {
    position: absolute; top: var(--nav-h, 62px); left: 0; right: 0;
    /* The cap has to sit high enough that it does not engage on an ordinary
       monitor — at 940px it kicked in by 1520px wide and handed a 1920 screen
       back the same letterbox this was meant to fix. It now only bites past
       ~1790px, so 1440 and 1920 both land near 1.5–1.6:1. */
    height: clamp(420px, 66vw, 1180px);
    z-index: -1; pointer-events: none;
    background-image: radial-gradient(rgba(255, 255, 255, 0.05) 1px, transparent 1.4px);
    background-size: 30px 30px;
    background-position: 0 0;
    background-repeat: repeat;
}
.landing-glow.has-art {
    background-image:
        radial-gradient(rgba(255, 255, 255, 0.05) 1px, transparent 1.4px),
        linear-gradient(180deg,
            rgba(11, 11, 13, var(--hero-top, 0.60)) 0%,
            rgba(11, 11, 13, var(--hero-mid, 0.80)) 46%,
            rgba(11, 11, 13, 0.95) 78%,
            var(--lp-bg) 100%),
        var(--hero),
        var(--hero-lqip, none);
    background-size: 30px 30px, 100% 100%, cover, cover;
    background-position: 0 0, 0 0, var(--hero-pos, center 32%), var(--hero-pos, center 32%);
    background-repeat: repeat, no-repeat, no-repeat, no-repeat;
}
/* Phones crop `cover` hard and read the page in daylight — both push the same
   way, so the band gets shorter and the fade starts lower. */
/* On a phone the page is narrow, so a width-based band would be short and wide
   — the opposite of what a portrait screen wants. Here it goes taller than the
   width, and the crop starts lower to keep the subject in frame. */
@media (max-width: 720px) {
    .landing-glow { height: clamp(380px, 88vw, 560px); }
    .landing-glow.has-art { background-position: 0 0, 0 0, center 38%, center 38%; }
}
@keyframes fade-in { from { opacity: 0; } }

/* Global, not landing — dashboard/view.php and the page builder use it. */
.btn-lg { padding: 15px 24px; font-size: 15px; border-radius: 13px; }

/* collage art fallback (store thumbs without an image) */
.art { display: block; width: 100%; height: 100%; background: #0e1420; }

/* ---------------------------------------------------------- landing type */

.shell-landing h1, .shell-landing h2, .shell-landing h3 {
    color: var(--lp-text); margin: 0; text-wrap: balance;
}
.lp-eyebrow {
    display: inline-block; font-family: var(--font-mono);
    font-size: 11.5px; font-weight: 500; letter-spacing: 0.16em; text-transform: uppercase;
    color: var(--lp-3); margin: 0 0 14px;
}
.lp-h1 {
    font-size: clamp(33px, 5.4vw, 60px); font-weight: 550; letter-spacing: -0.035em;
    line-height: 1.06;
}
.lp-h1 span { display: block; color: var(--lp-3); }
.lp-h2 {
    font-size: clamp(25px, 3.2vw, 38px); font-weight: 500; letter-spacing: -0.03em;
    line-height: 1.12;
}
.lp-h2 span { color: var(--lp-3); }
.lp-lead {
    color: var(--lp-2); font-size: clamp(15px, 1.5vw, 17.5px); line-height: 1.6;
    max-width: 58ch; margin: 18px 0 0;
}

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

.lp-btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 8px;
    font: 500 14px/1.3 var(--font-ui); padding: 11px 20px; border-radius: var(--lp-r-sm);
    border: 1px solid transparent; cursor: pointer; white-space: nowrap;
    transition: background 0.16s, border-color 0.16s, color 0.16s;
}
.lp-btn-p { background: var(--lp-accent); color: #fff; }
.lp-btn-p:hover { background: var(--lp-accent-2); color: #fff; }
.lp-btn-g { background: var(--lp-raise); color: var(--lp-text); border-color: var(--lp-line-2); }
.lp-btn-g:hover { background: rgba(255, 255, 255, 0.07); color: var(--lp-text); border-color: var(--lp-line-2); }
.lp-btn-g .ic { color: var(--lp-3); }
.lp-btn-sm { padding: 8px 14px; font-size: 13px; }
.lp-btn-steam { background: #1b2838; color: #fff; border-color: rgba(255, 255, 255, 0.14); }
.lp-btn-steam:hover { background: #22374d; color: #fff; }
.lp-cta { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 26px; }

/* ------------------------------------------------------------------ hero */

.lp-hero { position: relative; padding: clamp(46px, 8vw, 104px) 0 clamp(30px, 4vw, 52px); text-align: center; }
.lp-hero .lp-in { position: relative; z-index: 1; display: flex; flex-direction: column; align-items: center; }

/* ---- the character rain ----
   A canvas of drifting monospace glyphs behind the hero. app.js fills it; this
   only places and masks it, so with JavaScript off the element is an empty box
   that paints nothing.

   THE MASK IS THE WHOLE TRICK. Left alone, the rain runs straight through the
   headline and the page becomes hard to read for the sake of an effect. The
   radial mask keeps the middle — where the type is — completely clear and lets
   the texture live at the edges, which is where it reads as atmosphere rather
   than noise. */
.lp-rain {
    position: absolute; inset: 0; width: 100%; height: 100%;
    z-index: 0; pointer-events: none; display: block;
    /* Canvas ignores `color`, so this is purely a carrier: it is the one way
       the script can read the site accent as a RESOLVED rgb() — reading the
       custom property directly hands back the unsubstituted `var(--accent-2)`
       token instead of a colour. */
    color: var(--lp-accent-2);
    -webkit-mask-image: radial-gradient(ellipse 58% 62% at 50% 46%,
        transparent 0%, transparent 46%, #000 100%);
    mask-image: radial-gradient(ellipse 58% 62% at 50% 46%,
        transparent 0%, transparent 46%, #000 100%);
}
/* Without mask support the effect would sit on top of the headline, so it is
   dropped entirely rather than shown badly. */
@supports not ((mask-image: radial-gradient(#000, #000)) or (-webkit-mask-image: radial-gradient(#000, #000))) {
    .lp-rain { display: none; }
}

/* ---- the bracketed frame ----
   inline-block so it shrinks to the headline; the marks then sit just outside
   the longest line rather than out at the column edge. */
.lp-frame { position: relative; display: inline-block; padding: clamp(10px, 1.6vw, 18px) clamp(16px, 3vw, 38px); }
.lp-corners { position: absolute; inset: 0; pointer-events: none; }
.lp-corners i {
    position: absolute; width: 13px; height: 13px;
    border: 2px solid var(--lp-accent-2); opacity: 0.9;
}
.lp-corners i:nth-child(1) { top: 0; left: 0; border-right: 0; border-bottom: 0; }
.lp-corners i:nth-child(2) { top: 0; right: 0; border-left: 0; border-bottom: 0; }
.lp-corners i:nth-child(3) { bottom: 0; left: 0; border-right: 0; border-top: 0; }
.lp-corners i:nth-child(4) { bottom: 0; right: 0; border-left: 0; border-top: 0; }
@media (max-width: 620px) {
    .lp-corners i { width: 9px; height: 9px; border-width: 1.5px; }
}
.lp-hero .lp-lead { margin-left: auto; margin-right: auto; }
.lp-hero .lp-cta { justify-content: center; }

.lp-pill {
    display: inline-flex; align-items: center; gap: 8px;
    font-family: var(--font-mono); font-size: 11.5px; letter-spacing: 0.1em; text-transform: uppercase;
    color: var(--lp-2); background: var(--lp-raise); border: 1px solid var(--lp-line);
    padding: 6px 13px; border-radius: 999px; margin-bottom: 22px;
}
.lp-pill i { width: 6px; height: 6px; border-radius: 50%; background: var(--lp-accent-2); flex: none; }

/* The proof strip: mono, small, and only ever what is true. */
.lp-proof {
    display: flex; flex-wrap: wrap; justify-content: center; gap: 10px 26px;
    margin-top: 28px; font-family: var(--font-mono); font-size: 12px; color: var(--lp-3);
}
.lp-proof b { color: var(--lp-2); font-weight: 500; }
.lp-proof small { font-size: 12px; }
.lp-stars { color: var(--lp-2); letter-spacing: 0.08em; }

/* The one image on the page, framed like a product shot. */
.lp-shot { margin-top: clamp(34px, 5vw, 64px); padding: 0 clamp(20px, 4vw, 32px); }
.lp-shot-frame {
    max-width: 1000px; margin: 0 auto; border: 1px solid var(--lp-line);
    border-radius: 12px; overflow: hidden; background: var(--lp-surface);
    box-shadow: 0 40px 120px -60px rgba(0, 0, 0, 0.9), 0 0 0 1px rgba(255, 255, 255, 0.02);
}
.lp-shot-frame img { display: block; width: 100%; height: auto; opacity: var(--art-o, 1); }

/* ---- the portal, drawn ----
   Everything below is deliberately small and low-contrast: it should read as a
   screenshot of software from across the room, not as a second page competing
   with the headline above it. Nothing here is interactive or announced — the
   whole frame is aria-hidden. */
.lp-win { display: flex; flex-direction: column; text-align: left; }
.lp-win-bar {
    display: flex; align-items: center; gap: 6px;
    padding: 11px 14px; border-bottom: 1px solid var(--lp-line); background: rgba(255, 255, 255, 0.02);
}
.lp-win-bar i { width: 8px; height: 8px; border-radius: 50%; background: rgba(255, 255, 255, 0.14); flex: none; }
.lp-win-bar span {
    margin-left: 12px; font-family: var(--font-mono); font-size: 10.5px; color: var(--lp-3);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.lp-win-body { display: grid; grid-template-columns: 168px 1fr; min-height: clamp(220px, 26vw, 330px); }
.lp-win-side {
    display: flex; flex-direction: column; gap: 9px; padding: 16px 14px;
    border-right: 1px solid var(--lp-line); background: rgba(255, 255, 255, 0.015);
}
.lp-win-mark { width: 26px; height: 26px; border-radius: 5px; background: linear-gradient(150deg, var(--lp-accent-2), var(--lp-accent)); margin-bottom: 6px; }
.lp-win-side b { font-size: 11.5px; font-weight: 400; color: var(--lp-3); }
.lp-win-side b.is-on { color: var(--lp-text); }
.lp-win-main { display: flex; flex-direction: column; gap: 12px; padding: 16px; min-width: 0; }
.lp-win-title { width: 42%; height: 11px; border-radius: 3px; background: rgba(255, 255, 255, 0.11); }
.lp-win-cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.lp-win-cards span {
    display: flex; flex-direction: column; gap: 4px; padding: 11px 12px;
    background: var(--lp-raise); border: 1px solid var(--lp-line); border-radius: 6px;
}
.lp-win-cards em {
    font-style: normal; font-family: var(--font-mono); font-size: 8.5px;
    letter-spacing: 0.12em; text-transform: uppercase; color: var(--lp-3);
}
.lp-win-cards b { font-size: 17px; font-weight: 500; color: var(--lp-text); letter-spacing: -0.02em; }
.lp-win-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 7px; }
.lp-win-list li {
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    padding: 10px 12px; background: var(--lp-raise); border: 1px solid var(--lp-line); border-radius: 6px;
}
.lp-win-list em { font-style: normal; font-size: 11.5px; color: var(--lp-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lp-win-list i {
    font-style: normal; font-family: var(--font-mono); font-size: 8.5px; flex: none;
    letter-spacing: 0.1em; text-transform: uppercase; color: var(--lp-accent-2);
    border: 1px solid var(--accent-line); background: var(--accent-soft);
    padding: 3px 7px; border-radius: 3px;
}
.lp-win-list i.is-done { color: #5FC98D; border-color: rgba(95, 201, 141, 0.3); background: rgba(95, 201, 141, 0.1); }
/* Below this the sidebar is more noise than signal, and the cards need the
   room more than the nav does. */
@media (max-width: 620px) {
    .lp-win-body { grid-template-columns: 1fr; min-height: 0; }
    .lp-win-side { display: none; }
    .lp-win-cards b { font-size: 14px; }
}

/* ----------------------------------------------------------- section shell */

.lp-band { padding: clamp(48px, 7vw, 96px) 0; }
.lp-band-tight { padding-top: 0; }
.lp-head { margin-bottom: clamp(28px, 4vw, 48px); }
.lp-head-row { display: flex; align-items: flex-end; justify-content: space-between; gap: 20px; flex-wrap: wrap; }
.lp-more {
    display: inline-flex; align-items: center; gap: 6px; flex: none;
    font-size: 13.5px; font-weight: 500; color: var(--lp-2); white-space: nowrap;
}
.lp-more:hover { color: var(--lp-text); }
.lp-more .ic { color: var(--lp-3); }

.lp-inline-link {
    display: inline-flex; align-items: center; gap: 10px; margin-top: 30px;
    font-size: 13.5px; color: var(--lp-2);
    background: var(--lp-raise); border: 1px solid var(--lp-line);
    padding: 11px 16px; border-radius: var(--lp-r-sm);
}
.lp-inline-link:hover { color: var(--lp-text); border-color: var(--lp-line-2); }
.lp-inline-link b { color: var(--lp-text); font-weight: 500; }
.lp-inline-link .ic { color: var(--lp-3); }

/* --------------------------------------------------------- three columns */

.lp-three { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(18px, 3vw, 40px); }
.lp-three article { display: flex; flex-direction: column; gap: 10px; }
.lp-step-n { font-family: var(--font-mono); font-size: 12px; color: var(--lp-accent-2); letter-spacing: 0.1em; }
.lp-three h3 { font-size: 17px; font-weight: 500; letter-spacing: -0.015em; }
.lp-three p { color: var(--lp-2); font-size: 14.5px; line-height: 1.6; margin: 0; }
@media (max-width: 860px) { .lp-three { grid-template-columns: 1fr; gap: 26px; } }

/* ------------------------------------------------------ alternating rows */

.lp-rows { display: flex; flex-direction: column; gap: clamp(28px, 4vw, 56px); }
.lp-row { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(20px, 4vw, 56px); align-items: center; }
/* Every other row swaps sides. order, not direction, so the DOM stays in
   reading order for anything that is not painting it. */
.lp-row.is-flip .lp-row-copy { order: 2; }
.lp-row-copy h3 { font-size: clamp(19px, 2.2vw, 26px); font-weight: 500; letter-spacing: -0.025em; margin: 12px 0 0; }
.lp-row-copy p { color: var(--lp-2); font-size: 14.5px; line-height: 1.6; margin: 12px 0 0; }
.lp-tag {
    display: inline-block; font-family: var(--font-mono); font-size: 11px;
    letter-spacing: 0.14em; text-transform: uppercase; color: var(--lp-accent-2);
}

/* The stack as a panel of chips — the honest visual for a capability with no
   screenshot yet. The words ARE the content, so they are set as the machine
   names they are rather than dressed up. */
.lp-row-panel {
    background: var(--lp-surface); border: 1px solid var(--lp-line);
    border-radius: 10px; overflow: hidden;
}
.lp-row-panel-bar {
    display: flex; align-items: center; gap: 6px;
    padding: 11px 14px; border-bottom: 1px solid var(--lp-line);
}
.lp-row-panel-bar i { width: 8px; height: 8px; border-radius: 50%; background: rgba(255, 255, 255, 0.14); }
.lp-row-panel ul { list-style: none; margin: 0; padding: 18px; display: flex; flex-wrap: wrap; gap: 8px; }
.lp-row-panel li {
    font-family: var(--font-mono); font-size: 12.5px; color: var(--lp-2);
    background: var(--lp-raise); border: 1px solid var(--lp-line);
    padding: 6px 11px; border-radius: var(--lp-r-sm);
}
@media (max-width: 860px) {
    .lp-row { grid-template-columns: 1fr; gap: 20px; }
    .lp-row.is-flip .lp-row-copy { order: 0; }
}

/* ------------------------------------------------------------ logos strip */

.lp-logos { padding: clamp(10px, 2vw, 22px) 0 clamp(30px, 4vw, 48px); }
.lp-logos-label {
    text-align: center; font-family: var(--font-mono); font-size: 11.5px;
    letter-spacing: 0.14em; text-transform: uppercase; color: var(--lp-3); margin: 0 0 22px;
}
.lp-logos-row {
    list-style: none; margin: 0; padding: 0;
    display: flex; flex-wrap: wrap; justify-content: center; gap: 12px clamp(20px, 4vw, 46px);
}
/* 0.55, not the 0.45 this wants by eye: at 0.45 the composite lands on ~4.4:1
   against the ground, and these are engine names a buyer is meant to read. */
.lp-logos-row li { font-size: 15px; font-weight: 500; color: var(--lp-text); opacity: 0.55; }

/* ------------------------------------------------------------------ shop */

.lp-shop { display: grid; grid-template-columns: 1.25fr 1fr; gap: 16px; }
.lp-big {
    display: flex; flex-direction: column; overflow: hidden; color: inherit;
    background: var(--lp-surface); border: 1px solid var(--lp-line); border-radius: 10px;
    transition: border-color 0.16s;
}
.lp-big:hover { border-color: var(--lp-line-2); color: inherit; }
.lp-big-media {
    position: relative; aspect-ratio: 16 / 9; background-size: cover; background-position: center;
    background-color: #101014; display: flex; align-items: center; justify-content: center;
}
.lp-badge {
    position: absolute; top: 12px; left: 12px; font-family: var(--font-mono);
    font-size: 10.5px; letter-spacing: 0.1em; text-transform: uppercase;
    color: #fff; background: var(--lp-accent); padding: 5px 10px; border-radius: 4px;
}
.lp-nomedia { color: var(--lp-3); }
.lp-big-body { display: flex; flex-direction: column; gap: 8px; padding: 20px; }
.lp-big-body strong { color: var(--lp-text); font-size: 18px; font-weight: 500; letter-spacing: -0.02em; }
.lp-big-desc { color: var(--lp-2); font-size: 14px; line-height: 1.55; }
.lp-big-foot { display: flex; align-items: center; justify-content: space-between; gap: 14px; margin-top: 6px; }
.lp-price { color: var(--lp-text); font-family: var(--font-mono); font-size: 15px; }
.lp-price s { color: var(--lp-3); margin-left: 8px; font-size: 13px; }

.lp-mini { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.lp-card {
    display: flex; flex-direction: column; overflow: hidden; color: inherit;
    background: var(--lp-surface); border: 1px solid var(--lp-line); border-radius: 10px;
    transition: border-color 0.16s;
}
.lp-card:hover { border-color: var(--lp-line-2); color: inherit; }
.lp-card-media {
    aspect-ratio: 4 / 3; background-size: cover; background-position: center;
    background-color: #101014; display: flex; align-items: center; justify-content: center;
}
.lp-card-body { display: flex; flex-direction: column; gap: 5px; padding: 13px 14px 15px; }
.lp-card-body strong { color: var(--lp-text); font-size: 14px; font-weight: 500; letter-spacing: -0.015em; }
.lp-card-body .lp-price { font-size: 13px; }
@media (max-width: 860px) {
    .lp-shop { grid-template-columns: 1fr; }
    .lp-mini { grid-template-columns: 1fr 1fr; }
}

/* ------------------------------------------------------------ categories */

.lp-cats { display: flex; flex-wrap: wrap; gap: 10px; }
.lp-cat {
    display: inline-flex; align-items: center; gap: 10px; color: var(--lp-2);
    background: var(--lp-raise); border: 1px solid var(--lp-line);
    padding: 9px 15px; border-radius: 999px; font-size: 13.5px;
}
.lp-cat:hover { color: var(--lp-text); border-color: var(--lp-line-2); }
.lp-cat-n { font-family: var(--font-mono); font-size: 11.5px; color: var(--lp-3); }

/* ------------------------------------------------------------------ demo */

.lp-demo {
    display: flex; align-items: center; justify-content: space-between; gap: 22px; flex-wrap: wrap;
    background: var(--lp-surface); border: 1px solid var(--lp-line);
    border-radius: 10px; padding: clamp(20px, 3vw, 30px);
}
.lp-demo h3 { font-size: clamp(17px, 2vw, 22px); font-weight: 500; letter-spacing: -0.02em; }
.lp-demo-join { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.lp-demo-join code {
    font-family: var(--font-mono); font-size: 13.5px; color: var(--lp-text);
    background: var(--lp-raise); border: 1px solid var(--lp-line);
    padding: 9px 13px; border-radius: var(--lp-r-sm);
}

/* ------------------------------------------------------------------- FAQ */

.lp-faq-grid { display: grid; grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr); gap: clamp(24px, 5vw, 64px); align-items: start; }
.lp-faq-grid .lp-head { margin-bottom: 0; }
.lp-faq { display: flex; flex-direction: column; }
.lp-faq details { border-bottom: 1px solid var(--lp-line); }
.lp-faq details:first-child { border-top: 1px solid var(--lp-line); }
.lp-faq summary {
    display: flex; align-items: center; justify-content: space-between; gap: 16px;
    padding: 18px 2px; cursor: pointer; list-style: none;
    color: var(--lp-text); font-size: 15px; font-weight: 500;
}
.lp-faq summary::-webkit-details-marker { display: none; }
.lp-faq summary:hover { color: var(--lp-accent-2); }
.lp-faq summary .ic { color: var(--lp-3); flex: none; transition: transform 0.18s; }
.lp-faq details[open] summary .ic { transform: rotate(180deg); }
.lp-faq p { margin: 0 0 20px; padding-right: 40px; color: var(--lp-2); font-size: 14.5px; line-height: 1.65; }
@media (prefers-reduced-motion: reduce) { .lp-faq summary .ic { transition: none; } }
@media (max-width: 860px) { .lp-faq-grid { grid-template-columns: 1fr; } }

/* ---------------------------------------------------------- closing band */

.lp-close { padding: clamp(56px, 8vw, 110px) 0 clamp(60px, 8vw, 120px); text-align: center; border-top: 1px solid var(--lp-line); }
.lp-close .lp-h2 span { display: block; }
.lp-close .lp-lead { margin-left: auto; margin-right: auto; }
.lp-close .lp-cta { justify-content: center; }

/* The footer and the sticky bar take the landing's ground, not the portal's,
   or a seam appears where one near-black meets the other. */
.shell-landing .site-foot { background: var(--lp-bg); border-top-color: var(--lp-line); }
.shell-landing .site-foot-brand,
.shell-landing .site-foot-links a,
.shell-landing .site-foot-identity,
.shell-landing .site-foot-note { color: var(--lp-3); }
.shell-landing .site-foot-links a:hover { color: var(--lp-text); }
.shell-landing .topnav { background: rgba(11, 11, 13, 0.72); border-bottom-color: var(--lp-line); }
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .shell-landing .topnav { background: rgba(11, 11, 13, 0.97); }
}
/* The nav is shared with the store and the dashboard, so it takes the portal's
   blue-grey text everywhere. On this page's neutral ground that reads faintly
   blue against the type beside it, so the landing lends it its own greys. */
/* The nav dropdowns are shared with the store and the dashboard, so they take
   the portal's navy surface and its 14px corner. Opened over this page's
   neutral greys that read as a panel borrowed from somewhere else, so here
   they take the landing's own ground, lines and radius. */
.shell-landing .nav-drop-menu {
    background: var(--lp-surface); border-color: var(--lp-line-2);
    border-radius: var(--lp-r); box-shadow: 0 24px 50px -28px rgba(0, 0, 0, 0.9);
}
.shell-landing .nav-drop-item { color: var(--lp-2); border-radius: var(--lp-r-sm); font-weight: 500; }
.shell-landing .nav-drop-item .ic { color: var(--lp-3); }
.shell-landing .nav-drop-item:hover { background: var(--lp-raise); color: var(--lp-text); }
.shell-landing .nav-drop-item:hover .ic,
.shell-landing .nav-drop-item.active .ic { color: var(--lp-accent-2); }
.shell-landing .nav-drop-item.active { color: var(--lp-text); background: var(--lp-raise); }

.shell-landing .nav-slot { color: var(--lp-2); }
.shell-landing .nav-slot:hover, .shell-landing .nav-slot.active { color: var(--lp-text); }
.shell-landing .nav-slot .ic { color: var(--lp-3); }
.shell-landing .nav-login { color: var(--lp-text); border-color: var(--lp-line-2); background: var(--lp-raise); }
.shell-landing .nav-login .ic { color: var(--lp-3); }

/* --------------------------------- store trust bar (layout-shells.php) ---
   Not the landing's, but it has always lived in this block and the store shell
   still renders it. */
.lp-trustbar { margin-top: 0; background: linear-gradient(180deg, var(--surface), rgba(14, 20, 32, 0.5)); border: 1px solid var(--line); border-radius: var(--radius-lg); padding: 16px clamp(20px, 4vw, 54px); display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
.lp-trust { display: flex; align-items: center; justify-content: center; gap: 14px; }
.lp-trust .ic { color: var(--accent-2); flex: none; }
.lp-trust b { font-family: var(--font-display); font-weight: 800; font-size: 18px; letter-spacing: -0.01em; }
/* the 6-up "what I cover" bar */
.lp-usps { grid-template-columns: repeat(6, 1fr); gap: 12px; padding: 15px clamp(16px, 2.5vw, 34px); }
.lp-usps .lp-trust { gap: 10px; }
.lp-usps .lp-trust .ic { width: 22px; height: 22px; }
.lp-usps .lp-trust b { font-size: 15px; white-space: nowrap; }
@media (max-width: 960px) { .lp-usps { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 620px) {
    .lp-usps { gap: 10px; padding: 12px; }
    .lp-usps .lp-trust { flex-direction: column; gap: 5px; text-align: center; }
    .lp-usps .lp-trust b { font-size: 12px; white-space: normal; }
}
/* shared site footer (landing / store / portal) — opaque so the fixed
   backdrop (image + dots) never shows through it. */
.site-foot { position: relative; z-index: 2; border-top: 1px solid var(--line); margin-top: 40px; background: var(--bg); }
.site-foot-inner { max-width: 1400px; margin: 0 auto; padding: 26px 28px 40px; display: flex; align-items: center; justify-content: space-between; gap: 12px 20px; flex-wrap: wrap; }
.site-foot-brand { color: var(--text-3); font-size: 12.5px; }
.site-foot-links { display: flex; flex-wrap: wrap; gap: 10px 18px; }
.site-foot-links a { color: var(--text-3); font-size: 13px; }
.site-foot-links a:hover { color: var(--text); }
.site-foot-identity { max-width: 1400px; margin: 0 auto; padding: 0 28px 10px; display: flex; flex-wrap: wrap; gap: 4px 16px; color: var(--text-3); font-size: 12px; }
.site-foot-identity a { color: var(--text-3); text-decoration: underline; text-underline-offset: 2px; }
.site-foot-identity a:hover { color: var(--text-2); }
.site-foot-note { max-width: 1400px; margin: 0 auto; padding: 0 28px 30px; color: var(--text-3); font-size: 11.5px; line-height: 1.5; opacity: 0.85; }
/* landing footer is a compact flex row pinned to the single screen */
.shell-landing .site-foot { margin-top: 0; flex: none; }
.shell-landing .site-foot-inner { padding: 14px 28px; }

/* ---------------------------------------------------------- legal pages */

.shell-legal { min-height: 100vh; display: flex; flex-direction: column; overflow-x: hidden; }
.legal { position: relative; z-index: 2; flex: 1; width: 100%; max-width: 1400px; margin: 0 auto; padding: 26px 28px 40px;
    display: grid; grid-template-columns: 240px minmax(0, 1fr); gap: 48px; align-items: start; }
.legal-single { display: block; max-width: 820px; }
.legal-nav { position: sticky; top: 20px; }
.legal-nav-title { font-size: 11px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--text-3); font-weight: 700; margin-bottom: 12px; }
.legal-nav nav { display: flex; flex-direction: column; gap: 2px; }
.legal-nav a { color: var(--text-2); font-size: 13.5px; padding: 7px 11px; border-radius: 7px; border-left: 2px solid transparent; }
.legal-nav a:hover { color: var(--text); background: var(--surface); }
.legal-nav a.active { color: var(--accent-2); background: var(--accent-soft); border-left-color: var(--accent-2); }
.legal-doc { min-width: 0; max-width: 70ch; }
.legal-eyebrow { font-size: 11.5px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--accent-2); font-weight: 700; }
.legal-doc h1 { font-family: var(--font-display); font-size: clamp(28px, 4vw, 40px); font-weight: 800; letter-spacing: -0.02em; margin: 8px 0 6px; }
.legal-updated { color: var(--text-3); font-size: 13px; margin: 0 0 26px; padding-bottom: 22px; border-bottom: 1px solid var(--line); }
.legal-doc h2 { font-family: var(--font-display); font-size: 19px; font-weight: 700; letter-spacing: -0.01em; margin: 32px 0 10px; }
.legal-doc p, .legal-doc li { color: var(--text-2); font-size: 15px; line-height: 1.7; }
.legal-doc p { margin: 0 0 14px; }
.legal-doc ul { margin: 0 0 16px; padding-left: 20px; display: flex; flex-direction: column; gap: 7px; }
.legal-doc strong { color: var(--text); }
.legal-doc em { color: var(--text-2); font-style: italic; }
.legal-doc a { color: var(--accent-2); text-decoration: underline; text-underline-offset: 2px; }
.legal-doc a:hover { color: var(--accent-3); }
.legal-doc code { font-family: var(--font-mono); font-size: 13px; background: var(--surface-2); border: 1px solid var(--line); border-radius: 5px; padding: 1px 6px; color: var(--accent-3); }

.legal-hub { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 14px; margin-top: 10px; }
.legal-hub-card { display: flex; flex-direction: column; gap: 6px; background: var(--surface); border: 1px solid var(--line); border-radius: 12px; padding: 18px; transition: border-color 0.15s, transform 0.15s; }
.legal-hub-card:hover { border-color: var(--accent-line); transform: translateY(-2px); }
.legal-hub-title { font-family: var(--font-display); font-weight: 700; font-size: 16px; color: var(--text); }
.legal-hub-sum { color: var(--text-3); font-size: 13px; line-height: 1.5; }

@media (max-width: 720px) {
    .legal { grid-template-columns: 1fr; gap: 22px; }
    .legal-nav { position: static; }
    .legal-nav nav { flex-direction: row; flex-wrap: wrap; gap: 6px; }
    .legal-nav a { border-left: none; border: 1px solid var(--line); }
    .legal-nav a.active { border-color: var(--accent-line); }
}

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

.sidenav-backdrop {
    position: fixed; inset: 0; z-index: 90;
    background: rgba(5, 6, 8, 0.7); -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
    opacity: 0; pointer-events: none; transition: opacity 0.25s;
}
.sidenav {
    position: fixed; top: 0; right: 0; bottom: 0; z-index: 95;
    width: min(400px, 100vw);
    background: var(--surface); border-left: 1px solid var(--line-2);
    box-shadow: -30px 0 80px -30px rgba(0, 0, 0, 0.8);
    padding: 26px 30px; overflow-y: auto;
    transform: translateX(102%); transition: transform 0.28s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.sidenav-is-open .sidenav { transform: translateX(0); }
.sidenav-is-open .sidenav-backdrop { opacity: 1; pointer-events: auto; }
.sidenav-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 30px; }
.sidenav-title { font-family: var(--font-display); font-size: 22px; font-weight: 800; letter-spacing: -0.01em; margin: 0 0 6px; color: var(--text); }
.sidenav-sub { color: var(--text-2); font-size: 13.5px; margin: 0 0 20px; }

/* ------------------------------------------------------ document editor */

.editor-cols { display: grid; grid-template-columns: 1.9fr 1fr; gap: 20px; align-items: start; }
.editor-main { min-width: 0; }
.editor-side { display: flex; flex-direction: column; gap: 16px; position: sticky; top: calc(var(--topbar-h, 0px) + 20px); }

/* ---- create-a-document: template picker ----------------------------------
   Full width and above the editor because it is the first decision, and the
   editor below it is an empty box until it is made. Collapses to a one-line
   summary once chosen so it stops occupying the screen. */
.tpl-pick { margin-bottom: 20px; }
.tpl-pick .card-head h2 { display: flex; align-items: center; gap: 9px; }
.step-dot {
    display: inline-flex; align-items: center; justify-content: center;
    width: 22px; height: 22px; flex: 0 0 22px; border-radius: 50%;
    background: var(--accent); color: #fff; font-size: 12px; font-weight: 700;
}
.tpl-grid {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
    gap: 10px; margin-bottom: 4px;
}
.tpl-card .ls-theme-card { gap: 6px; }
.tpl-card .ls-theme-card b { display: flex; align-items: center; gap: 7px; }
.tpl-card .ls-theme-card b svg { flex: 0 0 auto; color: var(--text-3); }
.tpl-card input:checked + .ls-theme-card b svg { color: var(--accent); }
.tpl-card .ls-theme-card small {
    display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical;
    overflow: hidden;
}
.tpl-chosen {
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    flex-wrap: wrap; padding: 12px 14px; border-radius: var(--radius);
    border: 1px solid var(--accent); background: var(--accent-soft);
}
.tpl-chosen-label { display: flex; align-items: center; gap: 9px; font-size: 14px; }
.tpl-chosen-label svg { color: var(--accent); flex: 0 0 auto; }

/* The agreement picker: two rows of buttons that write the whole document.
   A grid rather than cards -- there is no template to describe any more, only
   two choices to make, and a description under each would be noise. */
.wk-row {
    grid-column: 1 / -1;
    display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
    padding: 11px 14px; border: 1px solid var(--line-2);
    border-radius: var(--radius); background: var(--surface-2);
}
.wk-label {
    display: flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 600;
    color: var(--text-2); white-space: nowrap; min-width: 190px;
}
.wk-label svg { color: var(--accent); flex: 0 0 auto; }
.wk-opts { display: flex; gap: 6px; flex-wrap: wrap; }
/* The kind code (SRV, MAP) rides along inside its button, quieter than the
   label so the eye reads the word first and the code only when wanted. */
.wk-opts .btn small {
    margin-left: 6px; opacity: .55; font-size: 11px;
    font-variant-numeric: tabular-nums; letter-spacing: .04em;
}
.wk-row-out { border-color: var(--accent); background: var(--accent-soft); }
.wk-title {
    font-weight: 600; font-size: 14px; color: var(--text-1);
    font-variant-numeric: tabular-nums;
}

/* One Discord channel, on the settings screen. Boxed rather than a bare pair
   of inputs: there are five of them and they are otherwise ten identical
   fields, which is how you end up pasting the payments webhook into tips. The
   chip says which route the values actually resolve to, so the effect of what
   is typed is visible without saving and going to look. */
.dch-row {
    padding: 13px 15px; margin-bottom: 10px;
    border: 1px solid var(--line); border-radius: var(--radius-sm);
    background: var(--surface-2);
}
.dch-head { display: flex; align-items: center; gap: 9px; margin-bottom: 2px; }
.dch-head strong { font-size: 14px; }
.dch-row .field-note { margin-bottom: 9px; }
.dch-row .field-split { margin-top: 8px; }

/* What is waiting, per channel. The point of the list is the line that says a
   channel has nowhere to post: without it, pressing Push and watching one
   channel stay empty gives no way to tell "nothing to send" from "I never
   pasted that one in". */
.bf-list { list-style: none; margin: 10px 0 12px; padding: 0; display: grid; gap: 5px; }
.bf-list > li {
    display: flex; align-items: baseline; justify-content: space-between;
    gap: 12px; font-size: 12.5px;
}
.bf-name { color: var(--text-2); }
.bf-n { color: var(--accent-2); font-weight: 600; font-variant-numeric: tabular-nums; }
.bf-note { color: var(--text-3); }
.bf-off { display: inline-flex; align-items: center; gap: 5px; color: var(--warn); }
.bf-off svg { flex: 0 0 auto; }

/* Price and optional extras. Both write into the document as they are typed,
   so these sit in the meta column rather than in the picker -- they are
   properties of this agreement, not a choice about which agreement it is. */
.agr-money { display: grid; gap: 12px; }
.agr-money[hidden] { display: none; }
.agr-extras-head { display: block; margin-bottom: 6px; font-size: 13px; font-weight: 600; }
.agr-extras-head small { font-weight: 400; color: var(--text-3); }
.agr-extra {
    display: grid; grid-template-columns: 1fr 110px auto; gap: 6px;
    align-items: center; margin-bottom: 6px;
}
.agr-extra input { width: 100%; }
/* The remove button is a quiet x until hovered -- it sits beside every row and
   should not read as an action worth taking. */
.agr-extra-del { padding: 0 9px; line-height: 1.9; color: var(--text-3); }
.agr-extra-del:hover { color: var(--danger, #e06c5f); }

/* The Client's name slot, as seen WHILE COMPOSING. The span is empty until a
   signature fills it, so without this the editor shows "(2)  known as ..." with
   a hole in the middle of the sentence and no hint of why. Drawn as the rule it
   stands for, and not editable -- see loadStructure() in editor.js. */
.doc-page .party-name::after {
    content: "____________________";
    padding: 0 6px; color: var(--text-3); letter-spacing: .5px;
}
.doc-page .party-name {
    border-radius: 3px; background: var(--accent-soft);
    box-shadow: inset 0 -1px 0 var(--accent);
}

/* Work type — rewrites the type-specific wording in the document live. */
.tpl-worktype {
    display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
    margin-top: 14px; padding: 12px 14px;
    border: 1px solid var(--line-2); border-radius: var(--radius); background: var(--surface-2);
}
.tpl-worktype[hidden] { display: none; }
.tpl-worktype-label {
    display: flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 600;
    color: var(--text-2); white-space: nowrap;
}
.tpl-worktype-label svg { color: var(--accent); flex: 0 0 auto; }
.tpl-worktype-opts { display: flex; gap: 6px; flex-wrap: wrap; }

/* Two switches side by side rather than stacked -- they are short and related,
   and stacking them pushed "who can open it" below the fold. */
.field-split { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 10px; }

@media (max-width: 900px) {
    .tpl-grid { grid-template-columns: 1fr; }
    .wk-row { align-items: flex-start; flex-direction: column; gap: 8px; }
    .wk-label { min-width: 0; }
    .agr-extra { grid-template-columns: 1fr 90px auto; }
}
.editor-toolbar {
    position: sticky; top: var(--topbar-h, 0px); z-index: 30;
    display: flex; align-items: center; gap: 4px; flex-wrap: wrap;
    background: var(--surface-2); border: 1px solid var(--line-2);
    border-radius: var(--radius-sm) var(--radius-sm) 0 0; padding: 8px 10px;
}
.tb-btn {
    background: none; border: 1px solid transparent; border-radius: 6px;
    color: var(--text-2); font: 600 13px var(--font-ui); padding: 7px 10px; cursor: pointer;
    display: inline-flex; align-items: center; gap: 6px;
}
.tb-btn:hover { background: var(--surface-3); color: var(--text); }
.tb-btn strong, .tb-btn em, .tb-btn u, .tb-btn s { font-size: 13.5px; }
.tb-slot { color: var(--accent-2); border-color: var(--accent-line); background: var(--accent-soft); }
.tb-slot:hover { background: rgba(4, 102, 200, 0.28); color: var(--accent-3); }
.tb-sep { width: 1px; height: 20px; background: var(--line-2); margin: 0 6px; flex: none; }
.tb-select {
    background: var(--bg-2); border: 1px solid var(--line-2); border-radius: 6px;
    color: var(--text); font: 600 13px var(--font-ui); padding: 6px 8px;
}
.editor-page {
    min-height: 560px; border-radius: 0 0 4px 4px; outline: none;
    box-shadow: 0 0 0 1px var(--line-2), 0 30px 70px -30px rgba(0, 0, 0, 0.9);
}
.editor-page:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--accent); }
.toolbar-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }

/* -------------------------------------------- signature slots & blocks */

.sig-slot {
    border: 1.5px dashed #9db7d8; background: rgba(4, 102, 200, 0.05);
    border-radius: 8px; padding: 26px 18px; margin: 14px 0; text-align: center;
    color: #5379a3; font: 600 13px var(--font-ui); cursor: default;
}
.sig-slot::before { content: '✍  User Signature — the user signs here'; letter-spacing: 0.04em; }
.sig-slot[data-slot="wom"]::before { content: '✍  WOM Signature — stamped from Settings'; }

/* Fill-in fields: editable blanks (dates, names) the admin completes.
   The dotted outline only shows in the editor; the finished document is clean. */
.editor-page .fill {
    outline: 1px dashed var(--accent-2); outline-offset: 1px;
    border-radius: 3px; padding: 0 3px; background: rgba(4, 102, 200, 0.07);
    color: #14304f; cursor: text;
}
.editor-page .fill:hover { background: rgba(4, 102, 200, 0.13); }
.editor-page .fill:empty::before { content: '\00a0\00a0\00a0\00a0'; }

.sig-inline {
    display: inline-block; background: #fdfcf9; border: 1px solid var(--paper-line);
    border-radius: 8px; padding: 12px 26px 10px; margin: 10px 0; text-align: center;
}
.sig-inline img { max-height: 78px; display: block; margin: 0 auto; }
.sig-inline-meta { border-top: 1px solid var(--paper-line); margin-top: 8px; padding-top: 7px; line-height: 1.35; }
.sig-inline-meta strong { display: block; font-size: 13.5px; color: #1d1e22; }
.sig-inline-meta span { font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; color: #8b8d94; }
.sig-inline-empty {
    border-style: dashed; border-color: #c5bfae; color: #9a9b9f;
    font: 600 12.5px var(--font-ui); padding: 24px 26px;
}

/* ------------------------------------------------------- letterhead */

.letterhead {
    display: flex; align-items: center; justify-content: space-between; gap: 18px;
    border-bottom: 2px solid var(--accent); padding-bottom: 18px; margin-bottom: 34px;
}
.letterhead img { height: 34px; width: auto; }
.letterhead-meta { text-align: right; line-height: 1.3; }
.letterhead-meta strong { display: block; font-family: var(--font-display); font-weight: 800; font-size: 14px; color: #1d1e22; }
.letterhead-meta span { font-size: 10.5px; letter-spacing: 0.18em; text-transform: uppercase; color: #8b8d94; }

.sig-current { margin-bottom: 12px; min-width: 0; max-width: none; }

@media (max-width: 960px) {
    .editor-cols { grid-template-columns: 1fr; }
    .editor-side { position: static; }
}

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

/* --------------------------------------------------- automatic payments */

.autopay-cta {
    display: flex; align-items: center; gap: 12px; margin-bottom: 12px; padding: 13px 15px;
    background: var(--accent-soft); border: 1px solid var(--accent-line); border-radius: 11px;
    color: var(--text); transition: border-color 0.15s, transform 0.15s;
}
.autopay-cta:hover { border-color: var(--accent-2); transform: translateY(-1px); }
.autopay-cta > .ic { margin-left: auto; color: var(--text-3); flex: none; }
.autopay-cta-ic { display: flex; align-items: center; justify-content: center; width: 34px; height: 34px; flex: none; border-radius: 9px; background: rgba(4, 102, 200, 0.22); color: var(--accent-2); }
.autopay-cta-text { display: flex; flex-direction: column; min-width: 0; }
.autopay-cta-text strong { font-size: 13.5px; font-weight: 700; }
.autopay-cta-text small { color: var(--text-2); font-size: 11.5px; }

.autopay-note {
    display: flex; align-items: center; gap: 8px; margin-bottom: 12px; padding: 8px 12px;
    border-radius: 9px; font-size: 12.5px; color: var(--success);
    background: var(--success-soft); border: 1px solid rgba(127, 181, 138, 0.35);
}
.autopay-note > span:first-of-type { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.autopay-note-manage { margin-left: auto; flex: none; color: var(--text-2); text-decoration: underline; }

.autopay-points { list-style: none; margin: 4px 0 18px; padding: 0; display: flex; flex-direction: column; gap: 7px; }
.autopay-points li { display: flex; align-items: center; gap: 9px; color: var(--text-2); font-size: 13.5px; }
.autopay-points .ic { color: var(--success); flex: none; }

.check-row { display: flex; flex-wrap: wrap; gap: 10px 18px; padding-top: 4px; }
.check-inline { display: inline-flex; align-items: center; gap: 8px; color: var(--text-2); font-size: 13.5px; }
.check-inline input { width: 16px; height: 16px; accent-color: var(--accent); flex: none; }
.check-inline small { color: var(--text-3); }
.autopay-cron { margin-top: 20px; padding-top: 18px; border-top: 1px solid var(--line); }
.field-sub { display: flex; align-items: center; gap: 8px; font-family: var(--font-display); font-size: 14px; font-weight: 700; margin: 0 0 8px; }
.code-block { display: block; width: 100%; overflow-x: auto; white-space: nowrap; background: var(--bg-2); border: 1px solid var(--line-2); border-radius: 7px; padding: 8px 10px; font-family: var(--font-mono); font-size: 12px; color: var(--accent-3); margin-top: 4px; }
.btn.btn-on { color: var(--accent-2); border-color: var(--accent-line); background: var(--accent-soft); }


/* ==================================================== admin panel (v2) */
/* Shell (sidebar/topbar/nav/collapse/account/drawer) is in the "admin shell v3"
   block near the end of this file. What remains here are the KPI cards, charts,
   ranked lists and other content widgets shared by the admin pages. */

.online-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--success); flex: none; animation: pulse-dot 2s infinite; }
@keyframes pulse-dot { 0% { box-shadow: 0 0 0 0 rgba(127, 181, 138, 0.55); } 70% { box-shadow: 0 0 0 7px rgba(127, 181, 138, 0); } 100% { box-shadow: 0 0 0 0 rgba(127, 181, 138, 0); } }

.kpi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(188px, 1fr)); gap: 14px; margin-bottom: 22px; }
.kpi { display: flex; align-items: center; gap: 14px; background: var(--surface); border: 1px solid var(--line); border-radius: 13px; padding: 15px 17px; transition: border-color 0.15s, transform 0.15s; color: var(--text); }
a.kpi:hover { border-color: var(--line-2); transform: translateY(-2px); }
.kpi-ic { display: flex; align-items: center; justify-content: center; width: 42px; height: 42px; border-radius: 11px; flex: none; background: var(--surface-2); border: 1px solid var(--line-2); color: var(--accent-2); }
.kpi-ic-good { color: var(--success); }
.kpi-ic-live { background: var(--success-soft); border-color: rgba(127, 181, 138, 0.4); }
.kpi-body { min-width: 0; }
.kpi-num { font-family: var(--font-display); font-size: 25px; font-weight: 800; line-height: 1.02; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.kpi-label { color: var(--text-3); font-size: 12px; margin-top: 3px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kpi-attn { border-color: rgba(224, 108, 95, 0.4); background: linear-gradient(180deg, rgba(224, 108, 95, 0.06), var(--surface)); }
.kpi-attn .kpi-ic { color: var(--danger); border-color: rgba(224, 108, 95, 0.4); }
.kpi-cta { border-style: dashed; }
.kpi-cta .kpi-label, .kpi-live .kpi-label { color: var(--text-2); }

.dash-main, .dash-side { display: flex; flex-direction: column; gap: 20px; min-width: 0; }
.card-meta { color: var(--text-3); font-size: 12.5px; }
.card-link { color: var(--text-2); font-size: 13px; font-weight: 600; display: inline-flex; align-items: center; gap: 3px; }
.card-link:hover { color: var(--accent-2); }

.mini-chart { display: flex; align-items: flex-end; gap: 5px; height: 92px; padding-top: 6px; }
.mini-chart-lg { height: 150px; gap: 7px; }
.mini-bar-wrap { flex: 1; height: 100%; display: flex; align-items: flex-end; }
.mini-bar { display: block; width: 100%; background: linear-gradient(180deg, var(--accent-2), var(--accent)); border-radius: 4px 4px 2px 2px; min-height: 3px; transition: opacity 0.15s; }
.mini-bar-wrap:hover .mini-bar { opacity: 0.72; }

.rank-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.rank-list li { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 9px 0; border-bottom: 1px solid var(--line); font-size: 13.5px; }
.rank-list li:last-child { border-bottom: none; }
.rank-name { color: var(--text); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rank-val { color: var(--text-3); flex: none; font-variant-numeric: tabular-nums; font-size: 12.5px; }

.tabs-lg { gap: 2px; margin-bottom: 22px; border-bottom: 1px solid var(--line); flex-wrap: wrap; }
.tabs-lg .tab { display: inline-flex; align-items: center; gap: 8px; padding: 11px 16px; font-size: 14px; }
.rule { border: none; border-top: 1px solid var(--line); margin: 24px 0; }
.switch-inline { margin: 0; }
.switch-inline .switch-label small { color: var(--text-3); }
.accent-row { display: flex; align-items: flex-end; gap: 14px; margin-bottom: 14px; }
.accent-row input[type="color"] { width: 54px; height: 44px; padding: 2px; border: 1px solid var(--line-2); border-radius: 10px; background: var(--surface); cursor: pointer; flex: none; }
.accent-swatches { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 18px; }
.accent-sw { width: 30px; height: 30px; border-radius: 8px; border: 1px solid rgba(255, 255, 255, 0.15); cursor: pointer; padding: 0; transition: transform 0.12s; }
.accent-sw:hover { transform: scale(1.08); }
.brand-preview { display: flex; align-items: center; justify-content: center; background: var(--bg-2); border: 1px solid var(--line); border-radius: 10px; padding: 22px; margin-bottom: 12px; }
.brand-preview img { max-height: 58px; max-width: 100%; }
.brand-preview-fav img { max-height: 40px; }
/* The background preview is judged on framing, not on the mark, so it shows
   the whole image edge to edge at roughly the shape it renders at on the page
   rather than being boxed like a logo. */
.brand-preview-wide { padding: 0; overflow: hidden; aspect-ratio: 16 / 7; }
.brand-preview-wide img { max-height: none; width: 100%; height: 100%; object-fit: cover; display: block; }
.brand-form { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 8px; }
.brand-form input[type="file"] { font-size: 12.5px; color: var(--text-2); min-width: 0; flex: 1; }
/* The background form carries two controls as well as the file, which a single
   flex row squeezes to nothing. Declared after .brand-form so the display
   switch lands; the file input and button span both columns. */
.brand-form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; align-items: end; }
.brand-form-grid input[type="file"] { grid-column: 1 / -1; flex: none; }
.brand-form-grid .field { margin: 0; }
.brand-form-grid .btn { grid-column: 1 / -1; justify-self: start; }

.live-wrap { overflow-x: auto; }
.live-path { font-family: var(--font-mono); font-size: 12.5px; color: var(--text); }
.live-empty { color: var(--text-3); text-align: center; padding: 24px 0; }
.live-table th { white-space: nowrap; }
.card-head .online-dot { display: inline-block; vertical-align: middle; margin-right: 4px; }

.announce { display: flex; align-items: center; gap: 12px; padding: 9px 20px; font-size: 13.5px; position: relative; z-index: 40; }
.announce-text { flex: 1; text-align: center; }
.announce-info { background: var(--accent-soft); color: var(--accent-3); border-bottom: 1px solid var(--accent-line); }
.announce-success { background: var(--success-soft); color: var(--success); border-bottom: 1px solid rgba(127, 181, 138, 0.4); }
.announce-warn { background: rgba(217, 168, 78, 0.12); color: var(--warn); border-bottom: 1px solid rgba(217, 168, 78, 0.4); }
.announce-x { background: none; border: none; color: inherit; opacity: 0.7; font-size: 20px; line-height: 1; cursor: pointer; padding: 0 4px; flex: none; }
.announce-x:hover { opacity: 1; }

.consent { position: fixed; left: 0; right: 0; bottom: 0; z-index: 200; background: var(--surface); border-top: 1px solid var(--line-2); box-shadow: 0 -20px 50px -30px rgba(0, 0, 0, 0.85); animation: consent-in 0.3s ease-out; }
@keyframes consent-in { from { transform: translateY(100%); } }
.consent-inner { max-width: 1140px; margin: 0 auto; padding: 16px 22px; display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
.consent-text { display: flex; flex-direction: column; gap: 2px; min-width: 240px; flex: 1; }
.consent-text strong { font-size: 14px; }
.consent-text span { color: var(--text-2); font-size: 13px; line-height: 1.5; }
.consent-actions { display: flex; gap: 10px; flex: none; }

@media (max-width: 760px) {
    .kpi-num { font-size: 21px; }
    .consent-inner { padding: 14px 16px; }
}

/* ============================================ sign-in & connections (v1.9) */

.brand-glyph { flex: none; }
.btn .brand-glyph { margin-right: 2px; }

.btn-steam { background: #1b2838; color: #fff; border: 1px solid #2a475e; }
.btn-steam:hover { background: #223449; border-color: #66c0f4; color: #fff; }
.btn-discord { background: #5865f2; color: #fff; border: 1px solid #5865f2; }
.btn-discord:hover { background: #4752c4; border-color: #4752c4; color: #fff; }

.or-sep { display: flex; align-items: center; gap: 12px; margin: 16px 0; color: var(--text-3); font-size: 12px; }
.or-sep::before, .or-sep::after { content: ""; flex: 1; height: 1px; background: var(--line); }
.auth-foot-steam { margin-top: 8px; margin-bottom: 0; }

.profile-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; align-items: start; }
.profile-grid .profile-span { grid-column: 1 / -1; }

.conn { display: flex; align-items: center; gap: 14px; padding: 14px 0; border-top: 1px solid var(--line); }
.conn:first-of-type { border-top: none; }
.conn-ic { display: flex; align-items: center; justify-content: center; width: 44px; height: 44px; border-radius: 11px; flex: none; color: #fff; overflow: hidden; }
.conn-ic img { width: 100%; height: 100%; object-fit: cover; }
.conn-steam { background: #1b2838; }
.conn-discord { background: #5865f2; }
.conn-info { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.conn-name { font-weight: 700; font-size: 14.5px; }
.conn-sub { color: var(--text-3); font-size: 13px; }
.conn-act { margin-left: auto; display: flex; align-items: center; gap: 10px; flex: none; }

@media (max-width: 720px) {
    .profile-grid { grid-template-columns: 1fr; }
}

/* ==================================================== commission portal (v1.10) */

.kicker { display: inline-block; font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--accent-2); margin-bottom: 6px; }

.commission-grid { display: grid; grid-template-columns: 1fr 344px; gap: 22px; align-items: start; }
.commission-main { display: flex; flex-direction: column; gap: 20px; min-width: 0; }
.commission-side { display: flex; flex-direction: column; gap: 16px; position: sticky; top: 84px; }

.svc-cat-title { font-family: var(--font-display); font-size: 13px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-3); margin: 18px 0 10px; }
.svc-cat-title:first-of-type { margin-top: 2px; }
.svc-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(232px, 1fr)); gap: 12px; }
.svc-card { display: flex; flex-direction: column; gap: 8px; background: var(--surface); border: 1px solid var(--line); border-radius: 12px; padding: 14px 15px; transition: border-color 0.15s, box-shadow 0.15s, background 0.15s; }
.svc-card:hover { border-color: var(--line-2); }
.svc-card.selected { border-color: var(--accent-2); background: linear-gradient(180deg, rgba(4, 102, 200, 0.08), var(--surface)); box-shadow: 0 0 0 1px rgba(79, 158, 233, 0.35); }
.svc-pick { display: flex; align-items: center; gap: 10px; cursor: pointer; }
.svc-check { width: 18px; height: 18px; flex: none; accent-color: var(--accent); cursor: pointer; }
.svc-name { font-weight: 700; font-size: 14.5px; color: var(--text); }
.svc-desc { color: var(--text-3); font-size: 12.5px; line-height: 1.45; margin: 0; }
.svc-foot { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: auto; }
.svc-price { font-weight: 700; color: var(--text); font-size: 14px; }
.svc-price small { color: var(--text-3); font-weight: 400; font-size: 11px; }
.svc-qty { display: inline-flex; align-items: center; gap: 0; border: 1px solid var(--line-2); border-radius: 8px; overflow: hidden; }
.svc-qbtn { width: 28px; height: 28px; border: none; background: var(--surface-2); color: var(--text); font-size: 16px; line-height: 1; cursor: pointer; }
.svc-qbtn:hover { background: var(--accent); color: #fff; }
.svc-qinput { width: 34px; height: 28px; border: none; background: transparent; color: var(--text); text-align: center; font-weight: 700; -moz-appearance: textfield; }
.svc-qinput::-webkit-outer-spin-button, .svc-qinput::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

.commission-cart { position: relative; }
.cart-lines { list-style: none; margin: 0 0 6px; padding: 0; display: flex; flex-direction: column; gap: 8px; max-height: 260px; overflow-y: auto; }
.cart-lines li { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; font-size: 13.5px; color: var(--text); }
.cart-lines li span:last-child { font-variant-numeric: tabular-nums; color: var(--text-2); flex: none; }
.cart-empty { color: var(--text-3); font-size: 13px; }
.commission-total { display: flex; align-items: baseline; justify-content: space-between; margin: 4px 0 14px; }
.commission-total span { color: var(--text-2); font-size: 13.5px; }
.commission-total strong { font-family: var(--font-display); font-size: 26px; font-weight: 800; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }

.commission-steps { display: flex; align-items: center; gap: 10px; margin: 4px 0 22px; flex-wrap: wrap; }
.cstep { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; font-weight: 600; color: var(--text-3); padding: 6px 12px; border: 1px solid var(--line); border-radius: 999px; }
.cstep .ic { color: var(--text-3); }
.cstep.active { color: var(--accent-2); border-color: var(--accent-line); background: var(--accent-soft); }
.cstep.active .ic { color: var(--accent-2); }
.cstep.done { color: var(--success); border-color: rgba(127, 181, 138, 0.35); }
.cstep.done .ic { color: var(--success); }
.cstep-sep { flex: 1; max-width: 34px; height: 1px; background: var(--line); }

.pay-options { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 14px; margin-top: 8px; }
.pay-option { display: flex; flex-direction: column; gap: 4px; background: var(--surface-2); border: 1px solid var(--line); border-radius: 13px; padding: 16px; }
.pay-option-ic { display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px; border-radius: 10px; background: var(--surface); border: 1px solid var(--line-2); color: var(--accent-2); margin-bottom: 6px; }
.pay-option-name { font-weight: 700; font-size: 15px; }
.pay-option-sub { color: var(--text-3); font-size: 12.5px; line-height: 1.4; flex: 1; }
.pay-option-amt { font-family: var(--font-display); font-weight: 800; font-size: 18px; margin: 8px 0 10px; }

@media (max-width: 900px) {
    .commission-grid { grid-template-columns: 1fr; }
    .commission-side { position: static; }
}

/* commission portal — dashboard + viewer bits */
.dash-hero-portal { display: flex; align-items: center; gap: 20px; justify-content: space-between; flex-wrap: wrap; }
.dash-hero-copy { min-width: 0; }
.dash-hero-cta { flex: none; }

.commission-list { display: flex; flex-direction: column; gap: 8px; }
.commission-row { display: flex; align-items: center; gap: 14px; padding: 13px 16px; background: var(--surface); border: 1px solid var(--line); border-radius: 12px; color: var(--text); transition: border-color 0.15s, transform 0.15s; }
.commission-row:hover { border-color: var(--line-2); transform: translateY(-1px); }
.commission-row-ref { font-family: var(--font-mono); font-size: 12px; color: var(--text-3); flex: none; }
.commission-row-title { font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; }
.commission-row-amt { font-variant-numeric: tabular-nums; color: var(--text-2); flex: none; }

.viewer-commission-note { display: flex; align-items: center; gap: 12px; background: var(--accent-soft); border: 1px solid var(--accent-line); color: var(--accent-3); border-radius: 12px; padding: 12px 16px; margin-bottom: 18px; }
.viewer-commission-note span { flex: 1; font-size: 13.5px; }

/* commission intake — full-width grid, variant tiers, sticky quote bar (v1.11) */
.commission-intake { display: flex; flex-direction: column; gap: 20px; }
.commission-intake .svc-grid { grid-template-columns: repeat(auto-fill, minmax(212px, 1fr)); }

.svc-card-variant { grid-column: 1 / -1; gap: 12px; }
.svc-card-variant .svc-head { display: flex; flex-direction: column; gap: 4px; }
.svc-card-variant .svc-name { font-size: 15px; }
.svc-variants { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; }
.svc-variant { position: relative; display: flex; flex-direction: column; align-items: center; text-align: center; gap: 5px; padding: 15px 10px; background: var(--surface-2); border: 1px solid var(--line-2); border-radius: 11px; cursor: pointer; transition: border-color 0.15s, background 0.15s, box-shadow 0.15s; }
.svc-variant input { position: absolute; inset: 0; margin: 0; opacity: 0; cursor: pointer; }
.svc-variant-ic { display: inline-flex; color: var(--text-2); transition: color 0.15s; }
.svc-variant-label { font-weight: 700; font-size: 13px; }
.svc-variant-price { font-size: 12px; color: var(--text-3); font-variant-numeric: tabular-nums; }
.svc-variant:hover { border-color: var(--line-2); background: var(--surface); }
.svc-variant.checked { border-color: var(--accent-2); background: var(--accent-soft); box-shadow: 0 0 0 1px rgba(79, 158, 233, 0.35); }
.svc-variant.checked .svc-variant-ic { color: var(--accent-2); }
.svc-variant.checked .svc-variant-price { color: var(--accent-3); }
.svc-foot-qty { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.svc-qty-label { font-size: 12.5px; color: var(--text-3); }

.quote-bar { position: sticky; bottom: 12px; z-index: 30; display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; background: rgba(11, 12, 15, 0.9); -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px); border: 1px solid var(--line-2); border-radius: 14px; padding: 13px 18px; box-shadow: 0 16px 40px -22px rgba(0, 0, 0, 0.85); }
.quote-bar-info { display: flex; align-items: baseline; gap: 18px; flex-wrap: wrap; }
.quote-bar-count { color: var(--text-2); font-size: 13.5px; }
.quote-bar-total { display: inline-flex; align-items: baseline; gap: 8px; color: var(--text-3); font-size: 13px; }
.quote-bar-total strong { font-family: var(--font-display); font-size: 24px; font-weight: 800; color: var(--text); font-variant-numeric: tabular-nums; letter-spacing: -0.02em; }

/* City nav responsive (see "City-style top nav bar" above) */
/* Phone: burger on the left, mark in the middle, nothing on the right.
   Both sides take an equal share of the leftover space, which is the only
   thing that puts the mark on the TRUE centre — an auto margin would drift as
   soon as the burger or the account controls changed width.

   Everything else folds into the burger: the links, the standout button and
   the account controls alike. That is why nav_mobile_menu_html renders sign-in
   and the account items itself — at this width they exist nowhere else. */
@media (max-width: 860px) {
    .topnav-inner { padding: 0 16px; }
    .topnav-side-l, .topnav-side-r { flex: 1 1 0; }
    .navmenu { display: block; }
    .topnav-links { display: none; }
    .nav-drop { display: none; }
    .usermenu-name { display: none; }
    /* Nothing on the right. Emptied rather than removed so the element keeps
       its half of the flex and the mark stays centred. */
    .topnav-side-r > * { display: none; }
}

/* ==================================================== request wizard (v1.12) */
.wizard-progress { list-style: none; display: flex; align-items: center; gap: 0; margin: 8px 0 22px; padding: 0; }
.wz-dot { display: flex; flex-direction: column; align-items: center; gap: 5px; position: relative; flex: 1; color: var(--text-3); font-size: 11.5px; font-weight: 600; }
.wz-dot b { display: flex; align-items: center; justify-content: center; width: 30px; height: 30px; border-radius: 50%; background: var(--surface-2); border: 1px solid var(--line-2); font-size: 13px; font-family: var(--font-display); transition: all 0.2s; }
.wz-dot::before { content: ""; position: absolute; top: 15px; left: -50%; width: 100%; height: 2px; background: var(--line); z-index: -1; }
.wz-dot:first-child::before { display: none; }
.wz-dot.active { color: var(--accent-2); }
.wz-dot.active b { background: var(--accent-soft); border-color: var(--accent-2); color: var(--accent-2); box-shadow: 0 0 16px rgba(4, 102, 200, 0.35); }
.wz-dot.done { color: var(--success); }
.wz-dot.done b { background: var(--success-soft); border-color: rgba(127, 181, 138, 0.5); color: var(--success); }
.wz-dot.done::before, .wz-dot.active::before { background: linear-gradient(90deg, var(--accent), var(--line)); }

.wizard-step { background: var(--surface); border: 1px solid var(--line); border-radius: 16px; padding: 26px; }
.wizard-step.is-active { animation: wz-in 0.35s cubic-bezier(0.22, 1, 0.36, 1); }
@keyframes wz-in { from { opacity: 0; transform: translateY(14px) scale(0.99); } to { opacity: 1; transform: none; } }
.wizard-h { font-family: var(--font-display); font-size: clamp(20px, 3vw, 27px); font-weight: 800; letter-spacing: -0.02em; margin: 0 0 4px; }
.wizard-sub { color: var(--text-3); font-size: 13.5px; margin: 0 0 18px; }
.wizard-nav { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 24px; }
.wizard-nav > span { flex: 1; }

.type-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 14px; margin-top: 6px; }
.type-card { position: relative; display: flex; flex-direction: column; align-items: center; text-align: center; gap: 8px; padding: 26px 18px; background: var(--surface-2); border: 1px solid var(--line-2); border-radius: 14px; cursor: pointer; transition: border-color 0.15s, background 0.15s, box-shadow 0.15s, transform 0.15s; }
.type-card input { position: absolute; inset: 0; opacity: 0; cursor: pointer; margin: 0; }
.type-ic { display: inline-flex; align-items: center; justify-content: center; width: 58px; height: 58px; border-radius: 14px; background: var(--surface); border: 1px solid var(--line-2); color: var(--accent-2); }
.type-name { font-family: var(--font-display); font-weight: 800; font-size: 16px; }
.type-desc { color: var(--text-3); font-size: 12.5px; line-height: 1.4; }
.type-card:hover { border-color: var(--line-2); transform: translateY(-2px); }
.type-card:has(input:checked) { border-color: var(--accent-2); background: linear-gradient(180deg, rgba(4, 102, 200, 0.1), var(--surface-2)); box-shadow: 0 0 0 1px rgba(79, 158, 233, 0.4), 0 0 30px rgba(4, 102, 200, 0.25); }
.type-card:has(input:checked) .type-ic { background: var(--accent-soft); border-color: var(--accent-2); }

.proj-choices { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 12px; margin-top: 4px; }
.proj-card { position: relative; display: grid; grid-template-columns: auto 1fr; grid-template-rows: auto auto; column-gap: 11px; align-items: center; padding: 14px 15px; background: var(--surface-2); border: 1px solid var(--line-2); border-radius: 12px; cursor: pointer; transition: border-color 0.15s, background 0.15s; }
.proj-card input { position: absolute; inset: 0; opacity: 0; cursor: pointer; margin: 0; }
.proj-ic { grid-row: 1 / 3; display: inline-flex; align-items: center; justify-content: center; width: 38px; height: 38px; border-radius: 10px; background: var(--surface); border: 1px solid var(--line-2); color: var(--accent-2); }
.proj-name { font-weight: 700; font-size: 14px; }
.proj-sub { color: var(--text-3); font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.proj-card:has(input:checked) { border-color: var(--accent-2); background: var(--accent-soft); }
.proj-new-fields { margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--line); display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }

.review-card { border: 1px solid var(--line); border-radius: 12px; overflow: hidden; }
.review-meta { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; padding: 12px 16px; border-bottom: 1px solid var(--line); }
.review-meta span { color: var(--text-3); font-size: 13px; }
.review-meta strong { font-weight: 700; }
.review-table { width: 100%; border-collapse: collapse; }
.review-table td { padding: 10px 16px; border-bottom: 1px solid var(--line); font-size: 13.5px; }
.review-table td:last-child { text-align: right; font-variant-numeric: tabular-nums; color: var(--text-2); }
.review-total td { border-bottom: none; font-weight: 800; font-size: 15px; color: var(--text); }

.celebrate-banner { display: flex; align-items: center; gap: 12px; background: var(--success-soft); border: 1px solid rgba(127, 181, 138, 0.45); color: var(--success); border-radius: 12px; padding: 14px 18px; margin-bottom: 16px; animation: wz-in 0.4s ease; }
.celebrate-banner strong { color: var(--text); }

@media (max-width: 640px) {
    .wz-dot span { display: none; }
    .proj-new-fields { grid-template-columns: 1fr; }
    .wizard-step { padding: 20px 16px; }
}

/* commission/services admin bits (v1.12) */
.commission-brief { color: var(--text-2); line-height: 1.6; margin: 0; }
.status-actions { display: flex; flex-direction: column; gap: 8px; }
.admin-svc-group { margin-bottom: 18px; }
.tier-row { display: flex; align-items: center; gap: 10px; padding: 9px 0; border-bottom: 1px solid var(--line); }
.tier-row:last-of-type { border-bottom: none; }
.tier-ic { display: inline-flex; color: var(--accent-2); flex: none; }
.tier-name { font-weight: 600; font-size: 13.5px; flex: 1; min-width: 0; }
.tier-price { color: var(--text-2); font-variant-numeric: tabular-nums; font-size: 13px; }
.tier-add { margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--line); }

/* ==================================================== page builder (v1.13) */
/* --- public rendering --- */
.pb-main { max-width: 1140px; margin: 0 auto; padding: 44px 22px 90px; }
.pb-canvas { width: 100%; }
.pb-blank-body { background: var(--bg); }
.pb-draft-bar { background: var(--warn); color: #17130a; text-align: center; padding: 8px 12px; font-size: 13px; font-weight: 700; }
.pb-draft-bar a { color: #17130a; text-decoration: underline; }
.pb-block { margin: 0 0 24px; }
.pb-block:last-child { margin-bottom: 0; }
.pb-left { text-align: left; } .pb-center { text-align: center; } .pb-right { text-align: right; }
.pb-heading { font-family: var(--font-display); font-weight: 800; letter-spacing: -0.02em; margin: 0 0 12px; color: var(--text); }
h1.pb-heading { font-size: clamp(30px, 5vw, 52px); } h2.pb-heading { font-size: clamp(24px, 3.6vw, 38px); } h3.pb-heading { font-size: clamp(19px, 2.4vw, 26px); } h4.pb-heading { font-size: 18px; }
.pb-text { color: var(--text-2); line-height: 1.7; }
.pb-text a { color: var(--accent-2); }
.pb-image img { border-radius: 12px; display: inline-block; }
.pb-buttons { display: flex; gap: 12px; flex-wrap: wrap; }
.pb-buttons.pb-center { justify-content: center; } .pb-buttons.pb-right { justify-content: flex-end; }
.pb-hero { padding: clamp(40px, 8vw, 92px) 0; }
.pb-hero-kicker { font-family: var(--font-mono); text-transform: uppercase; letter-spacing: 0.14em; color: var(--accent-2); font-size: 12px; margin: 0 0 14px; }
.pb-hero-title { font-family: var(--font-display); font-weight: 800; font-size: clamp(34px, 7vw, 74px); letter-spacing: -0.03em; line-height: 1.01; margin: 0 0 16px; color: var(--text); }
.pb-hero-sub { color: var(--text-2); font-size: clamp(16px, 2vw, 20px); line-height: 1.55; max-width: 60ch; margin: 0 0 26px; }
.pb-hero.pb-center .pb-hero-sub { margin-left: auto; margin-right: auto; }
.pb-hero.pb-center .pb-buttons { justify-content: center; }
.pb-columns { display: grid; gap: 24px; }
.pb-cols-2 { grid-template-columns: repeat(2, 1fr); } .pb-cols-3 { grid-template-columns: repeat(3, 1fr); } .pb-cols-4 { grid-template-columns: repeat(4, 1fr); }
.pb-col { color: var(--text-2); line-height: 1.7; min-width: 0; }
.pb-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 16px; }
.pb-card { display: block; background: var(--surface); border: 1px solid var(--line); border-radius: 14px; padding: 22px; color: var(--text); transition: border-color 0.15s, transform 0.15s; }
a.pb-card:hover { border-color: var(--accent-line); transform: translateY(-2px); color: var(--text); }
.pb-card-ic { display: inline-flex; color: var(--accent-2); margin-bottom: 8px; }
.pb-card-title { font-family: var(--font-display); font-weight: 800; font-size: 17px; margin: 0 0 6px; }
.pb-card-text { color: var(--text-3); font-size: 13.5px; line-height: 1.5; margin: 0; }
.pb-divider { border: none; border-top: 1px solid var(--line); margin: 24px 0; }
@media (max-width: 760px) { .pb-cols-2, .pb-cols-3, .pb-cols-4 { grid-template-columns: 1fr; } }

/* --- builder UI --- */
.pb-topbar { display: flex; align-items: center; gap: 10px; background: var(--surface); border: 1px solid var(--line); border-radius: 12px; padding: 9px 12px; margin-bottom: 16px; position: sticky; top: calc(var(--topbar-h, 0px) + 8px); z-index: 25; }
.pb-title-input { flex: 1; min-width: 0; background: transparent; border: none; color: var(--text); font-family: var(--font-display); font-size: 18px; font-weight: 700; padding: 6px 8px; }
.pb-title-input:focus { outline: none; background: var(--surface-2); border-radius: 8px; }
.pb-topbar-spacer { flex: 1; }
.pb-status { background: var(--surface-2); border: 1px solid var(--line-2); border-radius: 8px; color: var(--text); padding: 7px 10px; }
.pb-layout { display: grid; grid-template-columns: 1fr 328px; gap: 20px; align-items: start; }
.pb-editor-col { min-width: 0; }
.pb-settings-col { display: flex; flex-direction: column; gap: 16px; position: sticky; top: 74px; }
.pb-palette { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; background: var(--surface); border: 1px solid var(--line); border-radius: 12px; padding: 10px 12px; margin-bottom: 14px; }
.pb-palette-label { color: var(--text-3); font-size: 12.5px; margin-right: 4px; }
.pb-add-btn { display: inline-flex; align-items: center; gap: 5px; padding: 6px 10px; font-size: 12.5px; font-weight: 600; background: var(--surface-2); border: 1px solid var(--line-2); border-radius: 8px; color: var(--text-2); cursor: pointer; }
.pb-add-btn:hover { border-color: var(--accent-2); color: var(--text); }
.pb-add-btn .ic { color: var(--accent-2); }
.pb-block-list { display: flex; flex-direction: column; gap: 12px; }
.pb-empty { text-align: center; color: var(--text-3); padding: 44px 20px; border: 1px dashed var(--line-2); border-radius: 12px; }
.pb-block-card { background: var(--surface); border: 1px solid var(--line); border-radius: 12px; overflow: hidden; }
.pb-block-head { display: flex; align-items: center; justify-content: space-between; padding: 9px 13px; background: var(--surface-2); border-bottom: 1px solid var(--line); }
.pb-block-type { font-family: var(--font-display); font-weight: 700; font-size: 12px; text-transform: uppercase; letter-spacing: 0.07em; color: var(--text-2); }
.pb-block-tools { display: flex; gap: 4px; }
.pb-tool { width: 26px; height: 26px; border: 1px solid var(--line-2); background: var(--surface); border-radius: 6px; color: var(--text-2); cursor: pointer; font-size: 14px; line-height: 1; }
.pb-tool:hover { border-color: var(--accent-2); color: var(--text); }
.pb-del:hover { border-color: var(--danger); color: var(--danger); }
.pb-block-body { padding: 14px; display: flex; flex-direction: column; gap: 12px; }
.pb-f { display: flex; flex-direction: column; gap: 5px; }
.pb-f > span { font-size: 12.5px; color: var(--text-3); }
.pb-f input[type="text"], .pb-f input[type="number"], .pb-f select, .pb-f textarea { width: 100%; background: var(--surface-2); border: 1px solid var(--line-2); border-radius: 8px; color: var(--text); padding: 8px 10px; font-size: 13.5px; font-family: inherit; }
.pb-f textarea { resize: vertical; }
.pb-f input:focus, .pb-f select:focus, .pb-f textarea:focus { outline: none; border-color: var(--accent-2); }
.pb-code-input { font-family: var(--font-mono) !important; font-size: 12.5px !important; }
.pb-list { display: flex; flex-direction: column; gap: 8px; }
.pb-list-item { display: flex; gap: 8px; align-items: flex-start; background: var(--surface-2); border: 1px solid var(--line); border-radius: 8px; padding: 8px; }
.pb-list-fields { flex: 1; display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.pb-home-bar { display: flex; align-items: center; gap: 12px; margin-top: 16px; padding: 12px 16px; background: var(--surface); border: 1px solid var(--line); border-radius: 12px; }
@media (max-width: 900px) { .pb-layout { grid-template-columns: 1fr; } .pb-settings-col { position: static; } }

/* ==================================================== commissions rebuild (v1.13) */

/* --- Your Commissions list --- */
.commission-cards { display: flex; flex-direction: column; gap: 20px; }
.commission-card { margin-bottom: 0; }
.commission-card.is-highlight { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.commission-card .section-title { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; font-size: 16px; }
.commission-ref { font-family: var(--font-mono); font-size: 12px; font-weight: 700; color: var(--accent-2); background: var(--accent-soft); border: 1px solid var(--accent-line); border-radius: 6px; padding: 2px 7px; letter-spacing: 0.03em; }

.commission-scope { border: 1px solid var(--line); border-radius: 12px; overflow: hidden; margin-bottom: 14px; }
.cscope-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 14px; padding: 11px 15px; border-bottom: 1px solid var(--line); }
.cscope-main { min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.cscope-name { font-weight: 600; font-size: 14px; }
.cscope-qty { color: var(--text-3); font-weight: 700; font-size: 12.5px; }
.cscope-detail { color: var(--text-2); font-size: 12.5px; line-height: 1.5; white-space: pre-wrap; }
.cscope-amt { font-variant-numeric: tabular-nums; color: var(--text-2); font-size: 13.5px; flex: none; }
.cscope-total { display: flex; align-items: center; justify-content: space-between; padding: 12px 15px; background: var(--surface-2); }
.cscope-total span { color: var(--text-2); font-size: 13px; }
.cscope-total b { font-family: var(--font-display); font-size: 17px; font-weight: 800; }

.commission-actions { display: flex; align-items: center; gap: 10px 14px; flex-wrap: wrap; margin-bottom: 6px; }
.commission-hint { color: var(--text-3); font-size: 12.5px; }
.commission-cancel { margin-left: auto; }

.commission-block { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--line); }
.commission-block-h { display: flex; align-items: center; gap: 8px; font-family: var(--font-display); font-size: 12px; text-transform: uppercase; letter-spacing: 0.07em; color: var(--text-3); margin: 0 0 10px; }
.commission-block-h svg { color: var(--accent-2); }

/* --- delivery / download states --- */
.cdl { display: flex; align-items: center; justify-content: space-between; gap: 14px; flex-wrap: wrap; border: 1px solid var(--line); border-radius: 12px; padding: 13px 15px; }
.cdl-text { display: inline-flex; align-items: center; gap: 9px; font-size: 13.5px; font-weight: 600; }
.cdl-text svg { flex: none; }
.cdl-ready { border-color: rgba(127, 181, 138, 0.4); background: var(--success-soft); }
.cdl-ready .cdl-text { color: var(--text); }
.cdl-locked { border-color: var(--accent-line); background: linear-gradient(180deg, rgba(4, 102, 200, 0.06), var(--surface)); }
.cdl-locked .cdl-text { color: var(--accent-2); }
.cdl-none { display: flex; align-items: center; gap: 9px; color: var(--text-3); font-size: 13px; margin: 0; padding: 4px 2px; }
.cdl-none svg { flex: none; color: var(--text-3); }

/* --- confirm & pay modal --- */
.modal-sub { color: var(--text-2); font-size: 13.5px; line-height: 1.55; margin: -6px 0 16px; }
.modal-sub strong { color: var(--text); }
.cpay-list { display: flex; flex-direction: column; gap: 10px; }
.cpay-btn { display: flex; align-items: center; gap: 13px; width: 100%; text-align: left; background: var(--surface-2); border: 1px solid var(--line-2); border-radius: 13px; padding: 13px 15px; cursor: pointer; color: var(--text); transition: border-color 0.15s, background 0.15s, transform 0.1s; }
.cpay-btn:hover { border-color: var(--accent); background: var(--surface-3); }
.cpay-btn:active { transform: translateY(1px); }
.cpay-btn:disabled { opacity: 0.5; cursor: not-allowed; }
.cpay-btn:disabled:hover { border-color: var(--line-2); background: var(--surface-2); }
.cpay-ic { display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px; border-radius: 10px; background: var(--surface); border: 1px solid var(--line-2); color: var(--accent-2); flex: none; }
.cpay-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.cpay-body b { font-weight: 700; font-size: 14.5px; }
.cpay-body small { color: var(--text-3); font-size: 12.5px; line-height: 1.4; }
.cpay-go { color: var(--text-3); flex: none; }
.cpay-btn:hover .cpay-go { color: var(--accent-2); }

/* --- create wizard (modal) --- */
.cw-card { max-width: 640px; }
.cw-steps { display: flex; align-items: center; gap: 6px; list-style: none; margin: 0 0 18px; padding: 0; }
.cw-dot { display: flex; align-items: center; gap: 7px; flex: 1; color: var(--text-3); font-size: 12.5px; font-weight: 600; }
.cw-dot b { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; border-radius: 50%; background: var(--surface-2); border: 1px solid var(--line-2); font-size: 11.5px; flex: none; }
.cw-dot.is-active { color: var(--text); }
.cw-dot.is-active b { background: var(--accent); border-color: var(--accent); color: #fff; }
.cw-dot.is-done b { background: var(--accent-soft); border-color: var(--accent-line); color: var(--accent-2); }
.cw-step { animation: wz-in 0.25s ease; }
.cw-h { font-family: var(--font-display); font-size: 17px; font-weight: 800; margin: 0 0 4px; }
.cw-sub { color: var(--text-2); font-size: 13px; line-height: 1.5; margin: 0 0 16px; }
.cw-optional { font-family: var(--font-ui); font-weight: 600; font-size: 11px; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-3); background: var(--surface-2); border: 1px solid var(--line-2); border-radius: 20px; padding: 2px 9px; vertical-align: 2px; }
.cw-empty { color: var(--text-3); font-size: 13px; text-align: center; padding: 20px; }

/* option cards */
.cw-opts { display: flex; flex-direction: column; gap: 10px; }
.cw-opt { border: 1px solid var(--line-2); border-radius: 13px; overflow: hidden; transition: border-color 0.15s, background 0.15s; }
.cw-opt.is-selected { border-color: var(--accent); background: var(--accent-soft); }
.cw-opt-pick { display: flex; align-items: center; gap: 12px; padding: 12px 14px; cursor: pointer; }
.cw-opt-check { position: absolute; opacity: 0; width: 0; height: 0; }
.cw-opt-ic { display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px; border-radius: 10px; background: var(--surface-2); border: 1px solid var(--line-2); color: var(--accent-2); flex: none; }
.cw-opt.is-selected .cw-opt-ic { background: var(--accent); border-color: var(--accent); color: #fff; }
.cw-opt-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.cw-opt-name { font-weight: 700; font-size: 14.5px; }
.cw-opt-desc { color: var(--text-3); font-size: 12.5px; line-height: 1.4; }
.cw-opt-price { font-family: var(--font-display); font-weight: 800; font-size: 15px; text-align: right; flex: none; display: flex; flex-direction: column; }
.cw-opt-price small { font-family: var(--font-ui); font-weight: 600; font-size: 11px; color: var(--text-3); }
.cw-opt-detail { padding: 4px 14px 14px; border-top: 1px dashed var(--line-2); display: flex; flex-direction: column; gap: 12px; }
.cw-qty { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding-top: 12px; }
.cw-qty-label { font-size: 13px; font-weight: 600; color: var(--text-2); }
.cw-qty-ctrl { display: inline-flex; align-items: center; gap: 4px; }
.cw-qbtn { width: 32px; height: 32px; border-radius: 9px; border: 1px solid var(--line-2); background: var(--surface-2); color: var(--text); font-size: 17px; line-height: 1; cursor: pointer; }
.cw-qbtn:hover { border-color: var(--accent); color: var(--accent-2); }
.cw-qinput { width: 46px; height: 32px; text-align: center; border: 1px solid var(--line-2); border-radius: 9px; background: var(--surface); color: var(--text); font-weight: 700; font-variant-numeric: tabular-nums; -moz-appearance: textfield; }
.cw-qinput::-webkit-outer-spin-button, .cw-qinput::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.cw-field { display: flex; flex-direction: column; gap: 6px; }
.cw-field > span { font-size: 12.5px; color: var(--text-2); font-weight: 600; }
.cw-field textarea { width: 100%; background: var(--surface); border: 1px solid var(--line-2); border-radius: 10px; color: var(--text); padding: 9px 11px; font: inherit; font-size: 13.5px; resize: vertical; }
.cw-field textarea:focus { outline: none; border-color: var(--accent); }

/* references step */
.cw-refblock { margin-bottom: 18px; }
.cw-reflabel { display: flex; align-items: center; gap: 8px; font-weight: 700; font-size: 13.5px; margin-bottom: 10px; }
.cw-reflabel svg { color: var(--accent-2); }
.cw-drop { position: relative; display: flex; flex-direction: column; gap: 8px; border: 1.5px dashed var(--line-2); border-radius: 12px; padding: 16px; cursor: pointer; margin-bottom: 10px; transition: border-color 0.15s, background 0.15s; }
.cw-drop:hover { border-color: var(--accent); background: var(--accent-soft); }
.cw-file { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
.cw-drop-text { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; color: var(--text-2); font-size: 13px; }
.cw-drop-text svg { color: var(--accent-2); }
.cw-drop-text b { color: var(--text); }
.cw-drop-text small { color: var(--text-3); flex-basis: 100%; margin-left: 27px; font-size: 12px; }
.cw-drop-list { color: var(--accent-2); font-size: 12.5px; font-weight: 600; word-break: break-word; }
.cw-drop-list:empty { display: none; }
.cw-rows { display: flex; flex-direction: column; gap: 8px; margin-bottom: 8px; }
.cw-row input { width: 100%; background: var(--surface); border: 1px solid var(--line-2); border-radius: 10px; color: var(--text); padding: 9px 11px; font: inherit; font-size: 13.5px; }
.cw-row input:focus { outline: none; border-color: var(--accent); }
.cw-addrow { align-self: flex-start; }

/* review step */
.cw-review { border: 1px solid var(--line); border-radius: 12px; overflow: hidden; margin-bottom: 12px; }
.cw-rev-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 14px; padding: 11px 14px; border-bottom: 1px solid var(--line); }
.cw-rev-main { min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.cw-rev-name { font-weight: 600; font-size: 14px; }
.cw-rev-qty { color: var(--text-3); font-weight: 700; }
.cw-rev-detail { color: var(--text-2); font-size: 12.5px; line-height: 1.5; white-space: pre-wrap; }
.cw-rev-amt { font-variant-numeric: tabular-nums; color: var(--text-2); font-size: 13.5px; flex: none; }
.cw-rev-total { display: flex; align-items: center; justify-content: space-between; padding: 12px 14px; background: var(--surface-2); }
.cw-rev-total span { color: var(--text-2); font-size: 13px; }
.cw-rev-total strong { font-family: var(--font-display); font-size: 18px; font-weight: 800; }
.cw-rev-refs { padding: 10px 14px; color: var(--text-2); font-size: 12.5px; border-top: 1px solid var(--line); }
.cw-rev-refs-none { color: var(--text-3); }
.cw-note { display: flex; align-items: center; gap: 8px; color: var(--text-3); font-size: 12.5px; margin: 0 0 16px; }
.cw-note svg { color: var(--accent-2); flex: none; }

/* wizard footer nav + quote bar */
.cw-nav { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 18px; }
.cw-bar { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--line); }
.cw-bar-count { color: var(--text-3); font-size: 13px; }
.cw-bar-total { display: flex; align-items: baseline; gap: 8px; }
.cw-bar-total span { color: var(--text-3); font-size: 12.5px; }
.cw-bar-total strong { font-family: var(--font-display); font-size: 20px; font-weight: 800; }

@media (max-width: 560px) {
    .cw-dot span { display: none; }
    .cw-opt-pick { flex-wrap: wrap; }
    .cw-opt-price { text-align: left; flex-direction: row; align-items: baseline; gap: 5px; width: 100%; padding-left: 52px; }
    .commission-cancel { margin-left: 0; }
}

/* --- admin: commission references + deliver --- */
.commission-item-detail { white-space: pre-wrap; margin-top: 4px; max-width: 46ch; }
.ref-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(88px, 1fr)); gap: 8px; margin-bottom: 12px; }
.ref-thumb { display: block; aspect-ratio: 1; border: 1px solid var(--line-2); border-radius: 10px; overflow: hidden; background: var(--surface-2); }
.ref-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ref-thumb:hover { border-color: var(--accent); }
.ref-subhead { display: flex; align-items: center; gap: 7px; font-family: var(--font-display); font-size: 12px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-3); margin: 12px 0 7px; }
.ref-subhead svg { color: var(--accent-2); }
.ref-links { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 5px; }
.ref-links a { font-size: 13px; word-break: break-all; }
.deliver-current { display: flex; flex-direction: column; gap: 3px; padding: 10px 12px; background: var(--surface-2); border: 1px solid var(--line-2); border-radius: 10px; margin-bottom: 10px; }
.deliver-file { display: inline-flex; align-items: center; gap: 8px; font-weight: 600; font-size: 13.5px; word-break: break-all; }
.deliver-file svg { color: var(--accent-2); flex: none; }

/* ============================================== admin shell: side + top bar

   Two pieces, one job each. The sidebar navigates: brand and links, in two runs
   — the sections you work in, and the system ones pinned at the foot. The top
   bar works: jump-to, presence, the account menu, and whatever the page itself
   offers.

   They used to be one piece, and that was the problem. The sidebar carried the
   brand, a search box, fifteen links, a presence chip, a link off-site and the
   account menu, so the column that exists to move you between sections was
   mostly full of things that are not navigation — and the page had nowhere at
   all to put its own buttons. Each half now has a shape that suits it: a column
   for a list, a bar for controls.

   The sidebar has two widths (full, and a 68px icon rail, remembered per
   browser). Below 1000px it becomes a drawer, which is why the top bar is the
   constant: it sticks, it is what opens the drawer, and on a phone it is the
   whole of the chrome. */

.admin-shell {
    --aside-w: 244px;
    --aside-rail: 68px;
    --rail-pad: 10px;
    --topbar-h: 58px;
    min-height: 100vh;
    display: grid;
    grid-template-columns: var(--aside-w) minmax(0, 1fr);
    transition: grid-template-columns 0.16s ease;
}
.admin-shell.is-rail { grid-template-columns: var(--aside-rail) minmax(0, 1fr); }

/* ------------------------------------------------------------- sidebar ---- */

.admin-side {
    position: sticky; top: 0; align-self: start;
    /* A grid item defaults to min-width:auto, which refuses to shrink below its
       content — so in rail mode the column stayed 244px however narrow the track
       was told to be. This is what actually makes the rail a rail. */
    min-width: 0;
    height: 100vh; display: flex; flex-direction: column;
    padding: 0 12px 12px;
    background: var(--bg-2); border-right: 1px solid var(--line);
    overflow: visible;                 /* flyouts have to escape the column */
    z-index: 50;
}

/* Exactly the height of the top bar, so the brand and the bar's contents sit on
   one line straight across the window. */
.aside-top {
    flex: none; display: flex; align-items: center; gap: 8px;
    height: var(--topbar-h); padding: 0 4px; margin-bottom: 12px;
}
.aside-brand { display: inline-flex; align-items: center; min-width: 0; flex: 1; }
.aside-brand img { height: 24px; width: auto; display: block; flex: none; }
.aside-collapse, .aside-close {
    flex: none; display: inline-flex; align-items: center; justify-content: center;
    width: 30px; height: 30px; border-radius: 8px;
    border: 1px solid var(--line); background: none; color: var(--text-3); cursor: pointer;
}
.aside-collapse:hover, .aside-close:hover { color: var(--text); border-color: var(--line-2); background: var(--surface-2); }
.aside-close { display: none; border-color: transparent; }   /* drawer only */

/* ---- the nav ---- */
.aside-nav { flex: 1 1 auto; min-height: 0; overflow-y: auto; overflow-x: hidden; display: flex; flex-direction: column; gap: 2px; padding-right: 2px; }
.aside-nav::-webkit-scrollbar { width: 6px; }
.aside-nav::-webkit-scrollbar-thumb { background: var(--line-2); border-radius: 3px; }

/* Settings, accounts and the updater: configured once and then left alone, so
   they sit apart from the sections you actually work in. */
.aside-nav-foot {
    flex: none; overflow: visible;
    padding-top: 8px; margin-top: 8px; border-top: 1px solid var(--line);
}
.aside-nav-foot .aside-group { margin-top: 0; }

.aside-link, .aside-item, .aside-head {
    display: flex; align-items: center; gap: 10px;
    padding: 7px 10px; border-radius: 9px;
    font-size: 13.5px; font-weight: 600; color: var(--text-2);
    transition: background 0.14s, color 0.14s;
}
.aside-ic { display: inline-flex; flex: none; color: var(--text-3); transition: color 0.14s; }
.aside-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; }

.aside-link { position: relative; }
.aside-link:hover { background: var(--surface-2); color: var(--text); }
.aside-link:hover .aside-ic { color: var(--text-2); }
.aside-link.is-active { background: var(--accent-soft); color: var(--accent-3); }
.aside-link.is-active .aside-ic { color: var(--accent-2); }

.aside-group { position: relative; margin-top: 7px; }
.aside-head {
    font-size: 10.5px; font-weight: 800; letter-spacing: 0.13em; text-transform: uppercase;
    color: var(--text-3); padding-bottom: 3px; cursor: default;
}
.aside-head .aside-ic { display: none; }
.aside-items { display: flex; flex-direction: column; gap: 2px; }
.aside-item { padding-left: 12px; }
.aside-item svg { color: var(--text-3); flex: none; }
.aside-item:hover { background: var(--surface-2); color: var(--text); }
.aside-item:hover svg { color: var(--text-2); }
.aside-item.is-active { background: var(--accent-soft); color: var(--accent-3); }
.aside-item.is-active svg { color: var(--accent-2); }

/* A count on a link, for the two things that should come and find you: work
   sitting unsent, and money that is late. */
.aside-badge {
    flex: none; margin-left: auto;
    min-width: 18px; height: 18px; padding: 0 5px;
    display: inline-flex; align-items: center; justify-content: center;
    font-size: 10.5px; font-weight: 800; line-height: 1; border-radius: 999px;
    background: var(--accent-soft); color: var(--accent-3); border: 1px solid var(--accent-line);
}
/* The rolled-up count belongs to the rail, where the children it sums are not
   on screen. In the column they are, so it would just be the same number twice. */
.aside-badge-roll { display: none; }

/* ----------------------------------------------------------- rail mode ---- */

.is-rail .admin-side { padding-left: var(--rail-pad); padding-right: var(--rail-pad); }
.is-rail .aside-label { display: none; }
.is-rail .aside-top { justify-content: center; padding: 0; }
.is-rail .aside-brand { justify-content: center; flex: none; }
.is-rail .aside-collapse { position: absolute; top: 20px; right: -13px; width: 26px; height: 26px;
    background: var(--bg-2); border-color: var(--line-2); z-index: 2; }
.is-rail .aside-collapse svg { transform: rotate(180deg); }

/* The flyouts are absolutely positioned children of a group, so a scrolling
   nav would clip them at the column edge. At rail width there are six icons and
   nothing to scroll, so the overflow can simply go. */
.is-rail .aside-nav { overflow: visible; }

.is-rail .aside-link, .is-rail .aside-head { justify-content: center; padding-left: 0; padding-right: 0; }
.is-rail .aside-head { cursor: pointer; padding-top: 8px; padding-bottom: 8px; position: relative; }
.is-rail .aside-head .aside-ic { display: inline-flex; }
.is-rail .aside-group { margin-top: 2px; }

/* With no label to sit beside, a count becomes a marker on the icon. */
.is-rail .aside-nav > .aside-link > .aside-badge,
.is-rail .aside-badge-roll {
    display: inline-flex; position: absolute; top: 2px; right: 6px;
    margin-left: 0; min-width: 16px; height: 16px; padding: 0 4px; font-size: 9.5px;
}

/* The pages of a group, returned as a flyout. Hidden by clip rather than
   display:none so it can animate and stay keyboard-reachable. */
.is-rail .aside-items {
    /* Anchored past the edge of the COLUMN, not the edge of the row. The row
       is inset by the sidebar padding, so 100% + 8px lands back inside the
       column and the flyout overlaps its own border. */
    position: absolute; left: calc(var(--aside-rail) - var(--rail-pad) + 8px); top: 0; z-index: 80;
    min-width: 190px; padding: 6px;
    background: var(--surface); border: 1px solid var(--line-2); border-radius: 12px;
    box-shadow: var(--shadow);
    opacity: 0; visibility: hidden; transform: translateX(-4px);
    transition: opacity 0.12s, transform 0.12s, visibility 0.12s;
}
.is-rail .aside-group:hover .aside-items,
.is-rail .aside-group:focus-within .aside-items { opacity: 1; visibility: visible; transform: none; }
.is-rail .aside-item { padding-left: 10px; }
/* The foot sits at the bottom of the column, so its flyout has to open upward
   or it would run off the screen. */
.is-rail .aside-nav-foot .aside-items { top: auto; bottom: 0; }
/* Without an active page visible in the rail, the group carries the marker. */
.is-rail .aside-group.is-here .aside-head .aside-ic { color: var(--accent-2); }
.is-rail .aside-group.is-here .aside-head { background: var(--accent-soft); border-radius: 9px; }

/* ------------------------------------------------------------- top bar ---- */

.admin-content { min-width: 0; width: 100%; display: flex; flex-direction: column; }

.topbar {
    position: sticky; top: 0; z-index: 60; flex: none;
    display: flex; align-items: center; gap: 8px;
    height: var(--topbar-h); padding: 0 22px;
    background: var(--bg-2); border-bottom: 1px solid var(--line);
}
.topbar-burger {
    display: none; align-items: center; justify-content: center;
    width: 36px; height: 36px; border-radius: 9px; margin-left: -8px;
    border: none; background: none; color: var(--text-2); cursor: pointer;
}
.topbar-burger:hover { background: var(--surface-2); color: var(--text); }

.topbar-title {
    font-family: var(--font-display); font-size: 17px; font-weight: 700;
    letter-spacing: -0.01em; line-height: 1.2; margin: 0;
    min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* The page's own buttons sit next to the page's own name, and the permanent
   furniture stays out at the edge where it always is. */
.topbar-actions { display: flex; align-items: center; gap: 8px; margin-left: 10px; flex: none; }
.topbar-actions:empty { display: none; }
.topbar-tools { display: flex; align-items: center; gap: 6px; margin-left: auto; flex: none; }

.topbar-search { position: relative; width: 210px; flex: none; }
.topbar-search .admin-search-input {
    width: 100%; height: 34px; padding: 0 30px 0 32px; font-size: 13px;
    background: var(--surface); border: 1px solid var(--line); border-radius: 9px; color: var(--text);
}
.topbar-search .admin-search-input::placeholder { color: var(--text-3); }
.topbar-search .admin-search-input:focus { outline: none; border-color: var(--accent); background: var(--surface-2); }
.topbar-search .admin-search-ic { position: absolute; left: 10px; top: 50%; transform: translateY(-50%); color: var(--text-3); display: inline-flex; pointer-events: none; }
.topbar-search .admin-search-kbd {
    position: absolute; right: 9px; top: 50%; transform: translateY(-50%);
    font-family: var(--font-mono); font-size: 10.5px; color: var(--text-3);
    border: 1px solid var(--line-2); border-radius: 5px; padding: 1px 5px; pointer-events: none;
}
.topbar-search .admin-search-input:focus ~ .admin-search-kbd { opacity: 0; }
/* Anchored to the right edge of the box, because the box is out at the right
   edge of the window and a left-anchored menu would hang off it. */
.topbar-search .admin-search-menu {
    position: absolute; top: calc(100% + 6px); right: 0; z-index: 70; width: 300px;
    background: var(--surface); border: 1px solid var(--line-2); border-radius: 12px;
    padding: 6px; box-shadow: var(--shadow); max-height: 340px; overflow-y: auto;
}

.topbar-icon {
    display: inline-flex; align-items: center; justify-content: center;
    width: 34px; height: 34px; border-radius: 9px; flex: none;
    border: 1px solid transparent; background: none; color: var(--text-3); cursor: pointer;
}
.topbar-icon:hover { background: var(--surface-2); color: var(--text); border-color: var(--line); }
.topbar-searchbtn { display: none; }        /* stands in for the box when it will not fit */

/* The presence chip had no styling of its own — in the sidebar it borrowed
   a nav row and a label beside it, and out here it had neither. */
.topbar-online {
    display: inline-flex; align-items: center; gap: 6px; flex: none;
    height: 30px; padding: 0 11px; border-radius: 999px;
    border: 1px solid var(--line); background: var(--surface);
    color: var(--text-2); font-size: 12px; font-weight: 700;
    font-variant-numeric: tabular-nums;
}
.topbar-online:hover { border-color: var(--line-2); color: var(--text); background: var(--surface-2); }

.topbar-avatar { display: inline-flex; padding: 0; border: none; background: none; cursor: pointer; border-radius: 50%; }
.topbar-avatar .avatar { width: 32px; height: 32px; transition: border-color 0.14s; }
.topbar-avatar:hover .avatar { border-color: var(--accent-line); }

/* -------------------------------------------------------------- page ---- */

.admin-content > .page-sub,
.admin-content > .page-body { width: 100%; max-width: 1480px; }
.admin-content > .page-sub { margin: 22px 0 0; padding: 0 30px; }
.admin-content > .page-body { padding: 26px 30px 64px; }
.admin-content > .page-sub + .page-body { padding-top: 18px; }

.admin-scrim { display: none; }

/* ------------------------------------------------ drawer, and narrow ---- */

@media (max-width: 1000px) {
    /* The column becomes a drawer: off-canvas, over the page, dismissed by the
       scrim. Grid goes to one track so the page uses the full width. */
    .admin-shell, .admin-shell.is-rail { grid-template-columns: minmax(0, 1fr); }
    .admin-side {
        position: fixed; top: 0; left: 0; bottom: 0; width: var(--aside-w); height: 100dvh;
        transform: translateX(-100%); transition: transform 0.2s ease; z-index: 90;
        overflow-y: auto;
    }
    .admin-shell.is-open .admin-side { transform: none; }

    /* Rail is a preference about a column. As a drawer it would only ever be a
       worse drawer, so the whole of rail mode is undone here. */
    .admin-shell.is-rail .admin-side { width: var(--aside-w); padding-left: 12px; padding-right: 12px; }
    .is-rail .aside-label { display: revert; }
    .is-rail .aside-head .aside-ic { display: none; }
    .is-rail .aside-nav { overflow-y: auto; }
    .is-rail .aside-items { position: static; opacity: 1; visibility: visible; transform: none;
        background: none; border: 0; box-shadow: none; padding: 0; min-width: 0; }
    .is-rail .aside-link, .is-rail .aside-head { justify-content: flex-start; padding-left: 10px; padding-right: 10px; }
    .is-rail .aside-nav > .aside-link > .aside-badge { position: static; margin-left: auto;
        min-width: 18px; height: 18px; padding: 0 5px; font-size: 10.5px; }
    .is-rail .aside-badge-roll { display: none; }
    .aside-collapse { display: none; }
    .aside-close { display: inline-flex; }
    .aside-top { justify-content: space-between; }

    .admin-scrim { display: block; position: fixed; inset: 0; z-index: 80; background: rgba(0, 0, 0, 0.55); }
    .admin-scrim[hidden] { display: none; }

    .topbar-burger { display: inline-flex; }
    .topbar { padding: 0 16px; }
}

/* The jump box is the first thing to go when the bar runs out of room: it
   becomes its own icon, and opens across the bar when pressed. */
@media (max-width: 760px) {
    .topbar-search { display: none; }
    .topbar-searchbtn { display: inline-flex; }
    .topbar.is-search .topbar-search { display: block; flex: 1 1 auto; width: auto; min-width: 0; }
    .topbar.is-search .topbar-search .admin-search-menu { left: 0; right: 0; width: auto; }
    .topbar.is-search .topbar-burger,
    .topbar.is-search .topbar-title,
    .topbar.is-search .topbar-actions,
    .topbar.is-search .topbar-online,
    .topbar.is-search .topbar-view,
    .topbar.is-search .topbar-account { display: none; }
    .topbar.is-search .topbar-tools { margin-left: 0; flex: 1 1 auto; min-width: 0; }
}

@media (max-width: 620px) {
    .admin-content > .page-body { padding: 20px 16px 44px; }
    .admin-content > .page-sub { padding: 0 16px; margin-top: 16px; }
    .topbar { padding: 0 12px; gap: 6px; }
    /* Buttons shed their labels rather than their place — the icon is still the
       action, and a wrapped two-line bar is worse than a terse one. */
    .topbar-actions .btn { padding-left: 9px; padding-right: 9px; }
    .topbar-actions .btn svg + span { display: none; }
}
.admin-account { position: relative; }
.admin-account-btn { display: inline-flex; padding: 0; border: none; background: none; cursor: pointer; border-radius: 50%; }
.admin-account-btn .avatar { width: 34px; height: 34px; transition: border-color 0.14s; }
.admin-account-btn:hover .avatar { border-color: var(--accent-line); }
.admin-account-menu { position: absolute; top: calc(100% + 8px); right: 0; z-index: 50; min-width: 224px; background: var(--surface); border: 1px solid var(--line-2); border-radius: 12px; padding: 6px; box-shadow: var(--shadow); }
.admin-account-head { padding: 9px 11px 10px; border-bottom: 1px solid var(--line); margin-bottom: 5px; display: flex; flex-direction: column; gap: 2px; }
.admin-account-head strong { font-size: 13.5px; }
.admin-account-head small { color: var(--text-3); font-size: 12px; word-break: break-all; }
.admin-account-link { display: flex; align-items: center; gap: 10px; padding: 9px 11px; border-radius: 8px; color: var(--text-2); font-size: 13.5px; }
.admin-account-link svg { color: var(--text-3); flex: none; }
.admin-account-link:hover { background: var(--surface-2); color: var(--text); }
.admin-account-out { color: var(--danger); }
.admin-account-out svg { color: var(--danger); }
.admin-account-out:hover { background: var(--danger-soft); color: var(--danger); }

/* ---- settings tabs -------------------------------------------------------
   Hash-driven, so `settings#payments` deep-links straight to a section and the
   redirect('settings#…') calls after a save still land on the right one. */
.set-tabs {
    display: flex; gap: 2px; overflow-x: auto; scrollbar-width: none;
    border-bottom: 1px solid var(--line); margin-bottom: 24px;
}
.set-tabs::-webkit-scrollbar { display: none; }
.set-tab {
    position: relative; display: inline-flex; align-items: center; gap: 8px; flex: none;
    padding: 11px 15px; border: none; background: none; cursor: pointer;
    font: inherit; font-size: 13.5px; font-weight: 600; color: var(--text-2); white-space: nowrap;
    transition: color 0.14s;
}
.set-tab svg { color: var(--text-3); transition: color 0.14s; }
.set-tab:hover { color: var(--text); }
.set-tab:hover svg { color: var(--text-2); }
.set-tab.is-active { color: var(--text); }
.set-tab.is-active svg { color: var(--accent-2); }
.set-tab.is-active::after {
    content: ''; position: absolute; left: 10px; right: 10px; bottom: -1px;
    height: 2px; border-radius: 2px 2px 0 0; background: var(--accent);
}
/* The first panel is marked active server-side, so the page is never blank
   before (or without) JavaScript. */
.set-panel { display: none; max-width: 920px; }
.set-panel.is-active { display: block; }

/* The 920px above is a READING MEASURE, and it belongs to Settings: that page
   is a column of forms, and a text input stretched to 1400px is a worse input,
   not a better one.

   Analytics reuses the same tabs and panels and is not that page. It is six
   income tiles, a thirteen-column table and a row of breakdown cards, and it
   inherited the cap — so on a wide screen the tiles broke to four-plus-two
   orphans, the breakdowns were forced into two columns, and the whole page sat
   in the left two-thirds of the window underneath a tab divider that ran the
   full width. That gap was the bug, not the styling of anything in it.

   Opt-out rather than removal, because Settings still wants the measure. */
.set-panel.is-wide { max-width: none; }

/* A .card carries no margin of its own. For most of this page's life the wide
   panels held ONE card each, so nothing followed a card and the omission never
   showed; the moment money-in, money-out and profit stacked, they met with no
   gap at all. Traffic had the same latent collision between its chart, its live
   panel and the breakdown row below them.
   `> .card + *` rather than a margin on the card itself: the space only exists
   where two blocks actually meet, so no card ever carries a trailing margin
   that pushes the bottom of a panel around. Scoped to .is-wide, which is these
   two panels — the settings tabs nest their cards inside forms and are not
   reached by this. */
.set-panel.is-wide > .card + * { margin-top: 20px; }

/* Income tiles carry real sentences — "Still owed — not counted above" — and
   .kpi-label is nowrap+ellipsis, which is right for the dashboard's tighter
   tiles but here silently ate the half of the label that says what the number
   excludes. Grid rows stretch, so wrapping costs alignment nothing. */
.inc-kpis .kpi-label { white-space: normal; overflow: visible; text-overflow: clip; }

/* The sidebar owns its own breakpoints (see the sidebar block above); what is
   left here is the page header, which has to reflow with the content and not
   with the nav. */
@media (max-width: 860px) {
    .page-head { flex-wrap: wrap; margin-bottom: 20px; }
    .page-title { font-size: 24px; }
}

@media (max-width: 560px) {
    .online-chip { display: none; }
}

/* ==================================================== services & pricing */

.pricing-doc { max-width: 860px; }
.price-grid {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 14px; margin: 26px 0 18px;
}
.price-card {
    display: flex; flex-direction: column; gap: 8px;
    padding: 20px; border: 1px solid var(--line-2); border-radius: var(--radius-lg);
    background: var(--surface);
}
.price-name { font-size: 16px; font-weight: 700; margin: 0; }
.price-amount {
    display: flex; align-items: baseline; gap: 7px; flex-wrap: wrap;
    font-size: 27px; font-weight: 800; letter-spacing: -0.02em; color: var(--text);
}
.price-from { font-size: 12px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-3); }
/* The currency sits next to every figure, not just once at the top — a price
   without a stated currency is the most common website-review failure. */
.price-cur { font-size: 12px; font-weight: 700; color: var(--text-3); letter-spacing: 0.06em; }
.price-desc { margin: 0; font-size: 13.5px; line-height: 1.55; color: var(--text-2); }

.price-caveat {
    padding: 14px 16px; border-left: 3px solid var(--accent); border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
    background: var(--surface); color: var(--text-2); font-size: 14px; line-height: 1.6;
}
.price-steps { padding-left: 20px; line-height: 1.7; }
.price-steps li { margin-bottom: 8px; }
.price-contact { list-style: none; padding: 0; margin: 0; }
.price-contact li { margin-bottom: 6px; }

/* Landing-page link through to pricing. */
.lp-ag-pricing {
    display: inline-flex; align-items: center; gap: 9px; margin-top: 18px;
    padding: 10px 15px; border-radius: 999px;
    border: 1px solid var(--line-2); background: var(--surface);
    color: var(--text-2); font-size: 13.5px; font-weight: 500;
    transition: border-color 0.15s, color 0.15s, background 0.15s;
}
.lp-ag-pricing b { color: var(--text); font-weight: 700; }
.lp-ag-pricing svg { color: var(--accent-2); flex: none; }
.lp-ag-pricing:hover { border-color: var(--accent-line); background: var(--surface-2); color: var(--text); }

.site-foot-pay { opacity: 0.85; }

@media (max-width: 620px) {
    .lp-ag-pricing { width: 100%; justify-content: center; }
}

/* ==================================================== tools: loading screens */

.ls-list { display: flex; flex-direction: column; }
.ls-row {
    display: flex; align-items: center; gap: 14px; padding: 15px 0;
    border-top: 1px solid var(--line);
}
.ls-row:first-child { border-top: none; }
.ls-row-swatch { flex: none; width: 4px; align-self: stretch; border-radius: 3px; min-height: 42px; }
.ls-row-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.ls-row-name { font-weight: 700; font-size: 15px; }
.ls-row-meta { font-size: 12.5px; color: var(--text-3); }
.ls-row-link {
    font-family: var(--font-mono); font-size: 11.5px; color: var(--text-3);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%;
}
.ls-row-actions { flex: none; display: flex; align-items: center; gap: 6px; }

.ls-themes { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 10px; }
.ls-theme { display: block; cursor: pointer; }
.ls-theme input { position: absolute; opacity: 0; pointer-events: none; }
.ls-theme-card {
    display: flex; flex-direction: column; gap: 7px; height: 100%;
    padding: 14px; border: 1px solid var(--line-2); border-radius: var(--radius);
    background: var(--surface); transition: border-color 0.14s, background 0.14s;
}
.ls-theme-card b { font-size: 14px; }
.ls-theme-card small { color: var(--text-3); font-size: 12px; line-height: 1.45; }
.ls-theme:hover .ls-theme-card { border-color: var(--line-3, var(--line-2)); background: var(--surface-2); }
.ls-theme input:checked + .ls-theme-card { border-color: var(--accent); background: var(--accent-soft); }
.ls-theme input:focus-visible + .ls-theme-card { outline: 2px solid var(--accent); outline-offset: 2px; }
/* The swatch previews the theme's actual palette, so the choice is made by
   looking rather than by reading a name. */
.ls-theme-swatch { display: flex; height: 34px; border-radius: 9px; overflow: hidden; border: 1px solid var(--line); }
.ls-theme-swatch i { flex: 1; }
.ls-theme-swatch i:last-child { flex: 0 0 34%; }

.ls-linkcard .code-block { word-break: break-all; }
.ls-editor { display: flex; flex-direction: column; gap: 20px; margin-bottom: 20px; }
.ls-img-current {
    margin-bottom: 12px; padding: 14px; border-radius: var(--radius); border: 1px solid var(--line);
    background: repeating-conic-gradient(var(--surface-2) 0% 25%, var(--surface) 0% 50%) 50% / 18px 18px;
    display: flex; align-items: center; justify-content: center;
}
.ls-img-current img { max-height: 130px; width: auto; }

@media (max-width: 720px) {
    .ls-row { flex-wrap: wrap; }
    .ls-row-actions { width: 100%; }
    .ls-row-actions .btn { flex: 1; justify-content: center; }
}

/* ---- analytics page ---- */
.a-range { display: inline-flex; gap: 4px; padding: 4px; background: var(--surface); border: 1px solid var(--line); border-radius: 12px; margin-bottom: 18px; }
.a-range-pill { padding: 7px 15px; border-radius: 9px; font-size: 13px; font-weight: 600; color: var(--text-2); }
.a-range-pill:hover { color: var(--text); }
.a-range-pill.is-active { background: var(--accent); color: #fff; }
.a-legend { display: inline-flex; align-items: center; gap: 6px; }
.a-legend-dot { display: inline-block; width: 9px; height: 9px; border-radius: 3px; background: var(--accent); }

/* auto-FIT, not auto-fill. auto-fill keeps the empty tracks it creates, so on a
   wide admin panel two cards in a 1660px row were laid into five 300px columns
   and left squashed against the left edge with three empty columns of dead
   space beside them. auto-fit collapses the tracks nothing lands in, and the
   cards share the width. Every other grid on the page (.kpi-grid) already does
   this — this one was the odd one out. */
.analytics-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; }
.analytics-grid .card-head h2 { display: inline-flex; align-items: center; gap: 8px; }
.analytics-grid .card-head h2 svg { color: var(--accent-2); }
.a-path { font-family: var(--font-mono); font-size: 12.5px; }
.a-sub { color: var(--text-3); font-weight: 500; margin-left: 6px; }
.rank-val .a-sub { font-size: 11px; }

.a-meters { display: flex; flex-direction: column; gap: 13px; }
.a-meter-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 6px; }
.a-meter-label { display: inline-flex; align-items: center; gap: 8px; font-size: 13.5px; color: var(--text); }
.a-meter-label svg { color: var(--accent-2); flex: none; }
.a-meter-val { color: var(--text-3); font-size: 12.5px; font-variant-numeric: tabular-nums; }
.a-meter-track { height: 8px; border-radius: 6px; background: var(--surface-2); overflow: hidden; }
.a-meter-fill { display: block; height: 100%; border-radius: 6px; background: linear-gradient(90deg, var(--accent), var(--accent-2)); min-width: 2px; }

.a-cities { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--line); }
.a-city { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; color: var(--text-2); background: var(--surface-2); border: 1px solid var(--line); border-radius: 999px; padding: 4px 10px; }
.a-city svg { color: var(--accent-2); }
.a-city small { color: var(--text-3); font-variant-numeric: tabular-nums; }

/* ==================================================== drive (asset delivery) */

/* --- admin: who-can-see picker --- */
.pick-list { display: flex; flex-direction: column; max-height: 300px; overflow-y: auto; border: 1px solid var(--line-2); border-radius: 11px; background: var(--surface-2); }
.pick-row { display: flex; align-items: center; gap: 11px; padding: 9px 13px; border-bottom: 1px solid var(--line); cursor: pointer; transition: background 0.13s; }
.pick-row:last-child { border-bottom: none; }
.pick-row:hover { background: var(--surface-3); }
/* The picker lives inside a .field, and `.field input` sets width:100% with
   text-input padding. Applied to a checkbox that inflates it to the full row
   width — the glyph centres itself and .pick-main gets squeezed to nothing, so
   the list renders as a column of floating boxes with no names. Same reset
   .check input already carries; deliberately scoped here rather than made a
   general `.field input[type=checkbox]` rule, because that would outrank
   `.switch input` (0,2,1 beats 0,1,1) and un-hide every toggle in the admin. */
.pick-row input[type="checkbox"] { accent-color: var(--accent); width: 16px; height: 16px; flex: none; padding: 0; margin: 0; background: none; border: none; border-radius: 0; box-shadow: none; }
.pick-row input[type="checkbox"]:checked ~ .pick-main strong { color: var(--accent-3); }
.pick-av {
    flex: none; width: 30px; height: 30px; border-radius: 50%;
    display: grid; place-items: center;
    background: var(--surface-3); border: 1px solid var(--line-2);
    font-size: 12px; font-weight: 700; color: var(--text-2); text-transform: uppercase;
}
.pick-main { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
.pick-main strong { font-size: 13.5px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pick-main small { color: var(--text-3); font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* Toolbar above the list: filter, select all, live count. With more than a
   handful of clients, scrolling a 300px box to find one is the actual job. */
.pick-tools { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; flex-wrap: wrap; }
.pick-search { position: relative; flex: 1 1 200px; min-width: 0; }
.pick-search svg { position: absolute; left: 11px; top: 50%; transform: translateY(-50%); color: var(--text-3); pointer-events: none; }
/* Same specificity as `.field input` (0,1,1) but later in the file, so the
   longhand wins over that rule's padding shorthand without !important. */
.pick-search input { width: 100%; padding-left: 34px; }
.pick-count { font-size: 12.5px; color: var(--text-3); font-variant-numeric: tabular-nums; white-space: nowrap; }
.pick-count b { color: var(--accent-3); font-weight: 700; }
.pick-empty { padding: 18px 13px; text-align: center; color: var(--text-3); font-size: 13px; }

/* Collapsed by default — it is a diagnostic, not something to read every day,
   but the failure it explains gives no other clue that it exists. */
.drive-limits { margin-bottom: 16px; border: 1px solid var(--line); border-radius: 11px; background: var(--surface-2); }
.drive-limits > summary { cursor: pointer; padding: 10px 14px; font-size: 12.5px; font-weight: 600; color: var(--text-2); list-style: none; }
.drive-limits > summary::-webkit-details-marker { display: none; }
.drive-limits > summary::before { content: "▸ "; color: var(--text-3); }
.drive-limits[open] > summary::before { content: "▾ "; }
.drive-limits > summary:hover { color: var(--text); }
.drive-limits ul { margin: 0; padding: 0 14px 4px 30px; }
.drive-limits li { font-size: 12.5px; color: var(--text-3); line-height: 1.9; }
.drive-limits li b { color: var(--text); font-variant-numeric: tabular-nums; }
.drive-limits code { font-family: var(--font-mono); font-size: 11.5px; color: var(--accent-3); background: var(--surface-3); padding: 1px 5px; border-radius: 5px; }
.drive-limits .field-note { padding: 0 14px 12px; margin: 0; }
.drive-limits .field-note svg { color: var(--accent-2); vertical-align: -2px; margin-right: 3px; }
.drive-limits .dz-warn { margin: 0 14px 12px; }
/* --- upload progress --- */
.up-progress {
    margin: 0 0 16px; padding: 14px 16px;
    border: 1px solid var(--line-2); border-radius: var(--radius);
    background: var(--surface-2);
}
.up-head { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; }
.up-head strong { font-size: 13.5px; }
.up-pct { font-variant-numeric: tabular-nums; font-weight: 700; color: var(--accent-3); margin-left: auto; }
.up-bar { height: 7px; border-radius: 999px; background: var(--bg-2); overflow: hidden; }
.up-bar-fill {
    display: block; height: 100%; width: 0;
    background: linear-gradient(90deg, var(--accent-2), var(--accent));
    border-radius: inherit; transition: width 0.25s ease;
}
.up-detail { margin: 9px 0 0; font-size: 12.5px; color: var(--text-3); font-variant-numeric: tabular-nums; }
.up-error { margin: 10px 0 0; font-size: 12.5px; color: var(--danger); line-height: 1.5; }
@media (prefers-reduced-motion: reduce) { .up-bar-fill { transition: none; } }

.cap-form { padding: 4px 14px 14px; border-top: 1px solid var(--line); margin-top: 4px; }
.cap-form .field { max-width: 320px; margin-bottom: 10px; }
.cap-form .field-note { padding: 10px 0 0; }
.drive-limits .dz-warn strong { color: var(--danger); }
.ini-diff { display: block; margin: 6px 0; padding: 7px 10px; border-radius: 7px; background: var(--bg-2); font-size: 12px; color: var(--text-2); line-height: 1.8; }
.ini-diff b { color: var(--text); font-variant-numeric: tabular-nums; }
.drive-upload .field { margin-bottom: 14px; }
.drive-upload .dropzone { margin-bottom: 14px; }
.drive-row-actions { display: flex; align-items: center; justify-content: flex-end; gap: 6px; white-space: nowrap; }

/* --- client: the downloads list --- */
.drive-meta { flex: none; text-align: right; color: var(--text-3); font-size: 13px; }
.drive-meta strong { display: block; font-family: var(--font-display); font-size: 26px; font-weight: 800; color: var(--text); line-height: 1.1; }
.drive-toolbar { padding-bottom: 18px; }
.drive-list { display: flex; flex-direction: column; }
.drive-row { display: flex; align-items: center; gap: 14px; padding: 14px 2px; border-bottom: 1px solid var(--line); }
.drive-row:last-child { border-bottom: none; }
.drive-ic { display: inline-flex; align-items: center; justify-content: center; width: 42px; height: 42px; flex: none; border-radius: 11px; background: var(--surface-2); border: 1px solid var(--line-2); color: var(--accent-2); }
.drive-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.drive-name { font-weight: 600; font-size: 14.5px; word-break: break-word; }
.drive-desc { color: var(--text-2); font-size: 12.5px; line-height: 1.5; }
.drive-sub { color: var(--text-3); font-size: 12px; }
.drive-dl { flex: none; }
.drive-none { display: flex; align-items: center; justify-content: center; gap: 9px; color: var(--text-3); font-size: 13.5px; padding: 26px; }
.drive-none svg { color: var(--text-3); }

/* ==================================================== agency landing (v1.17) */

/* Two columns: positioning on the left, the sign-up card on the right.
   Still one screen, no scroll — .shell-landing keeps overflow hidden. */
.lp-ag {
    display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(360px, 0.85fr);
    gap: clamp(28px, 5vw, 72px); align-items: center; min-height: 0;
}
.lp-ag-copy { min-width: 0; }
.lp-ag-h1 {
    font-family: var(--font-display); font-weight: 900;
    font-size: clamp(30px, 4.2vw, 55px); line-height: 1.02; letter-spacing: -0.03em;
    margin: 16px 0 0; text-wrap: balance;
}
.lp-ag-h1 span { color: var(--accent-2); }
.lp-ag-lead { color: var(--text-2); font-size: clamp(14.5px, 1.35vw, 17px); line-height: 1.6; max-width: 56ch; margin: 16px 0 0; }

/* ---- the capability rail ------------------------------------------------
   Built like a server browser: a type tag, the discipline, and what it runs
   on, with a select-state on hover. Chosen because it is the one list layout
   this studio's own audience already reads fluently — and because the tag
   column answers "do you only do games?" before anyone has to ask.

   Everything here is monospace except the discipline name. That split is the
   point: prose is the studio talking, mono is the machine talking. */
.lp-rail {
    list-style: none; margin: 26px 0 0; padding: 0;
    border-top: 1px solid var(--line);
}
.lp-rail-row {
    position: relative;
    display: grid; grid-template-columns: 52px minmax(0, 1fr) auto;
    align-items: baseline; gap: 14px;
    padding: 11px 4px 11px 14px;
    border-bottom: 1px solid var(--line);
    transition: background 0.16s, padding-left 0.16s;
}
/* The select bar. Sits at zero width until the row is hovered, then slides —
   the same feedback as picking a server out of a list. */
.lp-rail-row::before {
    content: ""; position: absolute; left: 0; top: 6px; bottom: 6px;
    width: 2px; border-radius: 2px; background: var(--accent);
    transform: scaleY(0); transform-origin: center;
    transition: transform 0.18s ease;
}
.lp-rail-row:hover { background: rgba(255, 255, 255, 0.022); padding-left: 18px; }
.lp-rail-row:hover::before { transform: scaleY(1); }

.lp-rail-tag {
    font-family: var(--font-mono); font-size: 10px; font-weight: 700;
    letter-spacing: 0.12em; color: var(--accent-2);
    padding-top: 2px;
}
/* A second signal colour, so the rail reads as a status list rather than one
   accent repeated. Amber is already the app's "attention" colour. */
.lp-rail-web .lp-rail-tag { color: var(--warn); }
.lp-rail-sys .lp-rail-tag { color: var(--text-3); }

.lp-rail-name { font-size: 15px; font-weight: 600; color: var(--text); line-height: 1.3; }
.lp-rail-stack {
    font-family: var(--font-mono); font-size: 11.5px; color: var(--text-3);
    text-align: right; white-space: nowrap;
}

@media (max-width: 560px) {
    /* The stack drops below the name rather than being truncated: on a phone
       "what it is built with" is the part a technical visitor came for. */
    .lp-rail-row { grid-template-columns: 46px minmax(0, 1fr); row-gap: 3px; }
    .lp-rail-stack { grid-column: 2; text-align: left; white-space: normal; }
}

.lp-ag-releases { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-top: 24px; padding-top: 20px; border-top: 1px solid var(--line); }
.lp-rel-label { display: inline-flex; align-items: center; gap: 6px; font-size: 10.5px; font-weight: 800; letter-spacing: 0.14em; text-transform: uppercase; color: var(--text-3); margin-right: 4px; }
.lp-rel-label svg { color: var(--accent-2); }
.lp-rel { display: inline-flex; align-items: baseline; gap: 8px; font-size: 12.5px; color: var(--text-2); background: var(--surface); border: 1px solid var(--line); border-radius: 8px; padding: 6px 11px; transition: border-color 0.15s, color 0.15s; }
.lp-rel:hover { border-color: var(--accent); color: var(--text); }
.lp-rel-price { font-weight: 700; color: var(--accent-2); font-variant-numeric: tabular-nums; }

/* --- the sign-up card (the conversion target) --- */
.lp-join {
    position: relative; background: var(--surface); border: 1px solid var(--line-2);
    border-radius: var(--radius-lg); padding: 26px 26px 22px;
    box-shadow: 0 40px 80px -40px rgba(0, 0, 0, 0.95);
    max-height: 100%; overflow-y: auto;
}
.lp-join::before {
    content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
    background: radial-gradient(420px 180px at 50% 0%, rgba(0, 110, 255, 0.16), transparent 70%);
}
.lp-join > * { position: relative; }
.lp-join-head { margin-bottom: 18px; }
.lp-join-h { font-family: var(--font-display); font-weight: 800; font-size: clamp(19px, 1.9vw, 24px); letter-spacing: -0.02em; margin: 0; }
.lp-join-sub { color: var(--text-2); font-size: 13.5px; line-height: 1.5; margin: 7px 0 0; }
.lp-join-form .field { margin-bottom: 12px; }
.lp-join-foot { color: var(--text-3); font-size: 12.5px; text-align: center; margin: 14px 0 0; }
.linkish { background: none; border: none; padding: 0; font: inherit; color: var(--accent-2); cursor: pointer; text-decoration: underline; text-underline-offset: 2px; }
.linkish:hover { color: var(--accent-3); }

/* --- nav sign-up button --- */
.nav-join { flex: none; white-space: nowrap; }
.nav-join svg { flex: none; }

/* --- sidenav sign in / create account tabs --- */
.auth-tabs { display: flex; gap: 4px; background: var(--surface-2); border: 1px solid var(--line); border-radius: 11px; padding: 4px; margin-bottom: 18px; }
.auth-tab { flex: 1; background: none; border: none; border-radius: 8px; color: var(--text-2); font: inherit; font-size: 13px; font-weight: 600; padding: 9px 10px; cursor: pointer; transition: background 0.14s, color 0.14s; }
.auth-tab:hover { color: var(--text); }
.auth-tab.is-active { background: var(--accent); color: #fff; }

/* Base state FIRST — a later non-media rule would otherwise beat the media
   query below (media queries add no specificity, so source order decides). */
.lp-ag-mobile-ctas { display: none; gap: 10px; flex-wrap: wrap; margin-top: 24px; }
.lp-ag-mobile-ctas .btn { flex: 1 1 auto; justify-content: center; }

@media (max-width: 1080px) {
    .lp-ag { grid-template-columns: 1fr; gap: 22px; align-content: center; }
    /* On narrow screens the inline form would force scrolling, so the panel
       becomes the sign-up surface and the hero keeps its buttons instead. */
    .lp-join { display: none; }
    .lp-ag-mobile-ctas { display: flex; }
}

@media (max-width: 720px) {
    .lp-ag-releases { display: none; }
    /* The + button used to shrink to its icon here. It is hidden outright below
       860px now — the whole right-hand side is — so this rule went with it. */
}
@media (max-width: 480px) {
    /* The rail stays on the smallest screens — it is the answer to what the
       studio does, which is the one thing a first-time visitor needs. The last
       two rows go instead, so it is still a list you finish. */
    .lp-rail-row:nth-child(n+4) { display: none; }
}

@media (max-width: 560px) {
    .drive-row { flex-wrap: wrap; gap: 10px 12px; }
    .drive-main { flex-basis: calc(100% - 56px); }
    .drive-dl { width: 100%; justify-content: center; }
    .drive-meta { text-align: left; }
}


/* The old shop-front landing block lived here: an oversized uppercase
   headline and a shelf-first running order. Both were replaced by the
   product-led block further up, and leaving these rules in place meant
   they won on source order and silently reinstated the 900-weight hero. */


/* ======================================================= game types (admin)

   A game type is the look a project wears on a client's dashboard: a background
   image and a tint for the gradient over it. The card below previews exactly
   that treatment, so what an admin sets is what a client sees rather than an
   approximation they have to go and check. */

.gamegrid {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(290px, 1fr));
    gap: 16px; align-items: start;
}
.gamecard {
    display: flex; flex-direction: column; min-width: 0; overflow: hidden;
    background: var(--surface); border: 1px solid var(--line); border-radius: 14px;
}

/* The preview. Same gradient shape as .dh-proj so the two agree. */
.gamecard-art {
    position: relative; isolation: isolate;
    display: flex; align-items: flex-end; gap: 10px;
    min-height: 104px; padding: 13px 15px;
    background-size: cover; background-position: center;
    background-color: var(--surface-2);
}
.gamecard-art::after {
    content: ''; position: absolute; inset: 0; z-index: -1;
    background: linear-gradient(157deg,
        rgba(var(--game-rgb), 0.62) 0%,
        rgba(var(--game-rgb), 0.14) 48%,
        rgba(var(--game-rgb), 0) 72%),
        linear-gradient(to bottom, transparent 35%, rgba(0, 0, 0, 0.5) 100%);
}
.gamecard-name { font-size: 17px; font-weight: 800; letter-spacing: -0.01em; color: #fff;
    text-shadow: 0 1px 12px rgba(0, 0, 0, 0.7); overflow-wrap: anywhere; }
.gamecard-noart { margin-left: auto; font-size: 11px; color: rgba(255, 255, 255, 0.72); flex: none; }

.gamecard-form { display: flex; flex-direction: column; gap: 10px; padding: 14px 15px 0; }
.gamecard-row { display: grid; grid-template-columns: 86px minmax(0, 1fr); gap: 10px; align-items: end; }
.gamecard-form .field { margin: 0; }
.gamecard-form input[type="file"] { font-size: 12px; }

.gamecard-foot {
    display: flex; align-items: center; justify-content: space-between; gap: 10px;
    padding: 12px 15px 14px; margin-top: auto;
}
.gamecard-btns { display: inline-flex; align-items: center; gap: 6px; flex: none; }

/* A colour input styles nothing like a text input, so it is given the height of
   one rather than left as whatever the browser felt like. */
.field-color input[type="color"] {
    width: 100%; height: 36px; padding: 3px; cursor: pointer;
    background: var(--surface); border: 1px solid var(--line); border-radius: 9px;
}
.field-color input[type="color"]::-webkit-color-swatch { border: none; border-radius: 6px; }
.field-color input[type="color"]::-webkit-color-swatch-wrapper { padding: 0; }

/* The picker on a project, in the client profile's side column. */
.projlist-game { flex: none; }
.projlist-game select { font-size: 11.5px; padding: 3px 6px; max-width: 116px; }
.projnew select { font-size: 12.5px; padding: 6px 8px; max-width: 130px; }

/* The artwork picker on a project card. Sits in the card header beside the job
   count, because that header is the only place a project reads as a thing you
   can change rather than a heading over a list. */
.projgame { display: inline-flex; align-items: center; gap: 6px; margin-left: auto; flex: none; }
.projgame-lbl {
    display: inline-flex; align-items: center; gap: 5px;
    font-size: 11px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
    color: var(--text-3); cursor: pointer;
}
.projgame-lbl svg { color: var(--accent-2); }
.projgame select { font-size: 12px; padding: 5px 8px; max-width: 150px; }
@media (max-width: 560px) {
    .projgame { margin-left: 0; width: 100%; }
    .projgame select { flex: 1; max-width: none; }
}

/* ================================================================ invoices

   Two faces of one document. .inv-doc is what a client opens — a paper-shaped
   sheet on a plain background, because the recipient is an accounts inbox that
   has never seen this portal and should not have to learn it. Everything with
   an .inv- prefix and no -doc is the admin side of it. */

.inv-page { max-width: 860px; margin: 0 auto; padding: 34px 20px 64px; }
.inv-doc {
    background: var(--surface); border: 1px solid var(--line); border-radius: 16px;
    padding: 38px 40px 30px; box-shadow: var(--shadow);
}
.inv-doc-head {
    display: flex; align-items: flex-start; justify-content: space-between; gap: 20px;
    padding-bottom: 20px; border-bottom: 2px solid var(--accent);
}
.inv-doc-logo { height: 34px; width: auto; display: block; }
.inv-doc-id { text-align: right; }
.inv-doc-id h1 {
    margin: 0; font-family: var(--font-display); font-size: 27px; font-weight: 800;
    letter-spacing: 0.04em; text-transform: uppercase; line-height: 1;
}
.inv-doc-no { font-size: 13px; color: var(--text-3); font-variant-numeric: tabular-nums; }

/* One banner, saying the single thing that matters right now. */
.inv-banner {
    display: flex; align-items: center; gap: 10px; margin: 22px 0 4px;
    padding: 13px 16px; border-radius: 11px; font-size: 14px; color: var(--text-2);
    background: var(--accent-soft); border: 1px solid var(--accent-line);
}
.inv-banner strong { color: var(--text); font-variant-numeric: tabular-nums; }
.inv-banner svg { flex: none; color: var(--accent-2); }
.inv-banner.is-paid { background: var(--success-soft); border-color: rgba(76, 160, 92, 0.4); }
.inv-banner.is-paid svg { color: var(--success); }
.inv-banner.is-over { background: var(--danger-soft); border-color: rgba(224, 108, 95, 0.45); }
.inv-banner.is-over svg { color: var(--danger); }
.inv-banner.is-void { background: var(--surface-2); border-color: var(--line-2); }
.inv-banner.is-void svg { color: var(--text-3); }

.inv-doc-parties {
    display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 24px; margin: 26px 0 28px;
}
.inv-doc-parties > div { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.inv-doc-parties strong { font-size: 14px; color: var(--text); overflow-wrap: anywhere; }
.inv-doc-parties span { font-size: 13px; color: var(--text-2); overflow-wrap: anywhere; }
.inv-doc-label {
    font-size: 10px; font-weight: 800; letter-spacing: 0.14em; text-transform: uppercase;
    color: var(--text-3); margin-bottom: 3px;
}
.inv-doc-label-2 { margin-top: 12px; }

.inv-doc-items { width: 100%; border-collapse: collapse; margin-bottom: 4px; }
.inv-doc-items th {
    text-align: left; font-size: 10px; font-weight: 800; letter-spacing: 0.12em;
    text-transform: uppercase; color: var(--text-3);
    padding: 10px 10px; background: var(--surface-2);
    border-bottom: 1px solid var(--line-2);
}
.inv-doc-items td {
    padding: 12px 10px; font-size: 13.5px; color: var(--text-2);
    border-bottom: 1px solid var(--line); vertical-align: top;
}
.inv-doc-items td:first-child { color: var(--text); }
.inv-doc-items .t-right { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }

.inv-doc-totals { display: flex; flex-direction: column; gap: 7px; margin: 18px 0 4px; align-items: flex-end; }
.inv-doc-totals > div { display: flex; gap: 40px; font-size: 13.5px; color: var(--text-2); }
.inv-doc-totals > div > span:last-child { min-width: 110px; text-align: right; font-variant-numeric: tabular-nums; }
.inv-doc-total {
    margin-top: 6px; padding-top: 12px; border-top: 1px solid var(--line-2);
    font-size: 17px; font-weight: 800; color: var(--text);
}
.inv-doc-total > span:last-child { color: var(--accent-2); }

.inv-doc-actions { display: flex; gap: 10px; flex-wrap: wrap; margin: 26px 0 6px; }
.inv-doc-block { margin-top: 22px; }
.inv-doc-block p { margin: 4px 0 0; font-size: 13.5px; color: var(--text-2); line-height: 1.65; }
.inv-doc-foot {
    display: flex; flex-direction: column; gap: 4px;
    margin-top: 28px; padding-top: 16px; border-top: 1px solid var(--line);
    font-size: 11.5px; color: var(--text-3);
}

/* Printing the web copy has to give the same document, not a screenshot of an
   app: the chrome goes, the sheet loses its card treatment, and it prints on
   white however the reader's browser is themed. */
@media print {
    .inv-page { padding: 0; max-width: none; }
    .inv-doc { border: 0; border-radius: 0; box-shadow: none; padding: 0; background: #fff; }
    .inv-doc-actions, .toasts, .impersonation-bar, .consent-banner { display: none; }
    .inv-doc, .inv-doc-items td, .inv-doc-parties strong, .inv-doc-parties span { color: #14161a; }
    .inv-doc-items th { background: #f3f2ef; color: #55585f; }
    .inv-banner { border-color: #d8d6d0; background: #f7f6f3; color: #14161a; }
}

/* ---- the admin side ---- */

.inv-late { color: var(--warn); font-weight: 700; }
.inv-rowacts { display: inline-flex; align-items: center; gap: 6px; justify-content: flex-end; }
.inv-head { margin-bottom: 18px; }
.inv-linkcard { margin-bottom: 18px; }
.inv-linkcard input[readonly] { font-family: var(--font-mono); font-size: 12.5px; }
.inv-danger { margin-top: 18px; }

/* The line-item grid. Five columns on one row so a line reads across in the
   same order it prints: what, how many, how much each, how much in total. */
.inv-items { display: flex; flex-direction: column; }
.inv-item {
    display: grid; grid-template-columns: minmax(0, 1fr) 74px 104px 104px 32px;
    gap: 8px; align-items: center; padding: 7px 16px;
}
.inv-item + .inv-item { border-top: 1px solid var(--line); }
.inv-item-head {
    font-size: 10px; font-weight: 800; letter-spacing: 0.12em; text-transform: uppercase;
    color: var(--text-3); padding-top: 10px; padding-bottom: 10px;
    background: var(--surface-2); border-bottom: 1px solid var(--line-2);
}
.inv-item input {
    width: 100%; min-width: 0; font-size: 13px; padding: 7px 9px;
    background: var(--bg-2); border: 1px solid var(--line); border-radius: 8px; color: var(--text);
}
.inv-item input:focus { outline: none; border-color: var(--accent); }
.inv-item input[data-qty], .inv-item input[data-unit] { text-align: right; font-variant-numeric: tabular-nums; }
.inv-item-amt { font-size: 13px; font-weight: 700; color: var(--text-2); font-variant-numeric: tabular-nums; }
.inv-item-x {
    display: inline-flex; align-items: center; justify-content: center;
    width: 26px; height: 26px; border-radius: 7px; border: 1px solid transparent;
    background: none; color: var(--text-3); cursor: pointer;
}
.inv-item-x:hover { color: var(--danger); border-color: var(--line); background: var(--surface-2); }
.inv-item-x:disabled { opacity: 0.3; cursor: default; }
.inv-additem { padding: 12px 16px; border-top: 1px solid var(--line); }

.inv-totals dd { font-variant-numeric: tabular-nums; }
.inv-total-row dt { font-weight: 800; color: var(--text); }
.inv-total-row dd { font-size: 16px; font-weight: 800; color: var(--accent-2); }

@media (max-width: 720px) {
    .inv-doc { padding: 24px 20px 22px; }
    .inv-doc-parties { grid-template-columns: minmax(0, 1fr); gap: 16px; }
    .inv-doc-items th:nth-child(2), .inv-doc-items td:nth-child(2),
    .inv-doc-items th:nth-child(3), .inv-doc-items td:nth-child(3) { display: none; }
    .inv-item { grid-template-columns: minmax(0, 1fr) 60px 84px; row-gap: 6px; }
    .inv-item-amt, .inv-item-x { grid-column: 2 / -1; justify-self: end; }
    .inv-item-head { display: none; }
}

/* ================================================================== income

   The month-by-month grid: a year to a row, a month to a column. Cells are
   shaded against the studio's own best month, so depth means something relative
   to its history rather than to an arbitrary scale.

   Three cell states, and the difference between the last two matters: a figure,
   a dash for "earned nothing", and a dot for "hasn't happened yet". Printing
   £0.00 for a month that is still in the future makes a good year look like a
   collapsing one. */

.inc-cur-head {
    margin: 26px 0 12px; font-size: 12px; font-weight: 800;
    letter-spacing: 0.16em; text-transform: uppercase; color: var(--text-3);
}
/* 20px, matching the gap between the cards below it, so every seam down the
   income panel reads as the same distance. */
.inc-kpis { margin-bottom: 20px; }
.inc-delta { font-weight: 700; font-variant-numeric: tabular-nums; }
.inc-delta.is-up { color: var(--success); }
.inc-delta.is-down { color: var(--warn); }
.inc-owed { color: var(--warn); }

/* Thirteen columns will not fold; on a narrow screen it scrolls sideways rather
   than wrapping into something unreadable. */
.inc-scroll { overflow-x: auto; }
.inc-grid { width: 100%; border-collapse: collapse; min-width: 900px; }
.inc-grid th {
    text-align: right; font-size: 10px; font-weight: 800; letter-spacing: 0.1em;
    text-transform: uppercase; color: var(--text-3);
    padding: 11px 10px; border-bottom: 1px solid var(--line-2); white-space: nowrap;
}
.inc-grid th.is-now { color: var(--accent-2); }
.inc-grid th.inc-year { text-align: left; }
.inc-grid tbody th.inc-year {
    font-family: var(--font-display); font-size: 15px; font-weight: 800;
    letter-spacing: 0; text-transform: none; color: var(--text);
    border-bottom: 1px solid var(--line);
}
.inc-cell {
    padding: 11px 10px; text-align: right; white-space: nowrap;
    font-size: 12.5px; font-variant-numeric: tabular-nums;
    color: var(--text-2); border-bottom: 1px solid var(--line);
}
.inc-cell.inc-total {
    font-weight: 800; color: var(--text);
    border-left: 1px solid var(--line-2); background: var(--surface-2);
}
.inc-grid th.inc-total { border-left: 1px solid var(--line-2); }
/* The month you are in, marked down the column so "so far this month" is
   findable without counting across from January. */
.inc-cell.is-now { box-shadow: inset 0 0 0 1px var(--accent-line); }

.inc-zero { color: var(--text-3); }
.inc-blank { color: var(--line-2); }
.inc-cell.is-future { background: repeating-linear-gradient(135deg,
    transparent 0 6px, rgba(255, 255, 255, 0.02) 6px 12px); }

/* Four bands rather than a continuous ramp: the eye groups steps far better
   than it reads a gradient, and four is enough to say quiet/steady/good/best. */
.inc-b1 { background: rgba(4, 102, 200, 0.10); color: var(--text-2); }
.inc-b2 { background: rgba(4, 102, 200, 0.20); color: var(--text); }
.inc-b3 { background: rgba(4, 102, 200, 0.32); color: var(--text); font-weight: 600; }
.inc-b4 { background: rgba(4, 102, 200, 0.46); color: var(--text); font-weight: 700; }

.inc-legend { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding: 0 20px 16px; margin: 0; }
.inc-key { display: inline-flex; gap: 3px; }
.inc-swatch { width: 16px; height: 12px; border-radius: 3px; display: inline-block; }

/* One inset for the whole card. The head and the legend sit at 20px, so the
   outer columns of the table have to as well — otherwise the card has three
   different left edges (head at 0, cells at 10px, legend at 20px), which is
   what made the block look misaligned even though nothing was overflowing. */
/* The first cell of every row is the year <th>, so th:first-child covers both
   the head and the body; only the trailing Total is a <td>. */
.inc-grid th:first-child { padding-left: 20px; }
.inc-grid th:last-child, .inc-cell:last-child { padding-right: 20px; }

/* ------------------------------------------------- money out, and profit */

/* Spending gets amber rather than the income blue, and profit diverges green
   above the line / red below. Same four steps in each so a cell's depth means
   the same thing on all three tables. */
.exp-b1 { background: rgba(217, 168, 78, 0.10); color: var(--text-2); }
.exp-b2 { background: rgba(217, 168, 78, 0.19); color: var(--text); }
.exp-b3 { background: rgba(217, 168, 78, 0.30); color: var(--text); font-weight: 600; }
.exp-b4 { background: rgba(217, 168, 78, 0.44); color: var(--text); font-weight: 700; }

.pft-u1 { background: rgba(127, 181, 138, 0.10); color: var(--text-2); }
.pft-u2 { background: rgba(127, 181, 138, 0.20); color: var(--text); }
.pft-u3 { background: rgba(127, 181, 138, 0.32); color: var(--text); font-weight: 600; }
.pft-u4 { background: rgba(127, 181, 138, 0.46); color: var(--text); font-weight: 700; }
.pft-d1 { background: rgba(224, 108, 95, 0.12); color: var(--text-2); }
.pft-d2 { background: rgba(224, 108, 95, 0.22); color: var(--text); }
.pft-d3 { background: rgba(224, 108, 95, 0.34); color: var(--text); font-weight: 600; }
.pft-d4 { background: rgba(224, 108, 95, 0.48); color: var(--text); font-weight: 700; }
/* Band 0 is "nothing happened", on every ramp. Declared so the grid class
   always resolves rather than relying on the absence of a rule. */
.inc-b0, .exp-b0, .pft-u0, .pft-d0 { background: transparent; }

.inc-kept { color: var(--success); }
.inc-loss { color: var(--danger); }

/* The whole cell is the target, not the few characters of the amount. The link
   grows back out over the cell's own padding, so the hover state is the cell
   rather than a small rectangle inside it — and no :has() is needed for it. */
.inc-pick { display: block; margin: -11px -10px; padding: 11px 10px; color: inherit; }
.inc-pick:hover { color: inherit; background-color: var(--surface-3); }
.inc-cell.is-picked { box-shadow: inset 0 0 0 2px var(--accent); }

/* ---- the expense editor ----
   Dense admin UI, so it takes the squarer corner rather than the portal's
   16px — see the job dashboard for the same call and the reason. */
.exp-editor {
    --dash-radius: 3px;
    border-top: 1px solid var(--line);
    background: var(--bg-2);
}
/* The whole row is the toggle, so the month and its total stay readable while
   it is shut — which is the point of collapsing it. list-style/marker off
   because the chevron on the left is the affordance. */
.exp-editor-head {
    display: flex; align-items: center; justify-content: space-between; gap: 14px; flex-wrap: wrap;
    padding: 14px 20px; cursor: pointer; list-style: none;
}
.exp-editor-head::-webkit-details-marker { display: none; }
.exp-editor-head:hover .exp-editor-title b { color: var(--accent-2); }
.exp-editor-title { display: inline-flex; align-items: center; gap: 9px; }
.exp-editor-title b { font-family: var(--font-display); font-size: 15px; font-weight: 800; letter-spacing: -0.01em; }
.exp-editor-title .ic { color: var(--text-3); transition: transform 0.15s ease; }
.exp-editor[open] .exp-editor-title .ic { transform: rotate(90deg); }
@media (prefers-reduced-motion: reduce) { .exp-editor-title .ic { transition: none; } }
.exp-editor-body { padding: 0 20px 20px; }
.exp-editor-sum { color: var(--text-3); font-size: 13px; }
.exp-editor-sum b { color: var(--warn); font-variant-numeric: tabular-nums; }

.exp-items { list-style: none; margin: 0 0 14px; padding: 0; display: flex; flex-direction: column; }
/* The action column is a FIXED 34px, not auto. Each row is its own grid, so an
   auto track sizes to that row's own content — the derived fee row ends in a
   28px settings link and the typed rows in a 34px delete button, which pushed
   the amounts 6px out of line with each other. A fixed track makes the amounts
   share a right edge whatever sits beside them. */
.exp-items li {
    display: grid; grid-template-columns: 22px 1fr auto 34px; align-items: center; gap: 11px;
    padding: 9px 0; border-bottom: 1px solid var(--line);
}
.exp-items li > :last-child { justify-self: center; }
.exp-items li:last-child { border-bottom: none; }
.exp-item-cat { display: inline-flex; color: var(--text-3); }
.exp-item-label { min-width: 0; font-size: 13.5px; color: var(--text); overflow: hidden; text-overflow: ellipsis; }
.exp-item-label small { display: block; color: var(--text-3); font-size: 11.5px; }
.exp-item-amt { font-variant-numeric: tabular-nums; font-size: 13.5px; color: var(--text); white-space: nowrap; }
.exp-item-del { margin: 0; }

/* The derived fee row. Tinted and given a settings link rather than a delete
   button, so it reads as "this is worked out for you" instead of "somebody
   forgot to finish this row". */
.exp-item-auto .exp-item-label { color: var(--text-2); }
.exp-item-auto .exp-item-amt { color: var(--warn); }
.exp-item-cog { display: inline-flex; color: var(--text-3); padding: 7px; border-radius: var(--dash-radius); }
.exp-item-cog:hover { color: var(--accent-2); background: var(--surface-2); }

/* ------------------------------------------------------------ updater ---
   One column, centred. The page used to be a two-column admin layout with the
   upload on the left and three side cards beside it; the whole screen does one
   thing, so it now reads as one thing. */
.up-wrap { --dash-radius: 3px; max-width: 680px; margin: 0 auto; display: flex; flex-direction: column; gap: 18px; }
.up-card { display: flex; flex-direction: column; gap: 16px; }
.up-drop { margin: 0; }
.up-note { margin: 0; }
.up-meta .def-list { margin: 0; }

.up-run { display: flex; flex-direction: column; gap: 12px; }
.up-bar {
    height: 8px; border-radius: var(--dash-radius); overflow: hidden;
    background: var(--surface-2); border: 1px solid var(--line);
}
.up-bar-fill {
    display: block; height: 100%; width: 0;
    background: linear-gradient(90deg, var(--accent), var(--accent-2));
    transition: width 0.25s ease;
}
.up-run.is-done .up-bar-fill   { background: var(--success); }
.up-run.is-failed .up-bar-fill { background: var(--danger); }
@media (prefers-reduced-motion: reduce) { .up-bar-fill { transition: none; } }

.up-status { margin: 0; font-size: 14px; color: var(--text-2); font-variant-numeric: tabular-nums; }
.up-run.is-done .up-status   { color: var(--success); font-weight: 600; }
.up-run.is-failed .up-status { color: var(--danger); font-weight: 600; }

/* The four phases. A counter rather than typed-in numbers, so reordering them
   in the markup cannot leave the list numbered wrongly. */
.up-steps { list-style: none; margin: 0; padding: 0; counter-reset: upstep; display: flex; flex-direction: column; gap: 7px; }
.up-steps li {
    counter-increment: upstep;
    display: grid; grid-template-columns: 20px 1fr; align-items: center; gap: 11px;
    font-size: 13.5px; color: var(--text-3);
}
.up-steps li i {
    width: 18px; height: 18px; border-radius: 50%; display: flex; align-items: center; justify-content: center;
    border: 1px solid var(--line-2); background: var(--surface-2);
    font-size: 10px; font-family: var(--font-mono); color: var(--text-3);
}
.up-steps li i::before { content: counter(upstep); }
.up-steps li.is-doing { color: var(--text); }
.up-steps li.is-doing i { border-color: var(--accent); color: var(--accent-2); background: var(--accent-soft); }
.up-steps li.is-done { color: var(--text-2); }
.up-steps li.is-done i { border-color: rgba(127, 181, 138, 0.5); background: var(--success-soft); color: var(--success); }
.up-steps li.is-done i::before { content: "\2713"; }
.up-steps li.is-failed { color: var(--danger); }
.up-steps li.is-failed i { border-color: rgba(224, 108, 95, 0.5); background: var(--danger-soft); color: var(--danger); }
.up-steps li.is-failed i::before { content: "\00d7"; }

/* The running phase pulses, so a long file copy does not look like a hang. */
@media (prefers-reduced-motion: no-preference) {
    .up-steps li.is-doing i { animation: up-pulse 1.4s ease-in-out infinite; }
    @keyframes up-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.45; } }
}

.up-run .update-log { max-height: 240px; overflow: auto; margin: 0; }

/* ------------------------------------------------- the monthly target ---
   Dense admin, so the squarer corner, same as the dashboard and the expense
   editor above it. */
.tgt { --dash-radius: 3px; }
.tgt-head { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 12px; margin-bottom: 14px; }
.tgt-big {
    font-family: var(--font-display); font-size: 34px; font-weight: 800;
    letter-spacing: -0.025em; line-height: 1; color: var(--warn);
    font-variant-numeric: tabular-nums;
}
/* Met is good news and reads green; no target at all is neither, so it stays
   the ordinary ink rather than implying something is wrong. */
.tgt-big.tgt-met  { color: var(--success); }
.tgt-big.tgt-none { color: var(--text); }
.tgt-cap { color: var(--text-3); font-size: 13.5px; }

.tgt-track {
    position: relative; display: flex; height: 10px; overflow: hidden;
    border-radius: var(--dash-radius); background: var(--surface-2);
    border: 1px solid var(--line); margin-bottom: 14px;
}
.tgt-fill { display: block; height: 100%; transition: width 0.3s ease; }
.tgt-fill-earned { background: var(--accent); }
/* Hatched, not solid: this half of the bar is a promise rather than money, and
   it should not read with the same confidence as the part that has landed. */
.tgt-fill-sched {
    background: repeating-linear-gradient(135deg,
        var(--accent-line) 0 5px, rgba(0, 110, 255, 0.10) 5px 10px);
}
@media (prefers-reduced-motion: reduce) { .tgt-fill { transition: none; } }

.tgt-legend { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 8px 22px; }
.tgt-legend li { display: inline-flex; align-items: center; gap: 8px; font-size: 13px; color: var(--text-3); }
.tgt-legend b { color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums; }
.tgt-legend i { width: 10px; height: 10px; border-radius: 2px; flex: none; }
.tgt-legend i.is-earned { background: var(--accent); }
.tgt-legend i.is-sched  { background: repeating-linear-gradient(135deg, var(--accent-line) 0 3px, rgba(0, 110, 255, 0.10) 3px 6px); }
.tgt-legend i.is-gap    { background: var(--surface-2); border: 1px solid var(--line-2); }

.tgt-set { margin-top: 16px; border-top: 1px solid var(--line); padding-top: 12px; }
.tgt-set > summary {
    display: inline-flex; align-items: center; gap: 8px; cursor: pointer; list-style: none;
    font-size: 13px; font-weight: 600; color: var(--text-2);
}
.tgt-set > summary::-webkit-details-marker { display: none; }
.tgt-set > summary:hover { color: var(--text); }
.tgt-set > summary .ic { color: var(--accent-2); }
.tgt-set form { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px 12px; align-items: end; margin-top: 12px; }
.tgt-set .field { margin-bottom: 0; }
.tgt-set .field > span { font-size: 11.5px; }
.tgt-set .field input { border-radius: var(--dash-radius); padding: 9px 11px; font-size: 14px; }
.tgt-set .btn { border-radius: var(--dash-radius); height: 40px; }
.tgt-set .field-note { margin: 12px 0 0; }
@media (max-width: 700px) { .tgt-set form { grid-template-columns: 1fr 1fr; } .tgt-set .btn { grid-column: span 2; } }

/* The two rate boxes in Settings → Payments. */
.fee-fields { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 4px 16px; margin: 12px 0 2px; }

/* Auto-fitting columns rather than fixed widths: this sits inside a card that
   is full width on a desktop and half of a phone, and a five-column form would
   otherwise need a breakpoint per field. */
.exp-add { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 10px 12px; align-items: end; }
.exp-add .field { margin-bottom: 0; }
.exp-add .field > span { font-size: 11.5px; }
.exp-add .field input, .exp-add .field select { border-radius: var(--dash-radius); padding: 9px 11px; font-size: 14px; }
/* 40px to match the text inputs beside it — the row is bottom-aligned, so a
   shorter button reads as a misalignment even though it is not one. */
.exp-add .btn { border-radius: var(--dash-radius); height: 40px; }
.exp-f-label { grid-column: span 2; }
@media (max-width: 700px) {
    .exp-add { grid-template-columns: 1fr 1fr; }
    .exp-f-label { grid-column: span 2; }
    .exp-add .btn { grid-column: span 2; }
}

.exp-needs-update { display: flex; align-items: center; gap: 8px; padding: 0 20px 20px; }
.exp-needs-update svg { color: var(--warn); flex: none; }

/* The outgoing meters read amber for the same reason the grid above does. */
.a-meters-out .a-meter-fill { background: linear-gradient(90deg, #b8862f, var(--warn)); }
.a-meters-out .a-meter-label svg { color: var(--warn); }

@media (max-width: 620px) {
    .inc-grid { min-width: 760px; }
    .inc-grid th, .inc-cell { padding: 9px 7px; font-size: 11.5px; }
}

/* ============================================================ job dashboard
   The admin dashboard is the live work and nothing else.

   THE CORNER. Everything else in the portal is on --radius (16px). These cards
   are on 3px, which is the one deliberate break: a 16px corner on a dense grid
   of six cards reads as six lozenges, and the eye follows the curves instead of
   the column edges. At 3px the cards line up as a grid and the content is what
   you see. If this look is wanted everywhere, --dash-radius is the variable to
   promote — nothing here hard-codes a number.

   THE GROUPING IS THE POINT. These were one flat run of cards ordered by
   urgency, which meant the ordering existed but was invisible: card four looked
   exactly like card one, and "in the order it needs you" was a sentence at the
   top rather than something you could see. They sit in three labelled bands
   now, so whose move it is reads as structure before any word is read, and the
   filter chips became a way to narrow rather than the only way to find out. */

.jobdash-scope { --dash-radius: 3px; }

/* --- the bar over everything: what there is, and how to narrow it --- */
.jobdash-bar {
    display: flex; align-items: center; justify-content: space-between;
    gap: 14px 20px; flex-wrap: wrap;
    padding-bottom: 13px; margin-bottom: 4px;
    border-bottom: 1px solid var(--line);
}
.jobdash-sum { font-size: 14px; color: var(--text-2); }
.jobdash-sum strong { color: var(--text); font-weight: 700; font-variant-numeric: tabular-nums; }
.jobdash-sum-sep { color: var(--text-3); margin: 0 7px; }
.jobdash-scope .chip-filter { border-radius: var(--dash-radius); }

/* --- a band: one state, everything in it --- */
.jobband { margin-top: 26px; }
.jobband[hidden] { display: none; }

/* The label, a rule to the edge, and the count. The rule is doing real work:
   it ties the label to the count so the band reads as one heading rather than
   two floating fragments, and it draws the eye across the full width the cards
   below will occupy. */
.jobband-head {
    display: flex; align-items: center; gap: 14px;
    margin-bottom: 13px;
}
.jobband-label {
    font-size: 11.5px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
    color: var(--text-2); white-space: nowrap;
}
.jobband-rule { flex: 1; height: 1px; background: var(--line); }
.jobband-n {
    font-size: 11.5px; font-weight: 700; color: var(--text-3);
    font-variant-numeric: tabular-nums; white-space: nowrap;
}
/* The band's own colour, carried by the label and picked up by its cards. */
.jobband-you  .jobband-label { color: var(--accent-3); }
.jobband-live .jobband-label { color: var(--success); }
.jobband-them .jobband-label { color: var(--text-3); }

.jobgrid {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(330px, 1fr));
    gap: 12px; align-items: start;
}

/* --- one job --- */
.jobcard {
    display: flex; flex-direction: column; gap: 10px;
    padding: 14px 16px 15px;
    background: var(--surface); border: 1px solid var(--line);
    border-radius: var(--dash-radius);
    /* No shadow. Six of them side by side turned into six floating tiles; flat
       cards on a hairline grid hold the column edges the corner change was for. */
    border-left: 2px solid var(--line-2);
    transition: border-color .14s, background .14s;
}
.jobcard:hover { border-color: var(--line-2); background: var(--surface-2); }
.jobcard-you  { border-left-color: var(--accent); }
.jobcard-live { border-left-color: var(--success); }
.jobcard-them { border-left-color: var(--text-3); }

/* Reference and stage share the top line, which gives the title the full width
   of the card instead of whatever the chip left it. */
.jobcard-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.jobcard-ref {
    font-family: var(--font-mono); font-size: 11px; letter-spacing: .07em;
    color: var(--text-3);
}
.jobcard .chip { border-radius: var(--dash-radius); }

.jobcard-title {
    display: block; font-size: 15.5px; font-weight: 650; line-height: 1.3;
    color: var(--text); text-decoration: none; overflow-wrap: anywhere;
    margin-top: -2px;
}
.jobcard-title:hover { color: var(--accent-3); }

.jobcard-client {
    display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
    font-size: 12.5px; color: var(--text-2); text-decoration: none; width: fit-content;
}
.jobcard-client:hover { color: var(--text); }
.jobcard-project {
    display: inline-flex; align-items: center; gap: 4px;
    padding: 1px 7px; border-radius: var(--dash-radius);
    background: var(--surface-2); font-size: 11.5px; color: var(--text-3);
}
.jobcard-project svg { flex: 0 0 auto; }

/* The pipeline. Segments, not a bar: the stages are discrete and the shape
   should say so. The gap is 2px rather than 3 and the height 6 rather than 4 —
   at the old numbers six segments read as a dashed line rather than one meter,
   which is the opposite of "how far along is this". */
.jobtrack { display: flex; gap: 2px; margin-top: 1px; }
.jobtrack-seg { flex: 1; height: 6px; background: var(--surface-3); }
.jobtrack-seg:first-child { border-radius: var(--dash-radius) 0 0 var(--dash-radius); }
.jobtrack-seg:last-child  { border-radius: 0 var(--dash-radius) var(--dash-radius) 0; }
.jobtrack-seg.is-done { background: var(--accent-line); }
.jobtrack-seg.is-now  { background: var(--accent); }

.jobcard-money {
    display: flex; gap: 6px 14px; flex-wrap: wrap;
    font-size: 12.5px; font-variant-numeric: tabular-nums;
}
.money-due  { color: var(--warn); font-weight: 650; }
.money-paid { color: var(--success); }
.money-held { color: var(--text-3); }
.money-none { color: var(--text-3); font-style: italic; }

.jobcard-foot {
    display: flex; align-items: center; justify-content: space-between;
    gap: 10px; flex-wrap: wrap; margin-top: auto; padding-top: 2px;
}
.jobcard-foot .btn { border-radius: var(--dash-radius); }
.jobcard-wait { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--text-3); }

/* <details> rather than a script: keyboard-reachable, works with CSS off, and
   holds no state of its own. */
.jobmore { font-size: 12.5px; margin-left: auto; }
.jobmore > summary {
    display: inline-flex; align-items: center; gap: 5px;
    cursor: pointer; color: var(--text-3); list-style: none; padding: 3px 2px;
}
.jobmore > summary::-webkit-details-marker { display: none; }
.jobmore > summary:hover { color: var(--text-2); }
.jobmore > summary svg { transition: transform .18s; }
.jobmore[open] > summary svg { transform: rotate(90deg); }
.jobmore[open] { width: 100%; }

.jobmore-list { margin: 9px 0 0; display: grid; gap: 6px; }
.jobmore-list > div { display: grid; grid-template-columns: 88px 1fr; gap: 10px; align-items: baseline; }
.jobmore-list dt { color: var(--text-3); font-size: 11.5px; }
.jobmore-list dd { margin: 0; color: var(--text-2); font-size: 12.5px; }
.jobmore-brief { align-items: start !important; }
.jobmore-brief dd { line-height: 1.55; }
.jobmore-links { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 10px; }
.jobmore-links .btn { border-radius: var(--dash-radius); }

.jobdash-foot { text-align: center; margin: 30px 0 0; padding-top: 18px; border-top: 1px solid var(--line); }

@media (max-width: 700px) {
    .jobgrid { grid-template-columns: 1fr; }
    .jobdash-bar { align-items: flex-start; flex-direction: column; gap: 11px; }
    .jobmore-list > div { grid-template-columns: 1fr; gap: 2px; }
}

/* ==================================================================== mail
   The inbox, the reading pane, the compose form and mailbox setup.

   SQUARE, like the dashboard. Mail is a dense list of rows scanned quickly, and
   a 16px corner on forty of them turns the list into a column of lozenges —
   the same reason the job dashboard moved to --dash-radius. Anything with a
   corner in here takes that variable, so promoting it portal-wide later needs
   no edit in this block.

   TWO PANES, ONE COLUMN ON A PHONE. Below 1000px the list and the reading pane
   stop sitting side by side; the list hides itself whenever a message is open,
   which is what .has-open is for. A 320px-wide reading pane beside a 320px list
   is two unusable things rather than one usable one. */

.mail { --dash-radius: 3px; display: flex; flex-direction: column; gap: 0; }

/* --- the bar over everything --- */
.mail-bar {
    display: flex; align-items: center; justify-content: space-between;
    gap: 12px 18px; flex-wrap: wrap;
    padding-bottom: 13px; margin-bottom: 16px;
    border-bottom: 1px solid var(--line);
}
.mail-filters { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.mail-filters .chip-filter { border-radius: var(--dash-radius); text-decoration: none; }
.mail-sep { width: 1px; height: 18px; background: var(--line); margin: 0 4px; }

.mail-tools { display: flex; align-items: center; gap: 8px; }
.mail-search { display: flex; align-items: center; gap: 4px; }
.mail-search input {
    width: 200px; padding: 6px 10px; font-size: 13px;
    border: 1px solid var(--line-2); border-radius: var(--dash-radius);
    background: var(--surface); color: var(--text);
}
.mail-search input:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
.mail-tools .btn { border-radius: var(--dash-radius); }

/* --- the two panes --- */
.mail-panes {
    display: grid; grid-template-columns: minmax(300px, 380px) 1fr;
    gap: 16px; align-items: start;
}

/* --- the list --- */
.mail-list {
    display: flex; flex-direction: column; gap: 1px;
    background: var(--line); border: 1px solid var(--line);
    border-radius: var(--dash-radius); overflow: hidden;
    /* Its own scroll, so a long list does not push the reading pane down the
       page and leave the message you are reading somewhere above the fold. */
    max-height: calc(100vh - var(--topbar-h) - 150px);
    overflow-y: auto;
}

.mailrow {
    display: flex; flex-direction: column; gap: 3px;
    padding: 11px 13px; background: var(--surface);
    text-decoration: none; color: inherit;
    border-left: 2px solid transparent;
    transition: background .12s, border-color .12s;
}
.mailrow:hover { background: var(--surface-2); }
.mailrow.is-open { background: var(--surface-2); border-left-color: var(--accent); }

/* Unread is carried by weight and a colour shift, not by a dot. The whole row
   changing is readable at a glance down a list of forty; a 6px dot is not. */
.mailrow.is-unread .mailrow-who,
.mailrow.is-unread .mailrow-subject { font-weight: 650; color: var(--text); }
.mailrow.is-unread { border-left-color: var(--accent-line); }

.mailrow-top { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.mailrow-who {
    font-size: 13px; font-weight: 500; color: var(--text-2);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.mailrow-when {
    font-size: 11.5px; color: var(--text-3); white-space: nowrap; flex: 0 0 auto;
    font-variant-numeric: tabular-nums;
}
.mailrow-subject {
    display: flex; align-items: center; gap: 5px;
    font-size: 13.5px; color: var(--text-2); line-height: 1.35;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mailrow-subject svg { flex: 0 0 auto; color: var(--text-3); }
.mailrow-snippet {
    font-size: 12.5px; color: var(--text-3); line-height: 1.4;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mailrow-tags { display: flex; gap: 5px; flex-wrap: wrap; margin-top: 3px; }
.mailtag {
    display: inline-flex; align-items: center; gap: 4px;
    padding: 1px 6px; border-radius: var(--dash-radius);
    background: var(--surface-3); font-size: 11px; color: var(--text-3);
}
.mailtag svg { flex: 0 0 auto; }

.mail-pager {
    display: flex; align-items: center; justify-content: center; gap: 12px;
    padding: 11px; background: var(--surface);
}
.mail-pager .btn { border-radius: var(--dash-radius); }
.mail-pager-n { font-size: 12px; color: var(--text-3); font-variant-numeric: tabular-nums; }

/* --- the reading pane --- */
.mail-read {
    background: var(--surface); border: 1px solid var(--line);
    border-radius: var(--dash-radius); min-height: 340px;
}

.mail-empty { padding: 40px 22px; text-align: center; color: var(--text-2); }
.mail-empty p { margin: 0 0 8px; }
.mail-empty-read { display: flex; flex-direction: column; align-items: center; gap: 12px; padding: 70px 22px; }
.mail-empty-read svg { color: var(--text-3); opacity: .5; }

.mailmsg { display: flex; flex-direction: column; }
.mailmsg-head { padding: 18px 20px 14px; border-bottom: 1px solid var(--line); }
.mailmsg-subject {
    margin: 0 0 12px; font-size: 19px; font-weight: 650; line-height: 1.3;
    overflow-wrap: anywhere;
}
.mailmsg-meta { display: flex; flex-direction: column; gap: 3px; margin-bottom: 12px; }
.mailmsg-meta > div { display: flex; gap: 10px; font-size: 13px; align-items: baseline; }
.mailmsg-meta span:last-child { color: var(--text-2); overflow-wrap: anywhere; }
.mailmsg-label {
    flex: 0 0 62px; font-size: 11px; text-transform: uppercase; letter-spacing: .06em;
    color: var(--text-3); font-weight: 600;
}
.mailmsg-links { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 12px; }
.mailmsg-actions { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.mailmsg-actions .btn { border-radius: var(--dash-radius); }
.mailmsg-links .btn { border-radius: var(--dash-radius); }
.mailmsg-forget { margin-left: auto; }

/* --- attachments --- */
.mailatt {
    display: flex; gap: 7px; flex-wrap: wrap;
    padding: 12px 20px; border-bottom: 1px solid var(--line);
}
.mailatt-item {
    display: inline-flex; align-items: center; gap: 7px;
    padding: 6px 11px; border: 1px solid var(--line-2); border-radius: var(--dash-radius);
    background: var(--surface-2); color: var(--text-2);
    font-size: 12.5px; text-decoration: none; max-width: 100%;
    transition: border-color .12s, color .12s;
}
.mailatt-item:hover { border-color: var(--accent); color: var(--text); }
.mailatt-item svg { flex: 0 0 auto; color: var(--text-3); }
.mailatt-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mailatt-size { color: var(--text-3); flex: 0 0 auto; font-variant-numeric: tabular-nums; }

/* --- the blocked-images notice --- */
.mailimg-notice {
    display: flex; align-items: center; justify-content: space-between;
    gap: 12px; flex-wrap: wrap;
    padding: 9px 20px; background: var(--surface-2);
    border-bottom: 1px solid var(--line);
    font-size: 12.5px; color: var(--text-2);
}
.mailimg-notice > span { display: inline-flex; align-items: center; gap: 7px; }
.mailimg-notice svg { flex: 0 0 auto; color: var(--text-3); }
.mailimg-notice .btn { border-radius: var(--dash-radius); }

/* --- the message body ---
   Sender-supplied markup lands in here. The rules below are containment as
   much as styling: max-width on media and a scroll container on tables stop a
   message with a 4000px image from stretching the whole admin panel sideways. */
.mailbody {
    padding: 18px 20px 24px; font-size: 14.5px; line-height: 1.6; color: var(--text);
    overflow-wrap: anywhere;
}
.mailbody img, .mailbody video { max-width: 100%; height: auto; }
.mailbody table { max-width: 100%; border-collapse: collapse; display: block; overflow-x: auto; }
.mailbody td, .mailbody th { padding: 4px 8px; border: 1px solid var(--line); }
.mailbody a { color: var(--accent-3); }
.mailbody blockquote {
    margin: 10px 0; padding: 2px 0 2px 13px;
    border-left: 2px solid var(--line-2); color: var(--text-2);
}
.mailbody pre { overflow-x: auto; padding: 10px; background: var(--surface-2); border-radius: var(--dash-radius); }
/* An image the sender asked for and the portal held back. Sized so the layout
   does not jump when "Show images" fills them in. */
.mailbody img[data-mail-src] {
    min-width: 40px; min-height: 40px;
    border: 1px dashed var(--line-2); border-radius: var(--dash-radius);
    background: var(--surface-2);
}

.mail-plain { white-space: pre-wrap; font-family: var(--font-ui); }
.mail-plain .mail-quote { color: var(--text-3); }
.mailbody .mail-sig { color: var(--text-3); font-size: 13px; }

/* ------------------------------------------------------------ compose */
.mailcompose .field { margin-bottom: 13px; }
.mailcompose-body { font-family: var(--font-ui); line-height: 1.6; resize: vertical; }
.mailcompose-more { margin: -4px 0 13px; }
.mailcompose-more > summary {
    cursor: pointer; font-size: 12.5px; color: var(--text-3);
    padding: 4px 0; list-style: none; width: fit-content;
}
.mailcompose-more > summary::-webkit-details-marker { display: none; }
.mailcompose-more > summary::before { content: "+ "; }
.mailcompose-more[open] > summary::before { content: "- "; }
.mailcompose-more > summary:hover { color: var(--text-2); }

/* ------------------------------------------------------- mailbox setup */
.mailset { display: flex; flex-direction: column; gap: 16px; }

.mailbox-list { display: flex; flex-direction: column; gap: 1px; background: var(--line); }
.mailbox {
    display: flex; align-items: flex-start; justify-content: space-between;
    gap: 14px; flex-wrap: wrap;
    padding: 13px 15px; background: var(--surface);
}
.mailbox.is-off { opacity: .6; }
.mailbox-main { display: flex; flex-direction: column; gap: 5px; min-width: 0; flex: 1; }
.mailbox-id { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.mailbox-addr { font-weight: 650; font-size: 14.5px; overflow-wrap: anywhere; }
.mailbox-id .chip { border-radius: var(--dash-radius); }
.mailbox-name { margin: 0; font-size: 12.5px; color: var(--text-3); }

.mailbox-caps { display: flex; gap: 14px; flex-wrap: wrap; margin-top: 2px; }
.mailcap {
    display: inline-flex; align-items: center; gap: 6px;
    font-size: 12px; font-family: var(--font-mono);
}
.mailcap svg { flex: 0 0 auto; }
.mailcap.is-on { color: var(--text-2); }
.mailcap.is-on svg { color: var(--success); }
.mailcap.is-off { color: var(--text-3); }

.mailbox-err, .mailbox-ok {
    display: flex; align-items: flex-start; gap: 6px;
    margin: 2px 0 0; font-size: 12.5px; overflow-wrap: anywhere;
}
.mailbox-err { color: var(--danger); }
.mailbox-ok { color: var(--text-3); }
.mailbox-err svg, .mailbox-ok svg { flex: 0 0 auto; margin-top: 2px; }

.mailbox-actions { display: flex; gap: 6px; flex-wrap: wrap; flex: 0 0 auto; }
.mailbox-actions .btn { border-radius: var(--dash-radius); }

.mailform-h {
    margin: 22px 0 4px; font-size: 12px; font-weight: 700;
    text-transform: uppercase; letter-spacing: .09em; color: var(--text-3);
}
.mailform-rule { border: 0; border-top: 1px solid var(--line); margin: 22px 0; }
.mailform-danger {
    display: flex; align-items: center; justify-content: space-between;
    gap: 16px; flex-wrap: wrap;
}
.mailform-danger .field-note { margin: 3px 0 0; }
.mailtest { margin-bottom: 18px; }
.mailtest .field { max-width: 380px; }

/* The server conversation, shown after a test. Monospace because it is a
   protocol transcript and the alignment of the reply codes is the point. */
.mailtrans > summary {
    cursor: pointer; font-size: 12.5px; color: var(--text-3); padding: 6px 0;
    width: fit-content;
}
.mailtrans > summary:hover { color: var(--text-2); }
.mailtrans-body {
    margin: 6px 0 0; padding: 12px 14px; max-height: 320px; overflow: auto;
    background: var(--bg-2); border: 1px solid var(--line); border-radius: var(--dash-radius);
    font-family: var(--font-mono); font-size: 11.5px; line-height: 1.7;
    white-space: pre-wrap; overflow-wrap: anywhere;
}
/* Sent lines, received lines, and the client's own notes. The transcript marks
   direction with ">" and "<"; those are mapped to words in the template rather
   than used as class names, which would need CSS escapes to select and would
   break silently the first time somebody reformatted this file. */
.mailtrans-body .mt-out  { color: var(--accent-3); }
.mailtrans-body .mt-in   { color: var(--text-2); }
.mailtrans-body .mt-note { color: var(--warn); }

/* --- the outbox --- */
.mailq { display: flex; flex-direction: column; gap: 1px; background: var(--line); }
.mailq-row {
    display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
    padding: 10px 13px; background: var(--surface);
}
.mailq-row .chip { border-radius: var(--dash-radius); flex: 0 0 auto; }
.mailq-what { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; }
.mailq-what strong { font-size: 13.5px; font-weight: 600; }
.mailq-what small { font-size: 12px; color: var(--text-3); overflow-wrap: anywhere; }
.mailq-row .btn { border-radius: var(--dash-radius); }

@media (max-width: 1000px) {
    .mail-panes { grid-template-columns: 1fr; }
    /* One column: showing a 320px list above a 320px reading pane is two
       cramped things instead of one usable one, so the list stands down while
       a message is open. */
    .mail-list.has-open { display: none; }
    .mail-list { max-height: none; }
    .mail-search input { width: 140px; }
}

@media (max-width: 620px) {
    .mail-bar { align-items: stretch; flex-direction: column; }
    .mail-tools { justify-content: space-between; }
    .mail-search { flex: 1; }
    .mail-search input { width: 100%; }
    .mailmsg-meta > div { flex-direction: column; gap: 0; }
    .mailmsg-label { flex: none; }
    .mailmsg-forget { margin-left: 0; }
}

/* ============================================================== tips card
   A client's tips, on their profile. Deliberately not .paylist: a tip has no
   due date, no job behind it and no obligation, and giving it the same row
   treatment as an invoice is what made an unfinished one read as a debt.

   Quieter than a payment row, because that is what it is — a gesture worth
   seeing, not money worth chasing. */

.tiplist { display: flex; flex-direction: column; gap: 1px; background: var(--line); }

.tiprow {
    display: flex; align-items: center; gap: 12px;
    padding: 11px 14px; background: var(--surface);
}

/* One in flight is dimmed: it may not exist in a few minutes, and it should
   not draw the eye like something that needs doing. */
.tiprow.is-pending { opacity: .72; }

.tiprow-ic {
    display: inline-flex; align-items: center; justify-content: center;
    flex: 0 0 auto; color: var(--warn);
}
.tiprow.is-pending .tiprow-ic { color: var(--text-3); }

.tiprow-what { display: flex; flex-direction: column; gap: 1px; flex: 1; min-width: 0; }
.tiprow-what strong { font-size: 14.5px; font-weight: 650; font-variant-numeric: tabular-nums; }
.tiprow-what small { font-size: 12px; color: var(--text-3); }

.tiprow .chip { flex: 0 0 auto; white-space: nowrap; }

@media (max-width: 520px) {
    .tiprow { flex-wrap: wrap; }
    .tiprow-what { flex: 1 1 100%; order: 2; }
    .tiprow .chip { order: 3; }
}
