h1:focus {
    outline: none;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid #26b050;
}

.invalid {
    outline: 1px solid #e50000;
}

.validation-message {
    color: #e50000;
}

/* Global (not Razor-scoped) so it hides the #blazor-error-ui div in every top-level layout that
   renders one -- MainLayout.razor and PlatformAdminLayout.razor are alternate root layouts, each
   with its own copy of that div, and a scoped MainLayout.razor.css rule would only ever apply to
   the one it was scoped to. Previously scoped only to MainLayout.razor.css, so PlatformAdminLayout's
   own #blazor-error-ui had no default display:none at all and was visible on every page load. */
#blazor-error-ui {
    color-scheme: light only;
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    box-sizing: border-box;
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

    #blazor-error-ui .dismiss {
        cursor: pointer;
        position: absolute;
        right: 0.75rem;
        top: 0.5rem;
    }

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

    .blazor-error-boundary::after {
        content: "An error has occurred."
    }

.darker-border-checkbox.form-check-input {
    border-color: #929292;
}

.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
    color: var(--bs-secondary-color);
    text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
    text-align: start;
}

/* =====================================================================================
   DESIGN TOKENS -- three brand directions (ADMIN-UX.md Section 12 Open Item 1, now closed)
   x three appearances (light / dark / system). One token set drives every page in this
   app; picking a brand only changes these values, never markup. Applied via [data-brand]
   and [data-theme] on <html> -- see wwwroot/theme.js and the inline bootstrap script in
   App.razor for how the choice is read/persisted (a cookie, so first paint already has
   the right brand -- no flash of the wrong theme).

   "system" appearance = no [data-theme] attribute at all, so the plain
   @media (prefers-color-scheme) block below is what applies; picking Light/Dark explicitly
   sets [data-theme] and wins over the media query by specificity.
   ===================================================================================== */
:root {
    --font-ui: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    --font-mono: ui-monospace, "SF Mono", "Cascadia Code", "Roboto Mono", Menlo, Consolas, "Liberation Mono", monospace;
    color-scheme: light dark;
}

