/* AL Dev Toolbox — base styles.
   CSS variables, body resets, shell layout (top bar / sidebar / content),
   form fundamentals, generic buttons, theme toggle, tile grid (shared by
   the tools home and admin dashboard), confirmation modal, and the
   accessibility helpers. Loaded first in App.razor so later files can
   override safely. */

/* AL Dev Toolbox — global styles */

/* Design tokens. Names adopted verbatim from the design hand-off
   (.design/translator/styles/app.css); see CLAUDE.md "design tokens".
   Three tokens the hand-off omits but the app needs (--danger,
   --error-text, --info) are carried forward from the previous palette as
   additive tokens. --shadow* is a four-step scale replacing the single
   --shadow-color. */
:root {
    /* Tell the browser this surface is light so native UI — scrollbars,
       form controls, the focus ring — renders to match. Without this,
       Chromium/Edge paint light scrollbars on our dark theme regardless of
       the page colours; overridden to `dark` in the dark-theme blocks below. */
    color-scheme: light;

    /* neutrals — cool slate, very subtle */
    --bg:            #f7f8fa;
    --surface:       #ffffff;
    --surface-2:     #fbfcfd;
    --surface-sunken:#f1f3f6;
    --border:        #e6e8ec;
    --border-strong: #d6dae1;
    --border-input:  #d2d6dd;

    --ink:           #0f172a;  /* headings */
    --ink-2:         #334155;  /* body */
    --ink-3:         #64748b;  /* secondary */
    --ink-4:         #94a3b8;  /* micro-labels / muted */

    /* brand blue */
    --blue:          #2563eb;
    --blue-600:      #2563eb;
    --blue-700:      #1d4ed8;
    --blue-50:       #eff4ff;
    --blue-100:      #e0eaff;
    --on-blue:       #ffffff;

    /* status (XLIFF states) — semantic, consistent weight */
    --st-untrans:    #d97706;
    --st-untrans-bg: #fef3e2;
    --st-fuzzy:      #b45309;
    --st-fuzzy-bg:   #fdf0dc;
    --st-trans:      #2563eb;
    --st-trans-bg:   #eaf1ff;
    --st-final:      #15803d;
    --st-final-bg:   #e7f5ec;

    --good:          #16a34a;
    --good-bg:       #e7f6ec;

    /* additive — not in the hand-off, carried forward */
    --danger:        #b32121;
    --error-text:    #e50000;
    --info:          #2563eb;
    /* colour component of bespoke box-shadows that aren't on the --shadow*
       elevation scale (e.g. the action-bar's upward shadow). */
    --shadow-color:  rgba(0, 0, 0, 0.1);

    /* shape */
    --r-sm: 6px;
    --r:    8px;
    --r-lg: 12px;
    --r-xl: 16px;

    --shadow-xs: 0 1px 2px rgba(15,23,42,.05);
    --shadow-sm: 0 1px 2px rgba(15,23,42,.06), 0 1px 1px rgba(15,23,42,.04);
    --shadow:    0 4px 14px rgba(15,23,42,.07), 0 1px 3px rgba(15,23,42,.05);
    --shadow-lg: 0 12px 34px rgba(15,23,42,.12), 0 3px 8px rgba(15,23,42,.06);

    --sans: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    --mono: "JetBrains Mono", ui-monospace, "SF Mono", "Cascadia Code", "Consolas", monospace;

    --nav-w: 248px;
    --top-h: 64px;
}

/* Dark-theme tokens. Applied in two situations: when the OS prefers dark and
   the user hasn't explicitly chosen light, and when the user has explicitly
   chosen dark from the toggle. Duplicating the block is simpler than CSS
   gymnastics with multi-selector @media rules. Keep the two in sync. */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        color-scheme: dark;

        --bg:            #0b0f17;
        --surface:       #11161f;
        --surface-2:     #0e131b;
        --surface-sunken:#0a0e15;
        --border:        #1f2630;
        --border-strong: #2a323d;
        --border-input:  #2c343f;

        --ink:           #f1f5f9;
        --ink-2:         #cbd5e1;
        --ink-3:         #93a1b3;
        --ink-4:         #6b7787;

        --blue:          #5b8def;
        --blue-600:      #5b8def;
        --blue-700:      #6f9bf2;
        --blue-50:       #16243f;
        --blue-100:      #1b2c4d;
        --on-blue:       #ffffff;

        --st-untrans:    #e0a13c;
        --st-untrans-bg: #2a2114;
        --st-fuzzy:      #d4944a;
        --st-fuzzy-bg:   #2c2113;
        --st-trans:      #6f9bf2;
        --st-trans-bg:   #16243f;
        --st-final:      #4ec57f;
        --st-final-bg:   #12281c;

        --good:          #4ec57f;
        --good-bg:       #12281c;

        --danger:        #ef6464;
        --error-text:    #ff6b6b;
        --info:          #6ba3ff;
        --shadow-color:  rgba(0, 0, 0, 0.5);

        --shadow-xs: 0 1px 2px rgba(0,0,0,.4);
        --shadow-sm: 0 1px 2px rgba(0,0,0,.45);
        --shadow:    0 6px 18px rgba(0,0,0,.5);
        --shadow-lg: 0 18px 44px rgba(0,0,0,.6);
    }
}

:root[data-theme="dark"] {
    color-scheme: dark;

    --bg:            #0b0f17;
    --surface:       #11161f;
    --surface-2:     #0e131b;
    --surface-sunken:#0a0e15;
    --border:        #1f2630;
    --border-strong: #2a323d;
    --border-input:  #2c343f;

    --ink:           #f1f5f9;
    --ink-2:         #cbd5e1;
    --ink-3:         #93a1b3;
    --ink-4:         #6b7787;

    --blue:          #5b8def;
    --blue-600:      #5b8def;
    --blue-700:      #6f9bf2;
    --blue-50:       #16243f;
    --blue-100:      #1b2c4d;
    --on-blue:       #ffffff;

    --st-untrans:    #e0a13c;
    --st-untrans-bg: #2a2114;
    --st-fuzzy:      #d4944a;
    --st-fuzzy-bg:   #2c2113;
    --st-trans:      #6f9bf2;
    --st-trans-bg:   #16243f;
    --st-final:      #4ec57f;
    --st-final-bg:   #12281c;

    --good:          #4ec57f;
    --good-bg:       #12281c;

    --danger:        #ef6464;
    --error-text:    #ff6b6b;
    --info:          #6ba3ff;
    --shadow-color:  rgba(0, 0, 0, 0.5);

    --shadow-xs: 0 1px 2px rgba(0,0,0,.4);
    --shadow-sm: 0 1px 2px rgba(0,0,0,.45);
    --shadow:    0 6px 18px rgba(0,0,0,.5);
    --shadow-lg: 0 18px 44px rgba(0,0,0,.6);
}

/* Code syntax-highlight accents for the Cookbook recipe view
   (.design/explorer-cookbook). Mirrors the app's theme model: light default,
   plus both the system-dark media query and the explicit data-theme override. */