/* ---- Ledger (default): dense, ruled, ink-teal. Finance/GL/audit-flavored screens. ---- */
:root, :root[data-brand="ledger"] {
    --bg-page: #f6f5f2; --bg-surface: #ffffff; --bg-sunken: #efece5;
    --border: #ded9cd; --border-strong: #c9c2b2;
    --text-primary: #1c1a16; --text-secondary: #6b6558; --text-tertiary: #9a927f;
    --accent: #0e6b5c; --accent-hover: #0a5749; --accent-contrast: #ffffff;
    --success: #2f7a4f; --warning: #a9660a; --danger: #a3372c; --focus: #0e6b5c;
    --nav-bg: #1c1a16; --nav-text: #f3f1ea; --nav-text-dim: #a39c8a; --nav-border: #33302a; --nav-active-bg: #262319;
    --selected-bg: color-mix(in srgb, #0e6b5c 10%, var(--bg-surface));
    --radius-sm: 3px; --radius-md: 5px; --row-h: 38px; --tracking-label: 0.07em; --weight-head: 700;
    --name-font: var(--font-mono);
}
@media (prefers-color-scheme: dark) {
    :root, :root[data-brand="ledger"] {
        --bg-page: #0f1115; --bg-surface: #171a20; --bg-sunken: #12151a;
        --border: #262a31; --border-strong: #343941;
        --text-primary: #e8e6df; --text-secondary: #9a9689; --text-tertiary: #6f6b60;
        --accent: #29a389; --accent-hover: #37c2a3; --accent-contrast: #06110d;
        --success: #4caf7d; --warning: #d99a3e; --danger: #d16a5c; --focus: #29a389;
        --nav-bg: #0a0c0f; --nav-text: #e8e6df; --nav-text-dim: #71766f; --nav-border: #1d2128; --nav-active-bg: #14171c;
        --selected-bg: color-mix(in srgb, #29a389 14%, var(--bg-surface));
    }
}
:root[data-theme="dark"], :root[data-theme="dark"][data-brand="ledger"] {
    --bg-page: #0f1115; --bg-surface: #171a20; --bg-sunken: #12151a;
    --border: #262a31; --border-strong: #343941;
    --text-primary: #e8e6df; --text-secondary: #9a9689; --text-tertiary: #6f6b60;
    --accent: #29a389; --accent-hover: #37c2a3; --accent-contrast: #06110d;
    --success: #4caf7d; --warning: #d99a3e; --danger: #d16a5c; --focus: #29a389;
    --nav-bg: #0a0c0f; --nav-text: #e8e6df; --nav-text-dim: #71766f; --nav-border: #1d2128; --nav-active-bg: #14171c;
    --selected-bg: color-mix(in srgb, #29a389 14%, var(--bg-surface));
}
:root[data-theme="light"], :root[data-theme="light"][data-brand="ledger"] {
    --bg-page: #f6f5f2; --bg-surface: #ffffff; --bg-sunken: #efece5;
    --border: #ded9cd; --border-strong: #c9c2b2;
    --text-primary: #1c1a16; --text-secondary: #6b6558; --text-tertiary: #9a927f;
    --accent: #0e6b5c; --accent-hover: #0a5749; --accent-contrast: #ffffff;
    --success: #2f7a4f; --warning: #a9660a; --danger: #a3372c; --focus: #0e6b5c;
    --nav-bg: #1c1a16; --nav-text: #f3f1ea; --nav-text-dim: #a39c8a; --nav-border: #33302a; --nav-active-bg: #262319;
    --selected-bg: color-mix(in srgb, #0e6b5c 10%, var(--bg-surface));
}

/* ---- Storefront: warm stone + indigo, rounder and roomier. HR/store-ops screens. ---- */
:root[data-brand="storefront"] {
    --bg-page: #faf7f2; --bg-surface: #ffffff; --bg-sunken: #f1ece2;
    --border: #e8e0d1; --border-strong: #d8cbb4;
    --text-primary: #2a2420; --text-secondary: #8a8074; --text-tertiary: #b0a696;
    --accent: #4d4a8a; --accent-hover: #3c3a70; --accent-contrast: #ffffff;
    --success: #3f7d4a; --warning: #b8860b; --danger: #b23a3a; --focus: #4d4a8a;
    --nav-bg: #2a2420; --nav-text: #f6f1e8; --nav-text-dim: #b3a99a; --nav-border: #40382f; --nav-active-bg: #372f27;
    --selected-bg: color-mix(in srgb, #4d4a8a 8%, var(--bg-surface));
    --radius-sm: 8px; --radius-md: 12px; --row-h: 50px; --tracking-label: 0.03em; --weight-head: 700;
    --name-font: var(--font-ui);
}
@media (prefers-color-scheme: dark) {
    :root[data-brand="storefront"] {
        --bg-page: #211d19; --bg-surface: #2b2521; --bg-sunken: #1a1714;
        --border: #3c352e; --border-strong: #4d443b;
        --text-primary: #f2ece3; --text-secondary: #b3a99c; --text-tertiary: #7d7367;
        --accent: #8a86c9; --accent-hover: #a29ede; --accent-contrast: #1a1830;
        --success: #6cbf78; --warning: #d6a53f; --danger: #d97a6c; --focus: #8a86c9;
        --nav-bg: #17140f; --nav-text: #f2ece3; --nav-text-dim: #8a8074; --nav-border: #2a251f; --nav-active-bg: #201c17;
        --selected-bg: color-mix(in srgb, #8a86c9 16%, var(--bg-surface));
    }
}
:root[data-theme="dark"][data-brand="storefront"] {
    --bg-page: #211d19; --bg-surface: #2b2521; --bg-sunken: #1a1714;
    --border: #3c352e; --border-strong: #4d443b;
    --text-primary: #f2ece3; --text-secondary: #b3a99c; --text-tertiary: #7d7367;
    --accent: #8a86c9; --accent-hover: #a29ede; --accent-contrast: #1a1830;
    --success: #6cbf78; --warning: #d6a53f; --danger: #d97a6c; --focus: #8a86c9;
    --nav-bg: #17140f; --nav-text: #f2ece3; --nav-text-dim: #8a8074; --nav-border: #2a251f; --nav-active-bg: #201c17;
    --selected-bg: color-mix(in srgb, #8a86c9 16%, var(--bg-surface));
}
:root[data-theme="light"][data-brand="storefront"] {
    --bg-page: #faf7f2; --bg-surface: #ffffff; --bg-sunken: #f1ece2;
    --border: #e8e0d1; --border-strong: #d8cbb4;
    --text-primary: #2a2420; --text-secondary: #8a8074; --text-tertiary: #b0a696;
    --accent: #4d4a8a; --accent-hover: #3c3a70; --accent-contrast: #ffffff;
    --success: #3f7d4a; --warning: #b8860b; --danger: #b23a3a; --focus: #4d4a8a;
    --nav-bg: #2a2420; --nav-text: #f6f1e8; --nav-text-dim: #b3a99a; --nav-border: #40382f; --nav-active-bg: #372f27;
    --selected-bg: color-mix(in srgb, #4d4a8a 8%, var(--bg-surface));
}

/* ---- Control Room: cool slate + signal blue, monospace-forward. Platform/ops screens. ---- */
:root[data-brand="controlroom"] {
    --bg-page: #f4f6f8; --bg-surface: #ffffff; --bg-sunken: #eaeef2;
    --border: #dde3ea; --border-strong: #c5cdd6;
    --text-primary: #131a22; --text-secondary: #66727e; --text-tertiary: #97a1ab;
    --accent: #1478c9; --accent-hover: #0f5fa3; --accent-contrast: #ffffff;
    --success: #128a67; --warning: #c07d1a; --danger: #c0392f; --focus: #1478c9;
    --nav-bg: #0d1520; --nav-text: #e7edf3; --nav-text-dim: #6c7c8c; --nav-border: #1c2733; --nav-active-bg: #131d29;
    --selected-bg: color-mix(in srgb, #1478c9 9%, var(--bg-surface));
    --radius-sm: 4px; --radius-md: 6px; --row-h: 40px; --tracking-label: 0.08em; --weight-head: 700;
    --name-font: var(--font-mono);
}
@media (prefers-color-scheme: dark) {
    :root[data-brand="controlroom"] {
        --bg-page: #10141a; --bg-surface: #171d26; --bg-sunken: #0d1116;
        --border: #262f3a; --border-strong: #37424f;
        --text-primary: #e6ebf1; --text-secondary: #8a97a6; --text-tertiary: #5c6773;
        --accent: #4fa3f0; --accent-hover: #74b8f5; --accent-contrast: #08131f;
        --success: #34c397; --warning: #e3a53f; --danger: #e2685b; --focus: #4fa3f0;
        --nav-bg: #070a0e; --nav-text: #e6ebf1; --nav-text-dim: #5c6773; --nav-border: #161c23; --nav-active-bg: #0e141b;
        --selected-bg: color-mix(in srgb, #4fa3f0 14%, var(--bg-surface));
    }
}
:root[data-theme="dark"][data-brand="controlroom"] {
    --bg-page: #10141a; --bg-surface: #171d26; --bg-sunken: #0d1116;
    --border: #262f3a; --border-strong: #37424f;
    --text-primary: #e6ebf1; --text-secondary: #8a97a6; --text-tertiary: #5c6773;
    --accent: #4fa3f0; --accent-hover: #74b8f5; --accent-contrast: #08131f;
    --success: #34c397; --warning: #e3a53f; --danger: #e2685b; --focus: #4fa3f0;
    --nav-bg: #070a0e; --nav-text: #e6ebf1; --nav-text-dim: #5c6773; --nav-border: #161c23; --nav-active-bg: #0e141b;
    --selected-bg: color-mix(in srgb, #4fa3f0 14%, var(--bg-surface));
}
:root[data-theme="light"][data-brand="controlroom"] {
    --bg-page: #f4f6f8; --bg-surface: #ffffff; --bg-sunken: #eaeef2;
    --border: #dde3ea; --border-strong: #c5cdd6;
    --text-primary: #131a22; --text-secondary: #66727e; --text-tertiary: #97a1ab;
    --accent: #1478c9; --accent-hover: #0f5fa3; --accent-contrast: #ffffff;
    --success: #128a67; --warning: #c07d1a; --danger: #c0392f; --focus: #1478c9;
    --nav-bg: #0d1520; --nav-text: #e7edf3; --nav-text-dim: #6c7c8c; --nav-border: #1c2733; --nav-active-bg: #131d29;
    --selected-bg: color-mix(in srgb, #1478c9 9%, var(--bg-surface));
}

/* ---- Neutral Graphite: true neutral gray, no hue lean, quiet slate accent. The deliberately
   plain fourth option for anyone who finds the other three too colorful -- moderate density
   between Ledger's dense and Storefront's roomy, system font like Storefront (not mono). ---- */
:root[data-brand="neutral"] {
    --bg-page: #f4f4f3; --bg-surface: #ffffff; --bg-sunken: #ececeb;
    --border: #dcdcda; --border-strong: #c4c4c1;
    --text-primary: #1e1e1d; --text-secondary: #6e6e6a; --text-tertiary: #9c9c97;
    --accent: #52525b; --accent-hover: #3f3f46; --accent-contrast: #ffffff;
    --success: #3a7a52; --warning: #a06a1a; --danger: #a3372c; --focus: #52525b;
    --nav-bg: #1e1e1d; --nav-text: #f2f2f0; --nav-text-dim: #a3a39e; --nav-border: #343433; --nav-active-bg: #292927;
    --selected-bg: color-mix(in srgb, #52525b 9%, var(--bg-surface));
    --radius-sm: 6px; --radius-md: 9px; --row-h: 44px; --tracking-label: 0.05em; --weight-head: 700;
    --name-font: var(--font-ui);
}
@media (prefers-color-scheme: dark) {
    :root[data-brand="neutral"] {
        --bg-page: #131313; --bg-surface: #1c1c1b; --bg-sunken: #0f0f0f;
        --border: #2c2c2a; --border-strong: #3d3d3a;
        --text-primary: #ededea; --text-secondary: #a3a39e; --text-tertiary: #737370;
        --accent: #a1a1aa; --accent-hover: #c1c1c9; --accent-contrast: #131313;
        --success: #5fae7a; --warning: #d19a4a; --danger: #d16a5c; --focus: #a1a1aa;
        --nav-bg: #0c0c0c; --nav-text: #ededea; --nav-text-dim: #737370; --nav-border: #201f1e; --nav-active-bg: #161615;
        --selected-bg: color-mix(in srgb, #a1a1aa 14%, var(--bg-surface));
    }
}
:root[data-theme="dark"][data-brand="neutral"] {
    --bg-page: #131313; --bg-surface: #1c1c1b; --bg-sunken: #0f0f0f;
    --border: #2c2c2a; --border-strong: #3d3d3a;
    --text-primary: #ededea; --text-secondary: #a3a39e; --text-tertiary: #737370;
    --accent: #a1a1aa; --accent-hover: #c1c1c9; --accent-contrast: #131313;
    --success: #5fae7a; --warning: #d19a4a; --danger: #d16a5c; --focus: #a1a1aa;
    --nav-bg: #0c0c0c; --nav-text: #ededea; --nav-text-dim: #737370; --nav-border: #201f1e; --nav-active-bg: #161615;
    --selected-bg: color-mix(in srgb, #a1a1aa 14%, var(--bg-surface));
}
:root[data-theme="light"][data-brand="neutral"] {
    --bg-page: #f4f4f3; --bg-surface: #ffffff; --bg-sunken: #ececeb;
    --border: #dcdcda; --border-strong: #c4c4c1;
    --text-primary: #1e1e1d; --text-secondary: #6e6e6a; --text-tertiary: #9c9c97;
    --accent: #52525b; --accent-hover: #3f3f46; --accent-contrast: #ffffff;
    --success: #3a7a52; --warning: #a06a1a; --danger: #a3372c; --focus: #52525b;
    --nav-bg: #1e1e1d; --nav-text: #f2f2f0; --nav-text-dim: #a3a39e; --nav-border: #343433; --nav-active-bg: #292927;
    --selected-bg: color-mix(in srgb, #52525b 9%, var(--bg-surface));
}

/* =====================================================================================
   BASE / TYPOGRAPHY
   ===================================================================================== */
*, *::before, *::after {
    box-sizing: border-box;
}

body {
    margin: 0;
    font-family: var(--font-ui);
    color: var(--text-primary);
    background: var(--bg-page);
}

h1, h2, h3, h4 { letter-spacing: -0.01em; margin: 1.5rem 0 0.6rem; }
h1:first-child, h2:first-child, h3:first-child, h4:first-child { margin-top: 0; }
h2, h3 { font-weight: var(--weight-head, 650); }

p { margin: 0 0 0.75rem; }

/* Most pages in this app still write a bare "<label>Text <input /></label>" with no
   surrounding .field/.field-group wrapper -- this is their default, not just Admins.razor's:
   a label always sits on its own line, its input on the line below it, and consecutive
   labels/buttons get real gaps instead of flowing left-to-right and wrapping wherever
   there's room. .field/.field-group/.login-card override specific pieces of this with
   their own tighter or grid-based spacing; this is only the fallback for everything else. */
label {
    display: block;
    margin: 0 0 0.9rem;
    font-size: 0.85rem;
    color: var(--text-secondary);
}

label input:not([type="checkbox"]):not([type="radio"]), label select, label textarea {
    display: block;
    width: 100%;
    max-width: 420px;
    margin-top: 0.35rem;
}

/* A checkbox/radio has its own fixed native size -- stretching it to width:100% and a new
   block line below the label text (like a text field) reads as broken, not aligned with any
   of its sibling fields. Kept inline, sitting right after the label text on the same line,
   the conventional "[ ] Label text" shape. */
label input[type="checkbox"], label input[type="radio"] {
    width: auto;
    margin-left: 0.4rem;
    vertical-align: middle;
}

/* A row of top-of-page filter controls (Employees' Store/Department/Status, Tenants' status
   filter, ...) reads left-to-right, not stacked one filter per line -- but each individual
   filter keeps the label-above-control shape every other field in this app has (.field), it's
   the filters themselves that sit side by side, not the label next to its own control. .field's
   own margin-bottom/width:100% are overridden below since .list-toolbar controls its own gap
   and each filter needs a bounded, not-full-row width. */
.list-toolbar .field {
    margin-bottom: 0;
    min-width: 160px;
    max-width: 220px;
}

.list-toolbar > button, .list-toolbar > .btn {
    flex-shrink: 0;
}

/* =====================================================================================
   NAV SHELL -- shared by MainLayout.razor (tenant) and PlatformAdminLayout.razor. A fixed
   (not min-) height on the shell, with each of its two children independently scrollable,
   is what keeps the nav in place while only the main content scrolls -- min-height would let
   the whole shell grow past the viewport instead, taking the nav down the page along with it.
   ===================================================================================== */
.admin-shell {
    display: flex;
    height: 100vh;
}

/* TENANT-BRANDING.md Section 3.1 / ADMIN-UX.md Section 3.1: three stacked grid rows -- fixed
   header, scrollable nav, fixed footer -- instead of one single scrolling flex column. Only
   .nav-scroll scrolls now; .admin-nav itself no longer does. */
.admin-nav {
    width: 220px;
    flex-shrink: 0;
    height: 100vh;
    display: grid;
    grid-template-rows: auto 1fr auto;
    background: var(--nav-bg);
    color: var(--nav-text);
}

.nav-header {
    padding: 1rem;
    border-bottom: 1px solid var(--nav-border);
}

.nav-app-name-row {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.3rem;
    margin-bottom: 0.4rem;
}

.nav-app-name-main {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    min-width: 0;
    width: 100%;
}

/* Same accent + bar-glyph family as the favicon (wwwroot/favicon-*.svg) -- badge shape carries
   each brand's own personality (sharp/rounded/pill/circle), color comes straight from --accent
   so this repaints automatically on every brand, no per-brand markup needed. */
.nav-app-mark {
    width: 20px;
    height: 20px;
    border-radius: 6px;
    background: var(--accent);
    color: var(--accent-contrast);
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}
:root[data-brand="ledger"] .nav-app-mark { border-radius: 6px; }
:root[data-brand="storefront"] .nav-app-mark { border-radius: 8px; }
:root[data-brand="controlroom"] .nav-app-mark { border-radius: 0; }
:root[data-brand="neutral"] .nav-app-mark { border-radius: 50%; }

.nav-app-name {
    font-size: 0.66rem;
    text-transform: uppercase;
    letter-spacing: var(--tracking-label, 0.05em);
    color: var(--nav-text-dim);
}

.nav-plan-tier-badge {
    font-size: 0.62rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: var(--tracking-label, 0.05em);
    padding: 0.1rem 0.45rem;
    border-radius: 999px;
    background: var(--nav-border);
    color: var(--nav-text-dim);
    flex-shrink: 0;
    align-self: flex-start;
    margin-left: calc(20px + 0.4rem);
}

.nav-tenant-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.nav-logo,
.nav-logo-fallback {
    width: 28px;
    height: 28px;
    border-radius: var(--radius-sm);
    flex-shrink: 0;
    object-fit: cover;
}

.nav-logo-fallback {
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-weight: 700;
    font-size: 0.8rem;
}

.nav-tenant-name {
    font-weight: 700;
    letter-spacing: -0.01em;
    overflow-wrap: break-word;
}

.nav-store-name {
    margin-top: 0.35rem;
    font-size: 0.72rem;
    color: var(--nav-text-dim);
}

.nav-scroll {
    overflow-y: auto;
    padding: 1rem 0;
}

.admin-nav .nav-section {
    margin-bottom: 1.25rem;
}

.admin-nav .nav-section-title {
    text-transform: uppercase;
    font-size: 0.7rem;
    letter-spacing: var(--tracking-label, 0.05em);
    color: var(--nav-text-dim);
    padding: 0 1rem;
    margin-bottom: 0.25rem;
}

.admin-nav a {
    display: block;
    padding: 0.4rem 1rem;
    color: var(--nav-text-dim);
    text-decoration: none;
    border-left: 3px solid transparent;
    font-size: 0.85rem;
}

.admin-nav a:hover {
    background: var(--nav-active-bg);
    color: var(--nav-text);
}

.admin-nav a.active {
    background: var(--nav-active-bg);
    color: var(--nav-text);
    border-left-color: var(--accent);
    font-weight: 600;
}

.nav-theme {
    padding: 0.75rem 1rem;
    border-top: 1px solid var(--nav-border);
    margin-top: 0.5rem;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.nav-theme label {
    display: block;
    font-size: 0.66rem;
    text-transform: uppercase;
    letter-spacing: var(--tracking-label, 0.05em);
    color: var(--nav-text-dim);
    margin-bottom: 0.2rem;
}

.nav-theme select {
    width: 100%;
    background: var(--nav-active-bg);
    color: var(--nav-text);
    border: 1px solid var(--nav-border);
    border-radius: var(--radius-sm);
    padding: 0.3rem 0.4rem;
    font-size: 0.78rem;
}

/* ADMIN-UX.md Section 3.1/3.3 (revised again): Settings and Sign out sit directly beside the
   user's own name on one single line -- no click-to-reveal step (the two prior iterations of this
   footer, a :hover-only reveal and then a <details> click-to-open menu, both still hid these two
   safety-critical actions), and no text labels now that the icons alone read clearly. */
/* ADR-0090: min-width:0 is required here, not just on .nav-user-name further down. .nav-footer is
   a grid item of .admin-nav's own grid (grid-template-rows: auto 1fr auto) -- a grid item's default
   min-width is `auto`, which means "at least as wide as my content's own min-content size", and a
   nowrap text node's min-content width is its FULL unwrapped width, not zero. That min-content size
   bubbles up through .nav-user-row (a plain flex child, unconstrained itself) regardless of
   .nav-user-name's own min-width:0 -- confirmed directly: a long enough admin/user full name (first
   caught via the Platform Admin console's longer seeded name, "Playwright Platform Admin") pushed
   .nav-user-row wider than .admin-nav's own fixed 220px, bleeding the Sign Out button's clickable
   area rightward into .admin-main's own painted region -- visually invisible (.admin-nav's own box
   still measured exactly 220px) but functionally real: elementFromPoint at the button's own center
   resolved to .admin-main, not the button, blocking every click there. Setting min-width:0 here
   breaks that bubble-up at its actual source, letting .nav-user-name's own ellipsis truncation
   (further down) do its job as originally intended. */
.nav-footer {
    border-top: 1px solid var(--nav-border);
    padding: 0.4rem 0;
    min-width: 0;
}

.nav-user-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.4rem 1rem 0.4rem calc(1rem - 3px);
    border-left: 3px solid transparent;
}

.nav-user-row.active {
    background: var(--nav-active-bg);
    border-left-color: var(--accent);
}

.nav-user-avatar {
    width: 24px;
    height: 24px;
    border-radius: 50%;
    background: var(--nav-active-bg);
    color: var(--nav-text);
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.72rem;
    font-weight: 700;
}

.nav-user-name {
    flex: 1;
    min-width: 0;
    font-size: 0.78rem;
    color: var(--nav-text-dim);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.nav-user-actions {
    display: flex;
    gap: 0.3rem;
    flex-shrink: 0;
}

/* Settings and Sign out, revised again -- direct feedback that a permanent bordered/backgrounded
   button box around each icon read as unnecessary chrome next to the user's own name, and that
   Sign out having a visibly different (bordered) treatment from Settings looked misaligned rather
   than intentionally distinguished. Both are icon-only with no border by default now; an outline
   appears only on hover, so the affordance is still discoverable without permanent chrome. Scoped
   under .nav-user-actions so its specificity (0,2,0) beats ".admin-nav a" (0,1,1), which otherwise
   reflows this link into a block-level nav-list row (display:block, 1rem padding) and effectively
   hides the icon -- confirmed via computed-style diagnosis, not a guess. outline (not border) so
   the hover state adds no layout shift. */
.nav-user-actions .nav-user-action-plain {
    width: 26px;
    height: 26px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    background: transparent;
    border: none;
    border-radius: var(--radius-sm);
    outline: 1px solid transparent;
    outline-offset: -1px;
    color: var(--nav-text-dim);
    text-decoration: none;
    font-family: inherit;
    cursor: pointer;
}

.nav-user-actions .nav-user-action-plain:hover {
    color: var(--nav-text);
    outline-color: var(--nav-border);
    background: var(--nav-active-bg);
}

.nav-user-action-icon {
    display: flex;
    line-height: 1;
}

.nav-user-action-icon svg {
    width: 15px;
    height: 15px;
}

form.nav-logout {
    margin: 0;
    padding: 0;
    border: none;
}

/* ADMIN-UX.md Section 3.2 (revised) / ADR-0090: ThemeSwitcher moved out of the nav footer onto the
   /account/settings page (tenant) and /platform-admin/settings page (platform admin) alike -- its
   own .nav-theme styling assumes the dark nav's color tokens, which read wrong against a light
   page panel, so this overrides just those tokens for that one context. The shared component's
   own markup/classes are untouched. */
.panel .nav-theme {
    border-top: none;
    padding: 0;
    margin-top: 0;
}

.panel .nav-theme label {
    color: var(--text-secondary);
}

.panel .nav-theme select {
    width: auto;
    background: var(--bg-page);
    color: var(--text-primary);
    border: 1px solid var(--border);
}

/* Tenant Settings (Components/Pages/Admin/TenantSettings.razor): intro paragraph + quick-jump TOC
   pinned to the top of .admin-main's own scroll while the settings list scrolls underneath --
   ~70 settings across ~18 sections is long enough that losing the jump nav partway down defeats
   its own purpose. Its live height is measured by scroll.js (ResizeObserver), which is what
   .settings-editor's own sticky "top" offset is pinned to. */
/* A sticky child's top:0 does NOT reach .admin-main's true top edge -- empirically (confirmed via
   getBoundingClientRect after a deep scroll, not a guess) it settles 1.5rem short of it, at
   exactly .admin-main's own top-padding amount, the same systematic offset the original header fix
   diagnosed. top:-1.5rem is what actually pulls a sticky element's locked position up to true y:0.
   Applying that negative offset HERE (to this blank backdrop) rather than to the header below is
   the key move: the backdrop has no content to visibly notice mid-scroll, so the "scrolls up before
   it catches" transition a negative top causes is imperceptible on a flat color fill. That frees the
   header to use a plain top:0, which -- now that this backdrop already occupies and covers the
   padding gap above it -- locks flush directly beneath the backdrop with no pre-lock travel of its
   own, and nothing left uncovered for scrolled content to paint through. margin-bottom cancels the
   backdrop's own height so it adds no extra static-flow space before the header on first render. */
.settings-sticky-backdrop {
    position: sticky;
    top: -1.5rem;
    height: 1.5rem;
    margin-bottom: -1.5rem;
    background: var(--bg-page);
    z-index: 3;
}

.settings-sticky-header {
    position: sticky;
    top: 0;
    z-index: 3;
    background: var(--bg-page);
    padding-top: 0.25rem;
    padding-bottom: 0.75rem;
    margin-bottom: 1rem;
    border-bottom: 1px solid var(--border);
}

.settings-toc {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem 0.6rem;
    padding: 0.75rem;
    margin-top: 0.5rem;
    background: var(--bg-sunken);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
}

/* Buttons, not <a href="#...">: a plain in-page anchor was reported navigating to the app's home
   page instead of scrolling in place (Blazor's enhanced navigation intercepts anchor clicks), so
   these call scroll.js directly via @onclick instead -- same visual treatment as the old links. */
.settings-toc-link {
    appearance: none;
    background: none;
    border: none;
    padding: 0;
    font: inherit;
    font-size: 0.78rem;
    color: var(--accent);
    text-decoration: none;
    cursor: pointer;
}

.settings-toc-link:hover {
    text-decoration: underline;
}

/* The editing panel sits beside the settings list (30-50% of the available width), not below it
   -- .settings-editor is pinned by scroll.js to sit just under .settings-sticky-header so it stays
   reachable regardless of how far down the list the selected setting's row actually is. */
.settings-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(320px, 42%);
    gap: 1.5rem;
    align-items: start;
}

.settings-editor {
    position: sticky;
    /* top is set inline by scroll.js's pinBelowHeader, matching the header's live height */
    max-height: calc(100vh - 2rem);
    overflow-y: auto;
}

.settings-editor-empty {
    color: var(--text-secondary);
}

@media (max-width: 900px) {
    .settings-layout {
        grid-template-columns: 1fr;
    }

    .settings-editor {
        position: static;
        max-height: none;
    }
}

.admin-main {
    flex: 1;
    height: 100vh;
    padding: 1.5rem 2rem;
    overflow-x: auto;
    overflow-y: auto;
}

.access-denied {
    color: var(--danger);
}

/* =====================================================================================
   LOGIN (unchanged layout -- already reviewed and approved -- just re-pointed at tokens
   so it doesn't clash with whichever brand/appearance the user picked last time)
   ===================================================================================== */
.login-shell {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--nav-bg);
}

.login-card {
    background: var(--bg-surface);
    color: var(--text-primary);
    padding: 2rem;
    border-radius: var(--radius-md);
    width: 320px;
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.25);
}

.login-card h1 {
    font-size: 1.25rem;
    margin: 0;
}

.login-card h2 {
    font-size: 0.9rem;
    font-weight: 400;
    color: var(--text-secondary);
    margin: 0 0 1rem;
}

.login-card label {
    display: block;
    font-size: 0.85rem;
    margin: 0.75rem 0 0.25rem;
    color: var(--text-secondary);
}

.login-card input {
    width: 100%;
    padding: 0.5rem;
    box-sizing: border-box;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--bg-page);
    color: var(--text-primary);
}

.login-card button {
    width: 100%;
    margin-top: 1.25rem;
    padding: 0.6rem;
    background: var(--accent);
    color: var(--accent-contrast);
    border: none;
    border-radius: var(--radius-sm);
    cursor: pointer;
    font-weight: 600;
}

.login-card button:hover {
    background: var(--accent-hover);
}

.login-error {
    background: color-mix(in srgb, var(--danger) 14%, var(--bg-surface));
    color: var(--danger);
    padding: 0.5rem 0.75rem;
    border-radius: var(--radius-sm);
    font-size: 0.85rem;
}

.login-success {
    background: color-mix(in srgb, var(--success) 14%, var(--bg-surface));
    color: var(--success);
    padding: 0.5rem 0.75rem;
    border-radius: var(--radius-sm);
    font-size: 0.85rem;
}

.login-signup-link {
    margin: 1rem 0 0;
    font-size: 0.85rem;
    color: var(--text-secondary);
    text-align: center;
}

/* ADR-0079: Signup.razor's own form has far more fields than the 320px .login-card default
   (sign-in/MFA) comfortably fits, plus the Turnstile widget -- a width modifier, not a new
   component, so it inherits every other .login-card rule above unchanged. */
.login-card.login-card-wide {
    width: 420px;
}

.login-card .cf-turnstile {
    margin-top: 1rem;
}

/* =====================================================================================
   TABLES -- existing table.data-table kept as the baseline every page already uses;
   .table-wrap is the new opt-in wrapper (rounded/bordered container, horizontal scroll
   for wide tables) pages can adopt alongside it, as Admins.razor now does.
   ===================================================================================== */
table.data-table {
    width: 100%;
    border-collapse: collapse;
    background: var(--bg-surface);
    font-size: 0.87rem;
}

table.data-table th, table.data-table td {
    text-align: left;
    padding: 0.5rem 0.75rem;
    border-bottom: 1px solid var(--border);
}

table.data-table th {
    background: var(--bg-sunken);
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: var(--tracking-label, 0.05em);
    color: var(--text-secondary);
}

table.data-table tbody tr:hover td {
    background: var(--bg-sunken);
}

/* A selected row needs to read as unambiguously connected to whatever panel appears
   below it -- a left accent bar plus a tinted background, not just a faint highlight. */
tr.selected-row {
    background-color: var(--selected-bg);
}

tr.selected-row td {
    background-color: var(--selected-bg);
    box-shadow: inset 3px 0 0 var(--accent);
}

/* A deactivated/soft-deleted/terminated row needs to stay easy to find (it's still real data,
   e.g. someone auditing who was let go) without competing for attention with the active rows
   around it. Dimming just the text color -- not opacity, which would also fade buttons and chips
   into illegibility -- does that: any element with its own explicit color (a .chip, a .btn) keeps
   full strength since CSS inheritance never overrides an element's own declared property, only
   plain text content actually mutes. Combines cleanly with .selected-row on the same <tr>. */
tr.row-inactive td {
    color: var(--text-tertiary);
}

.table-wrap {
    overflow-x: auto;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
}

/* Plan Features (PlanFeatures.razor): each tier's own module list is a single short column, so the
   baseline table.data-table row padding reads unnecessarily tall next to a richer multi-column
   table like Admins.razor's -- an opt-in compact modifier, adopted alongside .table-wrap the same
   way that wrapper itself is opt-in (see the TABLES banner comment above). The Remove button's own
   .btn-sm padding is tightened further, scoped to inside this table only, so it doesn't dominate a
   row this much shorter than the .btn-sm size was originally tuned for. */
.data-table-compact th, .data-table-compact td {
    padding: 0.3rem 0.75rem;
}

.data-table-compact .btn-sm {
    padding: 0.12rem 0.5rem;
    font-size: 0.72rem;
}

.table-wrap table.data-table {
    border: none;
}

.table-wrap table.data-table tr:last-child td {
    border-bottom: none;
}

.name-cell {
    font-family: var(--name-font);
    font-weight: 600;
}

.email-cell {
    font-family: var(--font-mono);
    font-size: 0.82rem;
    color: var(--text-secondary);
}

/* Row-action buttons previously stretched to the row's own height (36-40px), reading as
   an oversized, ill-fitting control. They now sit at their natural button height with a
   little breathing room above/below instead of filling the row. */
.row-actions {
    display: flex;
    gap: 0.4rem;
    align-items: center;
    justify-content: flex-end;
    padding: 0.35rem 0;
}

/* =====================================================================================
   BUTTONS
   ===================================================================================== */
.btn {
    appearance: none;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    padding: 0.4rem 0.85rem;
    font-size: 0.83rem;
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    white-space: nowrap;
    transition: background-color 120ms ease, border-color 120ms ease, color 120ms ease;
}

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

.btn-secondary { background: var(--bg-surface); color: var(--text-primary); border-color: var(--border-strong); }
.btn-secondary:hover { background: var(--bg-sunken); }

.btn-danger { background: transparent; color: var(--danger); border-color: color-mix(in srgb, var(--danger) 45%, transparent); }
.btn-danger:hover { background: color-mix(in srgb, var(--danger) 12%, transparent); }

.btn-ghost { background: transparent; color: var(--text-secondary); border-color: transparent; padding-left: 0.5rem; padding-right: 0.5rem; }
.btn-ghost:hover { color: var(--text-primary); background: var(--bg-sunken); }

.btn:disabled { opacity: 0.45; cursor: not-allowed; }
.btn-sm { padding: 0.28rem 0.6rem; font-size: 0.76rem; }

/* AsyncButton.razor's busy state -- currentColor so it matches whichever .btn-* variant it's
   rendered inside without needing its own color per variant. */
.btn-spinner {
    display: inline-block;
    width: 0.8em;
    height: 0.8em;
    border: 0.15em solid currentColor;
    border-right-color: transparent;
    border-radius: 50%;
    opacity: 0.7;
    animation: btn-spinner-rotate 0.6s linear infinite;
}

@keyframes btn-spinner-rotate {
    to { transform: rotate(360deg); }
}

[data-brand="storefront"] .btn { border-radius: 999px; padding-left: 1rem; padding-right: 1rem; }
[data-brand="storefront"] .btn-sm { padding-left: 0.75rem; padding-right: 0.75rem; }

/* Plain, un-classed <button> elements (most existing pages) get a sane baseline too, so
   nothing looks broken before a page is retrofitted with the .btn classes above -- including
   breathing room, since two of these sitting side by side with zero CSS between them
   otherwise touch directly. The exclusions are wrapped in :where(...) so this stays a true
   low-priority fallback (specificity of a bare "button") -- chaining :not() directly instead
   accidentally made this MORE specific than later, purpose-built button rules like .pagebtn
   (a plain, un-classed <button class="pagebtn">), silently winning padding/font-size battles
   it was never meant to win and breaking .pagebtn's intended vertical centering. */
button:where(:not(.btn):not(.nav-logout button):not(.tab-strip button)) {
    appearance: none;
    border: 1px solid var(--border-strong);
    background: var(--bg-surface);
    color: var(--text-primary);
    border-radius: var(--radius-sm);
    padding: 0.4rem 0.85rem;
    font-size: 0.83rem;
    font-family: inherit;
    cursor: pointer;
    margin: 0.3rem 0.5rem 0.3rem 0;
}
button:where(:not(.btn):not(.nav-logout button):not(.tab-strip button)):hover {
    background: var(--bg-sunken);
}

/* =====================================================================================
   FORM FIELDS -- generic baseline (existing pages) + the .field/.field-group pair new
   pages (and Admins.razor) use for label-above-input groups.
   ===================================================================================== */
/* An allow-list of input[type="..."] values missed every <input @bind="..." /> that leaves
   type off entirely (defaults to text per the HTML spec, but never matches an attribute
   selector that requires the attribute to be literally present) -- most existing pages write
   it exactly that way, so this is an exclude-list instead: every text-like input unless it's
   one of the few types that shouldn't get this treatment. Wrapped in :where(...) for the same
   reason as the button rule above: 7 chained :not() clauses made this fallback MORE specific
   than .search-box input's own padding (meant to make room for the search icon), so every
   search box's placeholder text silently rendered underneath the icon instead of beside it. */
input:where(:not([type="checkbox"]):not([type="radio"]):not([type="submit"]):not([type="button"]):not([type="file"]):not([type="range"]):not([type="color"]):not([type="hidden"])), select, textarea {
    font-family: inherit;
    font-size: 0.85rem;
    padding: 0.4rem 0.55rem;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--bg-page);
    color: var(--text-primary);
}
input:where(:not([type="checkbox"]):not([type="radio"]):not([type="submit"]):not([type="button"]):not([type="file"]):not([type="range"]):not([type="color"]):not([type="hidden"])):hover, select:hover {
    border-color: var(--border-strong);
}

a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible, [tabindex]:focus-visible {
    outline: 2px solid var(--focus);
    outline-offset: 1px;
}

/* Labels wrap their input (matching every other page's existing markup/Playwright selector
   convention, label:has-text('X') input) rather than sitting beside it -- the label's own
   uppercase/tracked/small-font styling would otherwise inherit straight into the input's
   typed text, so .field input resets every one of those back to normal. */
.field label {
    display: block;
    font-size: 0.72rem;
    font-weight: 600;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: var(--tracking-label, 0.04em);
    margin-bottom: 0.3rem;
}

.field input:not([type="checkbox"]):not([type="radio"]), .field select {
    display: block;
    width: 100%;
    max-width: none;
    margin-top: 0.3rem;
    font-size: 0.85rem;
    font-weight: 400;
    text-transform: none;
    letter-spacing: normal;
    color: var(--text-primary);
}

/* Without the exclusion above, a checkbox inside a .field (e.g. TagPicker's dimension-value
   list on Report Builder) inherited display:block/width:100% here and became a full-width
   block box, pushing its own label text onto the next line -- the same class of bug
   label input[type="checkbox"] below and the input:where(...) reset above already guard
   against, just missed on this one selector. */

/* margin-top matters specifically when a .field-group follows a .table-wrap directly (a
   sub-block's own "add a new row" form right below its table, e.g. Roles.razor's Add
   Permission fields under the Permissions table) -- .field label's uppercase/tracked-letter
   styling is close enough to table.data-table th that with no gap between them, the field-group
   reads as a second, duplicate header row glued to the table instead of a separate form. Where a
   heading/paragraph already precedes it (the more common case) this margin collapses against
   that element's own larger margin-bottom and changes nothing visible. */
.field-group {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 0.75rem;
    margin-top: 0.75rem;
    margin-bottom: 1rem;
}

.field-group.single {
    grid-template-columns: 1fr;
}

/* A checkbox's own label names the checkbox itself, not a caption above a control on the next
   line -- .field label's uppercase/tracked/small-caps styling (built for a text-field caption)
   reads oddly next to a checkbox, and the base label's own checkbox margin (0.4rem, meant for
   "Label text [ ]" with the box last) sits on the wrong side once the box comes first, as it
   does here ("[ ] Enable multi-currency..."). .checkbox-label resets the caption styling and
   uses flex to keep the box and its own text on one aligned baseline regardless of order. */
.field label.checkbox-label {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    text-transform: none;
    letter-spacing: normal;
    font-size: 0.85rem;
    font-weight: 400;
    margin-bottom: 0;
}

.field label.checkbox-label input[type="checkbox"] {
    margin-left: 0;
}

/* =====================================================================================
   PANELS / SUB-BLOCKS -- the "which content came from selecting a row" fix. A managed
   row's detail content now lives inside a visibly bordered card (.panel), and within it,
   each labeled sub-section (Full Name / Password / Two-Factor Authentication, etc.) gets
   a rule above it plus a consistent gap before its own button row -- close enough to read
   as "this button belongs to this section", not stuck directly under the paragraph above it.
   ===================================================================================== */
.panels {
    display: grid;
    grid-template-columns: 1.3fr 1fr;
    gap: 1rem;
    margin-top: 1.5rem;
    align-items: start;
}

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

/* Every standalone .panel (an "Add new X" card with no accompanying Manage panel, e.g.
   PlanFeatures.razor's "Add module to a plan tier" right after its last plan-tier table) needs
   its own top margin -- only the .panels grid wrapper had one, so a lone .panel sat flush
   against whatever content preceded it. Panels inside .panels don't need it again (the grid
   wrapper's own margin-top already separates the pair from the content above as a unit). */
.panel {
    background: var(--bg-surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: 1.25rem;
    margin-top: 1.5rem;
}

.panels > .panel {
    margin-top: 0;
}

.panel-invite {
    border-style: dashed;
}

.panel > h2, .panel > h3:first-child {
    margin-top: 0;
}

.panel .panel-sub {
    font-size: 0.8rem;
    color: var(--text-secondary);
    margin: 0 0 1rem;
}

.sub-block {
    border-top: 1px solid var(--border);
    padding-top: 1rem;
    margin-top: 1rem;
}

.sub-block:first-of-type {
    border-top: none;
    padding-top: 0;
    margin-top: 0;
}

.sub-block h3, .sub-block h4 {
    margin: 0 0 0.4rem;
    font-size: 0.85rem;
}

.sub-block p {
    margin: 0 0 0.75rem;
    font-size: 0.83rem;
    color: var(--text-secondary);
}

/* The named fix: a button row directly under a heading/paragraph used to sit flush
   against it. A small, consistent gap now separates "the section's own controls" from
   its description without pushing them away from the section they belong to. */
.sub-block .btnrow, .panel > div > button, .panel form-actions {
    margin-top: 0.6rem;
}

.btnrow {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin-top: 0.6rem;
}

/* =====================================================================================
   STATUS CHIPS -- encode state as a shape + color, not just a "Yes"/"No" table cell.
   ===================================================================================== */
.chip {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    font-size: 0.68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: 0.15rem 0.5rem;
    border-radius: 999px;
}
.chip::before {
    content: "";
    width: 6px;
    height: 6px;
    border-radius: 50%;
}
.chip-on { color: var(--success); background: color-mix(in srgb, var(--success) 14%, transparent); }
.chip-on::before { background: var(--success); }
.chip-off { color: var(--text-tertiary); background: var(--bg-sunken); }
.chip-off::before { background: var(--text-tertiary); }
.chip-protected { color: var(--accent); background: color-mix(in srgb, var(--accent) 14%, transparent); }
.chip-protected::before { background: var(--accent); }
.chip-warn { color: var(--warning); background: color-mix(in srgb, var(--warning) 14%, transparent); }
.chip-warn::before { background: var(--warning); }
.chip-danger { color: var(--danger); background: color-mix(in srgb, var(--danger) 14%, transparent); }
.chip-danger::before { background: var(--danger); }

/* =====================================================================================
   DASHBOARD -- Company Pulse strip (Home.razor, ADR-0093). The strip reuses .chip's own
   good/watch/act color language (chip-on/chip-warn/chip-off) rather than inventing a second
   status vocabulary; stat tiles are a lighter, numeric-first sibling of .panel.
   ===================================================================================== */
/* ADR-0096: the period selector, above the pulse strip -- deliberately plain (a label + select,
   the same field markup every other page's filter row already uses), since the control itself
   isn't the point; the note beside it is, so a viewer never assumes it reaches further than the
   two activity tiles it actually drives (Sales' selected-period net sales, Payroll's selected-
   period cost). */
.period-selector {
    display: flex;
    align-items: center;
    gap: 0.9rem;
    flex-wrap: wrap;
    margin-top: 0.75rem;
}

.period-selector label {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.8rem;
    color: var(--text-secondary);
    font-weight: 600;
}

.period-selector-note {
    font-size: 0.78rem;
    color: var(--text-tertiary);
}

.pulse-strip {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin: 1rem 0 1.5rem;
}

.pulse-strip .chip {
    padding: 0.35rem 0.75rem;
    font-size: 0.72rem;
}

/* ADR-0094: chips became links (each drills into the page it summarizes) -- .chip's base rule
   never anticipated an <a>, so anchor defaults (underline, link-colored text) need overriding
   back to the chip's own color language. */
a.chip {
    text-decoration: none;
    cursor: pointer;
}
a.chip:hover {
    filter: brightness(0.95);
}

/* ADR-0094: a 30-day sales trend, on the fly from pos_transactions -- plain CSS bars, no charting
   library. Each bar's height is set inline via --h (a percentage of the 30-day max). */
.trend-block {
    margin-top: 1rem;
    padding-top: 0.85rem;
    border-top: 1px solid var(--border);
}

.mini-trend {
    display: flex;
    align-items: flex-end;
    gap: 2px;
    height: 40px;
    margin-top: 0.4rem;
}

.mini-trend span {
    flex: 1;
    background: var(--accent);
    opacity: 0.55;
    height: var(--h);
    min-height: 2px;
    border-radius: 2px 2px 0 0;
}

.mini-trend span:last-child {
    opacity: 1;
}

.stat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 0.75rem;
}

.stat-tile {
    background: var(--bg-sunken);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: 0.85rem 1rem;
}

.stat-tile .stat-label {
    font-size: 0.72rem;
    color: var(--text-tertiary);
    text-transform: uppercase;
    letter-spacing: var(--tracking-label);
    font-weight: 600;
}

.stat-tile .stat-value {
    font-size: 1.35rem;
    font-weight: var(--weight-head);
    margin-top: 0.2rem;
    font-variant-numeric: tabular-nums;
}

.stat-tile .stat-sub {
    font-size: 0.76rem;
    color: var(--text-secondary);
    margin-top: 0.25rem;
}

/* ADR-0099: Round 4 financial charts (Net profit shape, Assets vs. Liabilities+Equity, Income/
   Expense mix). Proportional bars rather than a true pie/donut -- this app supports several tenant
   brand palettes (see the multiple :root blocks above), so every category swatch below is a
   color-mix() shade of the tenant's own --accent rather than a hardcoded hue that could clash with,
   or vanish into, a brand palette this file has never seen. */
.fin-block {
    margin-top: 1.1rem;
    padding-top: 0.9rem;
    border-top: 1px solid var(--border);
}

.fin-block h3 {
    font-size: 0.85rem;
    margin: 0 0 0.3rem;
}

.shape-bar {
    display: flex;
    height: 34px;
    border-radius: var(--radius-md);
    overflow: hidden;
    border: 1px solid var(--border);
    margin-top: 0.5rem;
}

.shape-bar .seg {
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.72rem;
    font-weight: 600;
    color: #ffffff;
    white-space: nowrap;
    overflow: hidden;
}

.shape-bar .seg.cogs { background: var(--text-tertiary); }
.shape-bar .seg.opex { background: var(--warning); }
.shape-bar .seg.profit { background: var(--success); }
.shape-bar .seg.loss { background: var(--danger); }

.shape-legend {
    display: flex;
    gap: 1.1rem;
    margin-top: 0.55rem;
    flex-wrap: wrap;
    font-size: 0.78rem;
    color: var(--text-secondary);
}

.shape-legend span { display: inline-flex; align-items: center; gap: 0.4rem; }
.shape-legend i { width: 10px; height: 10px; border-radius: 3px; display: inline-block; flex: none; }

.category-bars { display: flex; flex-direction: column; gap: 0.65rem; margin-top: 0.6rem; }

.category-bar-row .cb-head {
    display: flex;
    justify-content: space-between;
    gap: 0.6rem;
    font-size: 0.82rem;
}

.category-bar-row .cb-label {
    color: var(--text-secondary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.category-bar-row .cb-value {
    font-variant-numeric: tabular-nums;
    color: var(--text-tertiary);
    white-space: nowrap;
    flex: none;
}

.cb-track {
    background: var(--bg-sunken);
    border-radius: 5px;
    height: 9px;
    overflow: hidden;
    margin-top: 0.25rem;
    display: flex;
}

.cb-track .cb-fill { height: 100%; }

.fin-split {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 1.4rem;
}

/* ADR-0103: the simple colored number-box presentation for "This Month vs. Last Month," reversing
   ADR-0102's neutral rank-bars treatment. */
.compare-strip {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 0.75rem;
}

.compare-tile {
    background: var(--bg-sunken);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: 0.75rem 0.9rem;
}

.compare-tile .stat-label {
    font-size: 0.72rem;
    color: var(--text-tertiary);
    text-transform: uppercase;
    letter-spacing: var(--tracking-label);
    font-weight: 600;
}

.stat-delta {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    font-size: 0.95rem;
    font-weight: 700;
    margin-top: 0.3rem;
    font-variant-numeric: tabular-nums;
}

.stat-delta.up { color: var(--success); }
.stat-delta.down { color: var(--danger); }
.stat-delta.flat { color: var(--text-tertiary); }

/* ADR-0100 follow-up: ports the Control Tower mockup's own labeled-SVG-bar and donut chart
   components into the real dashboard (Sales' 30-day trend and store ranking, Net profit/Cash flow
   trends, and a COGS/Opex/Profit pie), replacing the plainer .mini-trend/.shape-bar approximations
   for these specific charts. Direct labels stay selective (first/current point only, plus a native
   <title> tooltip per bar/segment) -- the same "never a number on every point" restraint the mockup
   itself uses, not a label crammed onto all 30 daily bars. */
.trend-caption {
    font-size: 0.74rem;
    color: var(--text-tertiary);
    margin-top: 0.4rem;
    font-variant-numeric: tabular-nums;
}

.chart-bars { margin-top: 0.3rem; }
.bars-svg { width: 100%; height: auto; display: block; overflow: visible; }
.bars-svg .bar { fill: var(--border-strong); }
.bars-svg .bar.now { fill: var(--accent); }
.bars-svg .bar.pos { fill: var(--success); }
.bars-svg .bar.neg { fill: var(--danger); }

/* The "current period" value callout lives OUTSIDE the svg, as plain HTML, not as an in-chart <text>
   element -- SVG text sizing is resolved in the viewBox's own user-unit space, so a small
   `font-size` on an SVG <text> gets rescaled right along with the chart's own width:100% stretch
   (an 8.5px label in a viewBox that renders ~4x larger than its own units becomes a ~34px label on
   screen). Plain HTML sits outside that coordinate system entirely and just uses real CSS pixels. */
.chart-callout {
    font-size: 0.82rem;
    font-weight: 600;
    color: var(--text-secondary);
    margin-bottom: 0.3rem;
}
.chart-callout.pos { color: var(--success); }
.chart-callout.neg { color: var(--danger); }

.chart-axis {
    display: flex;
    margin-top: 0.3rem;
    font-size: 0.64rem;
    color: var(--text-tertiary);
}
.chart-axis span { flex: 1; text-align: center; }

/* ---------- Ranked horizontal bars (Sales by store) -- mirrors the mockup's own .rank-bars ---------- */
.rank-bars { display: flex; flex-direction: column; gap: 0.55rem; margin-top: 0.4rem; }
.rank-row { display: grid; grid-template-columns: minmax(70px, 110px) 1fr minmax(70px, auto); align-items: center; gap: 0.7rem; }
.rank-row .rank-label { font-size: 0.85rem; color: var(--text-secondary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rank-row .rank-track { background: var(--bg-sunken); border-radius: 6px; height: 14px; overflow: hidden; }
.rank-row .rank-fill { background: var(--accent); height: 100%; border-radius: 6px; }
.rank-row .rank-value { font-size: 0.8rem; text-align: right; color: var(--text-secondary); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* ---------- Donut / pie charts (Where a shilling of revenue goes) ---------- */
.donut-wrap { display: flex; align-items: center; gap: 1.1rem; flex-wrap: wrap; }
.donut-svg { width: 108px; height: 108px; flex: none; }
.donut-svg .seg { cursor: default; }
.donut-center-label { font-size: 12px; fill: var(--text-primary); font-weight: 700; font-variant-numeric: tabular-nums; }
.donut-center-sub { font-size: 6.5px; fill: var(--text-tertiary); text-transform: uppercase; letter-spacing: 0.04em; }
.chart-legend { display: flex; flex-direction: column; gap: 0.4rem; font-size: 0.82rem; }
.chart-legend .lg-row { display: flex; align-items: center; gap: 0.5rem; color: var(--text-secondary); }
.chart-legend .lg-swatch { width: 10px; height: 10px; border-radius: 3px; flex: none; }
.chart-legend .lg-val { margin-left: auto; font-variant-numeric: tabular-nums; font-size: 0.78rem; color: var(--text-primary); padding-left: 0.8rem; }

/* =====================================================================================
   SEARCH + PAGINATION -- new, opt-in per list page (Admins.razor is the first to use it).
   ===================================================================================== */
.list-toolbar {
    display: flex;
    gap: 0.75rem;
    align-items: flex-end;
    flex-wrap: wrap;
    margin-bottom: 0.75rem;
}

.search-box {
    position: relative;
    flex: 1;
    min-width: 200px;
    max-width: 320px;
}

.search-box svg {
    position: absolute;
    left: 0.6rem;
    top: 50%;
    transform: translateY(-50%);
    width: 14px;
    height: 14px;
    color: var(--text-tertiary);
    pointer-events: none;
}

.search-box input {
    width: 100%;
    padding: 0.4rem 0.6rem 0.4rem 1.75rem;
}

.count-pill {
    font-size: 0.72rem;
    color: var(--text-secondary);
    background: var(--bg-sunken);
    border: 1px solid var(--border);
    padding: 0.15rem 0.55rem;
    border-radius: 999px;
    font-variant-numeric: tabular-nums;
}

/* ADR-0106 follow-up: flags a POS sale with no valid fiscal receipt on file (fiscal_status
   'not_configured' or 'failed') -- fiscal reporting is mandatory for eligible Tanzania businesses,
   so this must read as a compliance gap, not just an informational status label. */
.count-pill-warn {
    font-size: 0.72rem;
    color: var(--danger);
    background: color-mix(in srgb, var(--danger) 12%, transparent);
    border: 1px solid var(--danger);
    padding: 0.15rem 0.55rem;
    border-radius: 999px;
    font-variant-numeric: tabular-nums;
}

.fiscal-gap {
    color: var(--danger);
    font-weight: 600;
}

.pagination {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    flex-wrap: wrap;
    margin-top: 0.75rem;
}

.pagination .range {
    font-size: 0.78rem;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
}

/* ADR-0082: PaginationFooter.razor's page-size control. white-space:nowrap keeps "Show <select>
   per page" on one line -- flex-wrap:nowrap on the container only stops the SELECT ELEMENT from
   dropping to its own row, the "per page" text node was still free to wrap on its own within the
   remaining space, which is what forced the two-line layout. The select's own padding is trimmed
   to give that text the room it needs. */
.page-size-select {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    margin: 0;
    font-size: 0.78rem;
    color: var(--text-secondary);
    white-space: nowrap;
    flex-shrink: 0;
}

.page-size-select select {
    /* Overrides "label select { display:block; width:100%; margin-top:0.35rem }" (the standard
       label-above/input-below shape every other form field in this app uses) -- that margin-top
       was the actual cause of this control visibly sitting lower than the range text/page buttons
       on either side of it: this select sits inline beside "Show"/"per page" text, not below it. */
    display: inline-block;
    width: auto;
    margin-top: 0;
    font-size: 0.78rem;
    padding: 0.15rem 0.25rem;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--bg-surface);
    color: var(--text-primary);
}

.pagebtns {
    display: flex;
    gap: 0.25rem;
}

.pagebtn {
    appearance: none;
    border: 1px solid var(--border);
    background: var(--bg-surface);
    color: var(--text-primary);
    min-width: 28px;
    height: 28px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-sm);
    font-size: 0.78rem;
    cursor: pointer;
    font-variant-numeric: tabular-nums;
}

.pagebtn[aria-current="true"] {
    background: var(--accent);
    color: var(--accent-contrast);
    border-color: var(--accent);
    font-weight: 700;
}

.pagebtn:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

/* Non-clickable gap marker in a windowed page-button list (GL Journal Entries, UX-003 Section 13.1)
   -- sized to match .pagebtn so the row doesn't jump height when an ellipsis appears. */
.pagebtn-ellipsis {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 28px;
    height: 28px;
    color: var(--text-tertiary);
    font-size: 0.78rem;
}

/* Right-aligned, equal-width digits for any monetary figure -- table cells and <input> alike.
   tabular-nums keeps every digit glyph the same width without switching the whole page to a
   monospace font, so a column of amounts stays visually aligned on the decimal point. */
.amount {
    text-align: right;
    font-variant-numeric: tabular-nums;
    font-family: var(--font-mono);
}

/* table.data-table th, table.data-table td's own text-align: left (specificity 0,1,2) otherwise
   silently wins over .amount alone (0,1,0) regardless of source order -- a real bug, not just a
   missing rule: every .amount table cell rendered left-aligned despite this class existing. */
table.data-table td.amount, table.data-table th.amount {
    text-align: right;
}

/* Generic searchable multi-select with no JS (TagPicker.razor, UX-003 Section 12): selected
   items render as removable chips above a text-filtered checkbox list -- the same role a native
   <select multiple> plays, but actually searchable and not the notoriously unfriendly
   ctrl+click UI a multi-select forces on every browser. */
.tag-picker-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.3rem;
    margin-bottom: 0.4rem;
}

.tag-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    background: var(--bg-sunken);
    border: 1px solid var(--border);
    border-radius: 999px;
    padding: 0.1rem 0.3rem 0.1rem 0.6rem;
    font-size: 0.78rem;
    color: var(--text-primary);
}

.tag-chip-remove {
    appearance: none;
    border: none;
    background: none;
    color: var(--text-tertiary);
    cursor: pointer;
    font-size: 0.95rem;
    line-height: 1;
    padding: 0.1rem 0.25rem;
}

.tag-chip-remove:hover {
    color: var(--danger);
}

/* A journal entry line as one bordered card (JournalEntries.razor's posting form) rather than a
   <table> row -- a <tr> can only lay cells out side by side, never stack content beneath them
   within the same row, so a line's own Dimensions picker couldn't read as "part of this line,
   just below it" while it lived in a second, structurally separate <tr>. grid-template-columns is
   set inline (JournalEntries.razor's own LineFieldsGridStyle), shared between the header and every
   line so their columns always align, and changes shape when multi-currency adds/removes a column. */
/* Direct feedback: the Debit/Credit column headers didn't line up with their own input boxes
   below. Root cause -- .je-line has a real 1px border that .je-lines-header didn't, so the two
   grids' content boxes started (and totalled) 1-2px apart even with identical padding/gap/
   grid-template-columns; a transparent border of the same width gives the header the exact same
   box model as a line card, so their column tracks line up pixel-for-pixel. */
.je-lines-header {
    display: grid;
    gap: 0.5rem;
    border: 1px solid transparent;
    padding: 0 0.6rem 0.4rem;
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: var(--tracking-label, 0.05em);
    color: var(--text-secondary);
}

.je-line {
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: 0.6rem;
    margin-bottom: 0.5rem;
}

.je-line-fields {
    display: grid;
    gap: 0.5rem;
    align-items: center;
}

.je-line-fields input, .je-line-fields select {
    width: 100%;
}

.tag-picker-options {
    max-height: 8em;
    overflow-y: auto;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: 0.3rem 0.5rem;
    margin-top: 0.3rem;
}

/* Collapsed state: shown instead of the search box + checklist when nothing is selected and the
   picker hasn't been expanded yet -- keeps a TagPicker that appears once per journal entry line
   from permanently dumping a full checklist onto the page. */
.tag-picker-add-link {
    appearance: none;
    border: none;
    background: none;
    color: var(--accent);
    font-size: 0.8rem;
    font-weight: 600;
    cursor: pointer;
    padding: 0.15rem 0;
}

.tag-picker-add-link:hover {
    text-decoration: underline;
}

/* Each option is itself a <label> wrapping a checkbox -- inside a .field, .field label's own
   uppercase/tracked-letter/small-font styling would otherwise inherit straight in, the same
   reset reasoning .field input/select already need for the same structural reason. */
.tag-picker-option {
    display: block;
    font-size: 0.82rem;
    font-weight: 400;
    text-transform: none;
    letter-spacing: normal;
    color: var(--text-primary);
    padding: 0.1rem 0;
}

/* SettingValueInput.razor's checkbox-list rendering for a comma-separated closed-vocabulary
   tenant setting (e.g. severance-eligible termination reasons) -- same bordered-box/option
   styling as .tag-picker-options/.tag-picker-option above, since it plays the identical role. */
.setting-multiselect {
    max-height: 8em;
    overflow-y: auto;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: 0.3rem 0.5rem;
}

.setting-multiselect-option {
    display: block;
    font-size: 0.82rem;
    font-weight: 400;
    text-transform: none;
    letter-spacing: normal;
    color: var(--text-primary);
    padding: 0.1rem 0;
}

/* =====================================================================================
   MISC EXISTING UTILITIES -- retokenized, unchanged in shape.
   ===================================================================================== */
.tab-strip {
    display: flex;
    gap: 0.25rem;
    border-bottom: 1px solid var(--border);
    margin-bottom: 1rem;
}

.tab-strip button {
    padding: 0.5rem 1rem;
    border: none;
    background: transparent;
    color: var(--text-secondary);
    cursor: pointer;
    border-bottom: 2px solid transparent;
}

.tab-strip button.active {
    border-bottom-color: var(--accent);
    color: var(--text-primary);
    font-weight: 600;
}

.form-error {
    color: var(--danger);
    font-size: 0.85rem;
}

.form-warning {
    color: var(--warning);
    font-size: 0.85rem;
}

.form-success {
    color: var(--success);
    font-size: 0.85rem;
}

/* ADMIN-UX.md Open Item 4: a live, non-blocking notice for a SignalR push received while the
   underlying list itself hasn't been reloaded yet -- calm, not alarming (ADR-0010's own posture on
   connection-related UI), so it borrows the same --warning color form-warning already uses rather
   than --danger. */
.panel-notice {
    border: 1px solid var(--warning);
    border-radius: var(--radius, 6px);
    padding: 0.6rem 0.9rem;
    margin: 0.75rem 0;
    background: color-mix(in srgb, var(--warning) 10%, transparent);
}

.panel-notice p {
    margin: 0 0 0.4rem 0;
}

.panel-notice ul {
    margin: 0;
    padding-left: 1.25rem;
    font-size: 0.9rem;
}

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

/* A journal entry line's dimension tags, shown as their own row directly under the line they
   belong to (JournalEntries.razor entry detail) rather than a fifth table column -- muted/italic
   so it reads as supplementary context, not another data column competing for attention. */
.detail-dimension-row td {
    color: var(--text-tertiary);
    font-size: 0.8rem;
    font-style: italic;
    padding-top: 0.15rem;
    padding-bottom: 0.5rem;
}

/* TenantBranding.razor's live preview -- mirrors the nav's own top region (Section 3.1) at a
   smaller scale, so a tenant sees the real result before leaving the settings page. */
.branding-preview {
    background: var(--bg-page);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: 1rem;
}

.branding-preview-app-name {
    color: var(--text-tertiary);
    font-size: 0.75rem;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    margin-bottom: 0.5rem;
}

.branding-preview-tenant-row {
    display: flex;
    align-items: center;
    gap: 0.6rem;
}

.branding-preview-logo,
.branding-preview-logo-fallback {
    width: 32px;
    height: 32px;
    border-radius: var(--radius-sm);
    flex-shrink: 0;
    object-fit: cover;
}

.branding-preview-logo-fallback {
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-weight: 700;
}

.branding-preview-wordmark {
    font-size: 1.1rem;
    font-weight: 700;
}