:root { --code-type: #0e7490; --code-num: #9333ea; }
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) { --code-type: #67d6e8; --code-num: #c084fc; }
}
:root[data-theme="dark"] { --code-type: #67d6e8; --code-num: #c084fc; }

* { box-sizing: border-box; }

html, body {
    margin: 0;
    padding: 0;
    /* Bound the viewport-level scroll to 100vh so the app-shell grid
       can rely on .content (overflow-y: auto) as the actual scroll
       container. Without this, .app-shell's min-height: 100vh allowed
       the page to grow taller than the viewport and BODY would scroll
       instead — which silently broke position: sticky on any element
       that expected .content to be its scrolling ancestor. */
    height: 100%;
    overflow: hidden;
    /* --sans leads with Inter but falls back to the system UI stack, so no
       web-font load is required; the rendered face is the platform default
       until/unless Inter is self-hosted (see PR notes). */
    font-family: var(--sans);
    font-size: 14px;
    line-height: 1.5;
    color: var(--ink);
    background: var(--bg);
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

a { color: var(--blue); text-decoration: none; }
a:hover { text-decoration: underline; }

h1 { font-size: 22px; font-weight: 600; margin: 0 0 12px; }
h2 { font-size: 16px; font-weight: 600; margin: 0 0 8px; }
.muted { color: var(--ink-3); }

/* ---------- Shell ---------- */

.app-shell {
    display: grid;
    grid-template-columns: var(--nav-w) 1fr;
    /* Fixed 100vh (not min-height) so the content column is bounded and its
       overflow-y: auto actually engages instead of letting the body scroll.
       Required for position: sticky inside .content. The sidebar spans the
       full height; the top bar lives inside the content column (.main-col)
       so it only sits above the page body, not the sidebar brand. */
    height: 100vh;
    overflow: hidden;
}

/* Sidebar brand — a 64px header row aligned to the top bar so the two share
   one continuous top rule across the shell. */
.sidebar-brand {
    display: flex;
    align-items: center;
    gap: 11px;
    height: var(--top-h);
    min-height: var(--top-h);
    margin: 0 -12px 8px;
    padding: 0 20px;
    border-bottom: 1px solid var(--border);
    font-weight: 700;
    font-size: 16.5px;
    letter-spacing: -0.2px;
    color: var(--ink);
}

.sidebar-brand:hover { text-decoration: none; }
.sidebar-brand__logo { color: var(--blue); flex: 0 0 auto; }
.sidebar-brand__name { line-height: 1; }

.main-col {
    display: flex;
    flex-direction: column;
    overflow: hidden;
    min-width: 0;
}

.top-bar {
    height: var(--top-h);
    min-height: var(--top-h);
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 14px;
    padding: 0 22px;
    background: var(--surface);
    border-bottom: 1px solid var(--border);
}

.sidebar-brand:focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: 2px;
    border-radius: 4px;
}

/* Muted, low-emphasis affordance in the top bar. The admin section is
   secondary to the generator flows, so the entry point shouldn't compete
   visually with anything on the page. */
.signin-link {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    border: 1px solid var(--border-strong);
    border-radius: var(--r);
    background: transparent;
    color: var(--ink-3);
    font-size: 12.5px;
    text-decoration: none;
}

.signin-link:hover {
    color: var(--ink);
    background: var(--bg);
    text-decoration: none;
}

/* Icon-only variant used for the anonymous "Sign in" affordance — square
   with no text so it stays visually quiet next to the theme toggle. */
.signin-link--icon {
    padding: 4px;
    width: 28px;
    height: 28px;
    justify-content: center;
}

.sidebar {
    background: var(--surface);
    border-right: 1px solid var(--border);
    /* No top padding — the 64px .sidebar-brand row provides the top header
       and pins to the very top. Horizontal padding frames the nav items. */
    padding: 0 12px 16px;
    overflow-y: auto;
    /* Flex column so the inner .sidebar-nav can fill the full height,
       which in turn lets the storage indicator pin to the bottom via
       margin-top: auto. */
    display: flex;
    flex-direction: column;
}

.content {
    flex: 1;
    min-height: 0;
    padding: 24px 32px;
    overflow-y: auto;
}

/* Centre every page's top-level wrapper inside the content column. Pages
   set their own max-width (.admin-page, .workspace-page, .audit-page,
   etc.); margin-inline:auto is a no-op for elements with no max-width
   so this also leaves naturally-full-width content alone. */
.content > * { margin-inline: auto; }

/* SiteAdmin pages place a bare .admin-section at the root; give it the
   same reading width as .admin-page so the work area stays consistent
   across the app. */
.content > .admin-section { max-width: 1100px; }

/* ---------- Sidebar nav ---------- */

.sidebar-nav { display: flex; flex-direction: column; gap: 18px; flex: 1; min-height: 0; }

.nav-section__label {
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 1px;
    color: var(--ink-4);
    text-transform: uppercase;
    padding: 6px 10px 8px;
}

.nav-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }

.nav-link {
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 8px 11px;
    border-radius: var(--r);
    color: var(--ink-2);
    font-weight: 500;
    font-size: 13.5px;
    transition: background 0.12s ease, color 0.12s ease;
}

.nav-link:hover { background: var(--surface-sunken); text-decoration: none; }
.nav-link.active { background: var(--blue-50); color: var(--blue-700); font-weight: 600; }
.nav-link__icon { color: var(--ink-3); flex: 0 0 auto; }
.nav-link.active .nav-link__icon { color: var(--blue); }
.nav-link--muted { color: var(--ink-3); }

.nav-group { display: flex; flex-direction: column; gap: 2px; }

/* Group-header link (Projects, Templates). Used to be a non-clickable <div>;
   now it's a real NavLink that navigates to the group's primary page, so it
   picks up the standard pointer cursor and hover background like any other
   nav link — no overrides needed. */
.nav-link--group {
    color: var(--ink);
}

/* The sub-list is anchored to the parent's icon column (≈ 18px icon + 10px
   gap = 28px) so a thin vertical guide can sit at that x-coordinate and read
   as a continuation of the parent row. */
.nav-sublist {
    list-style: none;
    margin: 2px 0 0;
    padding: 2px 0 2px 28px;
    display: flex;
    flex-direction: column;
    gap: 2px;
    position: relative;
}

.nav-sublist::before {
    content: "";
    position: absolute;
    left: 18px;
    top: 2px;
    bottom: 2px;
    width: 1px;
    background: var(--border-strong);
}

.nav-link--sub {
    padding: 6px 10px;
    font-size: 13px;
    color: var(--ink-3);
    font-weight: 500;
}

.nav-link--sub.active {
    background: var(--blue-50);
    color: var(--blue-700);
    font-weight: 600;
}

.nav-divider {
    height: 1px;
    background: var(--border);
    margin: 10px 6px 10px;
}

/* Pinned to the bottom of the sidebar nav. Holds the storage indicator
   (when applicable) and the copyright line. Uses margin-top:auto on the
   wrapper so the copyright stays at the bottom even when the storage bar
   is hidden (unlimited quota, non-admin, system org). */
.sidebar-footer {
    margin-top: auto;
    display: flex;
    flex-direction: column;
}

.sidebar-links {
    display: flex;
    justify-content: center;
    gap: 12px;
    padding: 10px 12px 4px;
}

.sidebar-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: var(--r);
    color: var(--ink-4);
    transition: color 0.12s ease, background 0.12s ease;
}

.sidebar-link:hover {
    color: var(--ink);
    background: var(--bg);
    text-decoration: none;
}

.sidebar-copyright {
    padding: 4px 12px 6px;
    font-size: 11px;
    color: var(--ink-3, var(--ink-4));
    text-align: center;
}

/* ---------- Page stub ---------- */

.page-stub { max-width: 720px; }
.page-stub p { margin: 0; }

/* Page header used by the generator pages (New workspace, New extension,
   Templates). Matches admin-page__header visually so the title bar reads
   the same wherever you are. */
.page-header { margin-bottom: 20px; }
.page-header h1 { margin: 0 0 6px; }
.page-header p { margin: 0; }
.form-grid {
    display: flex;
    flex-direction: column;
    gap: 22px;
}

.form-section {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.form-section--row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px;
}

.form-section--row > div { display: flex; flex-direction: column; gap: 6px; }

/* Narrower form grid for forms where 100%-wide inputs feel wider than they
   need to be (the Configuration page being the main culprit). Keeps the
   eye-line shorter without forcing each field to declare its own max-width. */
.form-grid--narrow { max-width: 560px; }
.form-grid--narrow .form-section--row { max-width: 360px; }
.form-grid--narrow .form-section--id { max-width: 180px; }

.section-label {
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ink-4);
}

.form-section input[type="text"],
.form-section input[type="email"],
.form-section input[type="url"],
.form-section input[type="number"],
.form-section input[type="password"],
.form-section input[type="search"],
.form-section input[type="time"],
.form-section input[type="date"],
.form-section input[type="datetime-local"],
.form-section input[type="file"],
.form-section textarea,
.form-section select,
.form-grid > input[type="text"],
.form-grid > input[type="email"],
.form-grid > input[type="url"],
.form-grid > input[type="number"],
.form-grid > input[type="password"],
.form-grid > input[type="search"],
.form-grid > input[type="time"],
.form-grid > input[type="date"],
.form-grid > input[type="datetime-local"],
.form-grid > input[type="file"],
.form-grid > textarea,
.form-grid > select,
.admin-form input[type="text"],
.admin-form input[type="email"],
.admin-form input[type="url"],
.admin-form input[type="number"],
.admin-form input[type="password"],
.admin-form input[type="search"],
.admin-form input[type="time"],
.admin-form input[type="date"],
.admin-form input[type="datetime-local"],
.admin-form input[type="file"],
.admin-form textarea,
.admin-form select,
.admin-filter-form input[type="text"],
.admin-filter-form input[type="search"],
.admin-filter-form input[type="datetime-local"],
.admin-filter-form select,
.admin-search-input {
    width: 100%;
    padding: 8px 10px;
    border: 1px solid var(--border-strong);
    border-radius: var(--r);
    font-family: inherit;
    font-size: 13.5px;
    background: var(--surface);
    color: var(--ink);
}

.form-section textarea,
.form-grid > textarea,
.admin-form textarea { resize: vertical; min-height: 70px; }

.form-section input:disabled,
.form-section textarea:disabled,
.form-section select:disabled,
.form-grid > input:disabled,
.form-grid > textarea:disabled,
.form-grid > select:disabled,
.admin-form input:disabled,
.admin-form textarea:disabled,
.admin-form select:disabled {
    background: var(--bg);
    color: var(--ink-4);
    cursor: not-allowed;
}

.form-section input:focus,
.form-section textarea:focus,
.form-section select:focus,
.form-grid > input:focus,
.form-grid > textarea:focus,
.form-grid > select:focus,
.admin-form input:focus,
.admin-form textarea:focus,
.admin-form select:focus {
    outline: none;
    border-color: var(--blue);
    box-shadow: 0 0 0 3px var(--blue-50);
}

/* Pin <option> colours to the dark surface so the browser doesn't paint the
   open dropdown list in its own platform default (typically a near-white
   panel that's unreadable against our dark text). Chromium honours these
   on Linux; Safari and Windows still defer to the OS theme, which is a
   long-standing browser quirk we accept rather than re-implement the
   <select> in JS. */
.form-section select option,
.form-grid > select option,
.admin-form select option,
.admin-filter-form select option {
    background: var(--surface);
    color: var(--ink);
}

.form-section select optgroup,
.form-grid > select optgroup,
.admin-form select optgroup,
.admin-filter-form select optgroup {
    background: var(--surface);
    color: var(--ink-4);
    font-style: italic;
}

/* Browsers (Chrome / Safari) repaint autofilled fields with their own
   light-yellow background, which clashes badly with dark mode. Pin the
   colour and use the inset-shadow trick to mask the agent default. */
.form-section input:-webkit-autofill,
.form-section input:-webkit-autofill:hover,
.form-section input:-webkit-autofill:focus,
.form-grid > input:-webkit-autofill,
.form-grid > input:-webkit-autofill:hover,
.form-grid > input:-webkit-autofill:focus,
.admin-form input:-webkit-autofill,
.admin-form input:-webkit-autofill:hover,
.admin-form input:-webkit-autofill:focus {
    -webkit-text-fill-color: var(--ink);
    -webkit-box-shadow: 0 0 0 1000px var(--surface) inset;
    caret-color: var(--ink);
    transition: background-color 9999s ease-in-out 0s;
}

/* Sections inside .admin-form / .form-grid that pair a label with an
   input. SiteAdminSettings wraps both inside the same <label> element;
   the Administration pages place the .section-label and the input as
   sibling children of .form-grid. Both layouts need the same vertical
   rhythm. */
.admin-form > label,
.admin-form > .form-row > label {
    display: flex;
    flex-direction: column;
    gap: 6px;
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ink-4);
}

.admin-form > label > input,
.admin-form > label > textarea,
.admin-form > label > select,
.admin-form > .form-row > label > input,
.admin-form > .form-row > label > textarea,
.admin-form > .form-row > label > select {
    /* Reset the inherited uppercase from the label so the typed text
       reads at normal case. */
    text-transform: none;
    letter-spacing: normal;
    font-size: 13.5px;
    font-weight: 400;
    color: var(--ink);
}

.admin-form .form-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px;
}

.admin-form .checkbox-label,
.admin-form label.checkbox-label {
    display: inline-flex;
    flex-direction: row;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    font-weight: 400;
    letter-spacing: normal;
    text-transform: none;
    color: var(--ink);
}

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

/* Tool on/off list — site Tools settings and per-org Tools admin. One row per
   tool: a checkbox, the tool name, and a one-line description underneath. */
.tool-toggle-list {
    list-style: none;
    margin: 16px 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
    max-width: 560px;
}

.tool-toggle .checkbox-label {
    align-items: flex-start;
    gap: 10px;
    width: 100%;
    padding: 10px 12px;
    border: 1px solid var(--line);
    border-radius: 8px;
}

.tool-toggle .checkbox-label:hover {
    background: var(--surface-2);
}

.tool-toggle .checkbox-label input[type="checkbox"] {
    margin-top: 2px;
}

.tool-toggle__text {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.tool-toggle__name {
    font-weight: 600;
}

.tool-toggle__blurb {
    font-size: 12px;
}

.admin-form > h2 {
    font-size: 14px;
    font-weight: 600;
    margin: 8px 0 4px;
    color: var(--ink);
}

.admin-form > h2:first-child { margin-top: 0; }

.admin-form,
.admin-form--inline {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.admin-form--inline {
    flex-direction: row;
    align-items: center;
    gap: 10px;
}

.admin-form .form-actions {
    display: flex;
    gap: 10px;
    margin-top: 6px;
}

/* `.form-info` is referenced by SiteAdminSettings for success toasts;
   match the form-success rule's visual chrome but keep the original
   class so the page renders consistently. */
.form-info {
    color: var(--good);
    background: var(--surface);
    border: 1px solid var(--good);
    border-radius: var(--r);
    padding: 8px 12px;
    margin: 0 0 16px;
    font-size: 13px;
}

.caption { font-size: 12px; margin: 0; }

.module-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.module-card {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: var(--r);
    cursor: pointer;
    transition: background 0.1s ease;
}

.module-card:hover { background: var(--bg); }
.module-card:has(input:checked) { background: var(--blue-50); border-color: var(--blue); }

.module-card__body { display: flex; flex-direction: column; gap: 2px; }
.module-card__name { font-weight: 500; }
.module-card__caption { font-size: 12px; }

/* Lock badge on the right of an always-included file row. Signals that the
   row's path / content / mustache flag live in another editor (Configuration
   · Files); the checkbox here only opts the current template in or out. */
.module-card--with-lock .module-card__body { flex: 1; }
.module-card__lock {
    display: inline-flex;
    align-items: center;
    color: var(--ink-4);
    margin-left: auto;
}

.check-row {
    display: flex;
    align-items: center;
    gap: 8px;
    cursor: pointer;
}

.btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 9px 16px;
    border-radius: var(--r);
    border: 1px solid var(--border-strong);
    background: var(--surface);
    color: var(--ink);
    font-family: inherit;
    font-size: 13.5px;
    font-weight: 500;
    line-height: 1.2;
    cursor: pointer;
    white-space: nowrap;
    text-decoration: none;
    box-sizing: border-box;
}

.btn:hover {
    background: var(--surface-sunken);
    text-decoration: none;
}

.btn--primary {
    background: var(--blue);
    border-color: var(--blue);
    color: var(--on-blue);
    font-weight: 600;
    box-shadow: var(--shadow-xs);
}

.btn--primary:hover { background: var(--blue-700); border-color: var(--blue-700); }

/* Compact button used inside table rows (e.g. quick actions in the templates
   browser). Renders inline-flex so an Icon + label sit on one line. */
.btn--sm {
    padding: 4px 10px;
    font-size: 12.5px;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    text-decoration: none;
    white-space: nowrap;
}

.btn--sm:hover { text-decoration: none; }

/* Square icon-only variant. Used in tight row-action cells where a row of
   icons reads better than a row of full text buttons (Backups list, etc.).
   Title/aria-label on the element carry the accessible name. */
.btn--icon {
    padding: 4px;
    width: 28px;
    height: 28px;
    justify-content: center;
    gap: 0;
}

.data-table__actions {
    width: 1%;
    text-align: right;
    white-space: nowrap;
}

.data-table__actions .btn + .btn { margin-left: 8px; }

/* Inline action cell used on the Users / Invites tables. Lays out the
   per-row form buttons on a single line and gives them a consistent gap
   regardless of whether each <form> is rendered as inline-block. */
.row-actions {
    width: 1%;
    text-align: right;
    white-space: nowrap;
}

.row-actions form { display: inline-block; }
.row-actions form + form,
.row-actions form + .btn,
.row-actions .btn + form,
.row-actions .btn + .btn { margin-left: 6px; }

/* Small status pills for table cells (e.g. user Active/Disabled, role
   Admin/User). Same look as .user-button__role so the chrome is
   consistent across the app. */
.status-pill {
    display: inline-block;
    padding: 1px 8px;
    border-radius: 999px;
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 0.02em;
    line-height: 1.6;
    background: var(--blue-50);
    color: var(--blue);
    white-space: nowrap;
}

.status-pill--muted {
    background: var(--bg);
    color: var(--ink-4);
    border: 1px solid var(--border);
}

.status-pill--warn {
    background: rgba(207, 34, 46, 0.08);
    color: #cf222e;
}

.status-pill--inline { margin-left: 6px; }

/* Tiny uppercase caption label (design .cap-label) — section captions,
   "Latest import" / "Files" headers across the reimagined screens. */
.cap-label {
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.9px;
    text-transform: uppercase;
    color: var(--ink-4);
}

/* 3px dot separator used between inline meta items. */
.dotsep {
    display: inline-block;
    width: 3px;
    height: 3px;
    border-radius: 999px;
    background: var(--border-strong);
    flex: 0 0 auto;
}

/* "Live" / "Ready" pill with a glowing green dot, per the design hand-off
   (.design/translator/styles/screens.css). A modifier so the existing blue
   pills are untouched. */
.status-pill--live {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 4px 10px 4px 8px;
    background: var(--good-bg);
    color: var(--good);
    font-weight: 600;
    font-size: 12px;
}

.status-pill--live .status-pill__dot {
    width: 7px;
    height: 7px;
    border-radius: 999px;
    background: var(--good);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--good) 22%, transparent);
}

/* ---------- Errors ---------- */

#blazor-error-ui {
    background: var(--danger);
    color: white;
    padding: 0.6rem 1rem;
    box-shadow: 0 -1px 2px var(--shadow-color);
    display: none;
    position: fixed;
    bottom: 0; left: 0; right: 0;
    z-index: 1000;
}
#blazor-error-ui .reload, #blazor-error-ui .dismiss {
    color: white;
    margin-left: 12px;
    cursor: pointer;
}

.valid.modified:not([type=checkbox]) { outline: 1px solid var(--good); }
.invalid { outline: 1px solid var(--error-text); }
.validation-message { color: var(--error-text); }

/* Inline error banner used by every form that surfaces a saved-but-failed
   message — login, admin saves, generator validation. Lives in base because
   it crosses every surface; pages just emit <p class="form-error"> or wrap
   richer content in <div class="form-error">. */
.form-error {
    color: var(--error-text);
    background: var(--surface);
    border: 1px solid var(--error-text);
    border-radius: var(--r);
    padding: 8px 12px;
    margin: 0 0 16px;
    font-size: 13px;
}

.form-error code {
    font-family: var(--mono);
    font-size: 12px;
}

.form-error > p {
    margin: 0;
}

.form-error > p + .form-error__list {
    margin-top: 8px;
}

/* ---------- Theme toggle ---------- */

.theme-toggle {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    padding: 3px;
    border: 1px solid var(--border-input);
    border-radius: 9px;
    background: var(--surface);
    margin-right: 12px;
}

.theme-toggle__btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 26px;
    padding: 0;
    border: 0;
    border-radius: 6px;
    background: transparent;
    color: var(--ink-4);
    cursor: pointer;
    transition: background 0.12s ease, color 0.12s ease;
}

.theme-toggle__btn:hover { color: var(--ink-2); }

.theme-toggle__btn--active {
    background: var(--surface-sunken);
    color: var(--ink);
    box-shadow: var(--shadow-xs);
}

:root[data-theme="dark"] .theme-toggle__btn--active { background: #1c2430; color: #fff; }

.top-bar__user {
    display: flex;
    align-items: center;
    gap: 12px;
}

.top-bar__user .theme-toggle { margin-right: 0; }

.signout-form { margin: 0; display: inline-flex; }

.user-button {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 4px 10px;
    border: 1px solid var(--border-strong);
    border-radius: var(--r);
    background: transparent;
    color: var(--ink);
    font: inherit;
    font-size: 12.5px;
    cursor: pointer;
    transition: background-color 0.1s ease, border-color 0.1s ease, color 0.1s ease;
}

.user-button:hover {
    background: var(--bg);
    border-color: var(--blue);
    text-decoration: none;
}

.user-button:hover .user-button__name,
.user-button:hover .user-button__org { text-decoration: none; }

.user-button__name { font-weight: 500; }

.user-button__org {
    color: var(--ink-4);
    font-weight: 400;
}

.user-button__role {
    padding: 1px 7px;
    border-radius: 999px;
    background: var(--blue-50);
    color: var(--blue-700);
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 0.02em;
    line-height: 1.5;
    white-space: nowrap;
}

.user-button__icon { color: var(--ink-3); flex: 0 0 auto; }

.user-button:hover .user-button__icon { color: var(--blue); }

/* ---------- Tile grid (admin dashboard + tools home) ---------- */

.admin-dashboard { max-width: 1100px; }
.tools-home { max-width: 1100px; }

.tile-grid {
    margin-top: 20px;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px;
}

.tile {
    position: relative;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 16px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r);
}

.tile__icon { color: var(--ink-4); flex: 0 0 auto; }

.tile__body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }

.tile__title { font-weight: 500; }

.tile__caption {
    font-size: 12px;
    color: var(--ink-3);
}

.tile--placeholder { opacity: 0.7; }

.tile--link {
    color: inherit;
    text-decoration: none;
    transition: border-color 0.1s ease, background-color 0.1s ease;
}

.tile--link:hover {
    border-color: var(--blue);
    background: var(--surface-2, var(--surface));
    text-decoration: none;
}

/* Locked tile: visible but visually quieter, with a lock badge in the
   top-right corner. The whole tile is still a link (to /login?returnUrl=…)
   so clicking it doesn't dead-end. */
.tile--locked { opacity: 0.85; }
.tile--locked .tile__icon { color: var(--ink-3); }

.tile__lock {
    position: absolute;
    top: 8px;
    right: 8px;
    color: var(--ink-3);
}

.admin-section {
    margin-top: 32px;
    padding-top: 20px;
    border-top: 1px solid var(--border);
}

.admin-section h2 {
    margin: 0 0 6px;
    font-size: 16px;
}

.admin-section p {
    margin: 0 0 12px;
}

/* Stacked form-style sections — keep a consistent gap between siblings
   so configuration pages don't render their forms flush against
   following sections. */
.admin-section > form,
.admin-section > .form-grid {
    margin-bottom: 12px;
}

.admin-section > form + form { margin-top: 12px; }

.admin-section h3 {
    font-size: 13px;
    font-weight: 600;
    margin: 16px 0 8px;
    color: var(--ink);
}

/* ---------- Long-running job progress list ---------- */
/* /site-admin/backups renders the in-flight off-site downloads here. The
   list is intentionally minimal — one row per job, a wide progress bar,
   a single status string. Anything richer (logs, ETA) belongs on a
   dedicated jobs page, which doesn't exist yet. */

.admin-section__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 6px;
}

.admin-section__header h2 { margin: 0; }

.job-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.job-list__item {
    border: 1px solid var(--border);
    border-radius: var(--r);
    padding: 12px 14px;
    background: var(--surface);
}

.job-list__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 8px;
}

.job-list__head code {
    font-size: 13px;
}

.job-list__status {
    font-size: 12px;
    color: var(--ink-3);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.job-list__progress {
    width: 100%;
    height: 8px;
    appearance: none;
    border: 0;
    border-radius: 999px;
    overflow: hidden;
    background: var(--border);
}

.job-list__progress::-webkit-progress-bar { background: var(--border); border-radius: 999px; }
.job-list__progress::-webkit-progress-value { background: var(--blue); border-radius: 999px; }
.job-list__progress::-moz-progress-bar { background: var(--blue); border-radius: 999px; }

.job-list__item .form-error {
    margin: 4px 0 0;
}

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

.confirm-modal {
    position: fixed;
    inset: 0;
    z-index: 1000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
}

.confirm-modal__backdrop {
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.45);
}

.confirm-modal__panel {
    position: relative;
    max-width: 420px;
    width: 100%;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r);
    padding: 20px;
    box-shadow: 0 12px 32px var(--shadow-color);
}

/* Wider variant for panels carrying a list/picker rather than a yes/no prompt. */
.confirm-modal__panel--wide {
    max-width: 560px;
}

/* Keep a token + its trailing word together (e.g. ".app files") across line wraps. */
.nowrap { white-space: nowrap; }

.confirm-modal__title {
    font-size: 16px;
    margin: 0 0 8px;
}

.confirm-modal__message {
    margin: 0 0 16px;
    color: var(--ink-3);
    font-size: 13px;
}

.confirm-modal__actions {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
}

/* ---------- Bulleted form-error list ---------- */

.form-error__list {
    margin: 6px 0 0;
    padding-left: 20px;
    font-size: 12.5px;
}

.form-error__list code { font-family: var(--mono); }


/* ---------- Accessibility helpers (M21) ---------- */

/* Visually hide an element but keep it readable to screen readers. Used for
   table captions and inline ARIA labels that would clutter the rendered UI. */
.visually-hidden {
    position: absolute !important;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}
