/* AL Dev Toolbox — global styles */

:root {
    --color-bg: #fafafa;
    --color-surface: #ffffff;
    --color-border: #e6e6e8;
    --color-border-strong: #d2d3d8;
    --color-text: #1f2024;
    --color-text-muted: #6b6f76;
    --color-text-secondary: #8a8e96;
    --color-accent: #0066ff;
    --color-accent-soft: #e8f0ff;
    --color-info: #2563eb;
    --color-danger: #b32121;
    --color-error-text: #e50000;
    --color-valid: #26b050;
    --color-accent-hover: #0052cc;
    --color-shadow: rgba(0, 0, 0, 0.1);
    --sidebar-width: 220px;
    --top-bar-height: 52px;
    --radius: 6px;
    --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
}

/* Dark-theme variables. Variables only — no per-rule overrides — so component
   styles don't need to know which theme is active.

   The same dark variables are 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 doing CSS gymnastics with multi-selector @media rules. */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        --color-bg: #16181c;
        --color-surface: #1d2024;
        --color-border: #2c2f36;
        --color-border-strong: #3a3e47;
        --color-text: #e6e7ea;
        --color-text-muted: #9aa0aa;
        --color-text-secondary: #777c86;
        --color-accent: #4b8bff;
        --color-accent-soft: #1a2742;
        --color-accent-hover: #6ba0ff;
        --color-info: #6ba3ff;
        --color-danger: #ef6464;
        --color-error-text: #ff6b6b;
        --color-valid: #4cc972;
        --color-shadow: rgba(0, 0, 0, 0.5);
    }
}

:root[data-theme="dark"] {
    --color-bg: #16181c;
    --color-surface: #1d2024;
    --color-border: #2c2f36;
    --color-border-strong: #3a3e47;
    --color-text: #e6e7ea;
    --color-text-muted: #9aa0aa;
    --color-text-secondary: #777c86;
    --color-accent: #4b8bff;
    --color-accent-soft: #1a2742;
    --color-accent-hover: #6ba0ff;
    --color-info: #6ba3ff;
    --color-danger: #ef6464;
    --color-error-text: #ff6b6b;
    --color-valid: #4cc972;
    --color-shadow: rgba(0, 0, 0, 0.5);
}

* { box-sizing: border-box; }

html, body {
    margin: 0;
    padding: 0;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Helvetica, Arial, sans-serif;
    font-size: 14px;
    line-height: 1.5;
    color: var(--color-text);
    background: var(--color-bg);
}

a { color: var(--color-accent); 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(--color-text-muted); }

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

.app-shell {
    display: grid;
    grid-template-columns: var(--sidebar-width) 1fr;
    grid-template-rows: var(--top-bar-height) 1fr;
    grid-template-areas:
        "topbar topbar"
        "sidebar content";
    min-height: 100vh;
}

.top-bar {
    grid-area: topbar;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 20px;
    background: var(--color-surface);
    border-bottom: 1px solid var(--color-border);
}

.top-bar__brand {
    display: flex;
    align-items: center;
    gap: 8px;
    font-weight: 600;
}

.brand-icon { color: var(--color-accent); }
.brand-name { font-size: 15px; }

/* 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(--color-border-strong);
    border-radius: var(--radius);
    background: transparent;
    color: var(--color-text-muted);
    font-size: 12.5px;
    text-decoration: none;
}

.signin-link:hover {
    color: var(--color-text);
    background: var(--color-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 {
    grid-area: sidebar;
    background: var(--color-surface);
    border-right: 1px solid var(--color-border);
    padding: 20px 12px;
    overflow-y: auto;
}

.content {
    grid-area: content;
    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; }

.nav-section__label {
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 0.06em;
    color: var(--color-text-secondary);
    text-transform: uppercase;
    padding: 0 10px 6px;
}

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

.nav-link {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 7px 10px;
    border-radius: var(--radius);
    color: var(--color-text);
    font-size: 13.5px;
}

.nav-link:hover { background: var(--color-bg); text-decoration: none; }
.nav-link.active { background: var(--color-accent-soft); color: var(--color-accent); font-weight: 500; }
.nav-link__icon { color: var(--color-text-secondary); flex: 0 0 auto; }
.nav-link.active .nav-link__icon { color: var(--color-accent); }
.nav-link--muted { color: var(--color-text-muted); }

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

.nav-link--group {
    color: var(--color-text);
    cursor: default;
}

.nav-link--group:hover { background: transparent; }

/* 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(--color-border-strong);
}

.nav-link--sub {
    padding: 5px 10px;
    font-size: 13px;
    color: var(--color-text-secondary);
}

.nav-link--sub.active {
    background: var(--color-accent-soft);
    color: var(--color-accent);
    font-weight: 500;
}

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

/* ---------- Tab bar (page-level) ---------- */

/* The .tab-bar / .tab classes drive the auth sign-in tabs (password vs magic
   link). The in-page tab strip on the generator pages was removed once the
   sidebar gained sub-items, but the styles are kept here so the auth surface
   stays consistent with the rest of the chrome. */
.tab-bar {
    display: flex;
    gap: 6px;
    border-bottom: 1px solid var(--color-border);
    margin-bottom: 24px;
}

.tab {
    padding: 8px 14px;
    color: var(--color-text-muted);
    font-size: 13.5px;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
}

.tab:hover { color: var(--color-text); text-decoration: none; }

.tab.active {
    color: var(--color-text);
    border-bottom-color: var(--color-accent);
    font-weight: 500;
}

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

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

/* ---------- Templates browser ---------- */

.templates-browser { max-width: 1100px; }
.templates-browser h2 { margin-top: 28px; }
.templates-browser h2:first-of-type { margin-top: 16px; }

.data-table {
    width: 100%;
    border-collapse: collapse;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    overflow: hidden;
    font-size: 13px;
}
.data-table th, .data-table td {
    padding: 8px 12px;
    text-align: left;
    border-bottom: 1px solid var(--color-border);
}
.data-table th {
    background: var(--color-bg);
    font-weight: 500;
    color: var(--color-text-secondary);
    font-size: 12px;
    letter-spacing: 0.02em;
    text-transform: uppercase;
}
.data-table tr:last-child td { border-bottom: 0; }
.data-table code { font-family: var(--font-mono); font-size: 12.5px; }

/* ---------- Workspace form ---------- */

.workspace-form { max-width: 640px; }

/* Two-column shell for the New Workspace / New Extension pages: the form
   scrolls on the left, the preview sticks to the top of the viewport on the
   right so it stays visible while the user works through a long modules list. */
.workspace-page { max-width: 1100px; }

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

.workspace-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 360px;
    gap: 32px;
    align-items: start;
}

.workspace-layout__form { min-width: 0; }

.workspace-layout__generate { align-self: flex-start; }

.workspace-layout__preview {
    position: sticky;
    top: 16px;
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.preview-card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: 14px 16px;
    max-height: calc(100vh - 120px);
    overflow: auto;
}

.preview-card .section-label { margin-bottom: 8px; display: block; }

/* Import-config card on the New Workspace / New Extension pages. Lives at
   the top of the right-hand column and reuses .preview-card for chrome. */
.import-card {
    max-height: none;
    overflow: visible;
}

.import-card__row {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

.import-card__button,
.logo-upload__button {
    cursor: pointer;
    margin: 0;
    align-self: flex-start;
}

/* Native <input type="file"> is awkward to style cross-browser, so we hide
   it visually and let the surrounding label trigger it. The accessible
   name comes from the label's text content. */
.import-card__input,
.logo-upload__input {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.import-card__filename {
    font-size: 12.5px;
    color: var(--color-text-secondary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
    flex: 1 1 auto;
}

.import-card__hint { margin-top: 8px; }

.preview-stats {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
}

.stat-card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: 10px 12px;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.stat-card__value {
    font-size: 20px;
    font-weight: 600;
    color: var(--color-text);
}

.stat-card__label {
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--color-text-secondary);
}

/* ---------- Folder tree preview ---------- */

.ftp,
.ftp__children {
    list-style: none;
    margin: 0;
    padding: 0;
}

.ftp.ftp--root {
    font-family: var(--font-mono);
    font-size: 12.5px;
    line-height: 1.7;
    color: var(--color-text-secondary);
}

.ftp__children {
    padding-left: 18px;
    border-left: 1px dashed var(--color-border);
    margin-left: 6px;
}

.ftp__row {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

/* Folder rows render as a button so the whole label is clickable to toggle. */
.ftp__row--toggle {
    background: none;
    border: 0;
    padding: 0;
    margin: 0;
    font: inherit;
    color: inherit;
    cursor: pointer;
}

.ftp__row--toggle:hover .ftp__name { color: var(--color-text); }

.ftp__chevron {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 12px;
    color: var(--color-text-secondary);
    flex: 0 0 auto;
}

.ftp__chevron--placeholder { visibility: hidden; }

.ftp__icon {
    display: inline-flex;
    align-items: center;
    color: var(--color-text-secondary);
    flex: 0 0 auto;
}

.ftp__name { white-space: nowrap; }

/* The workspace root and module/Core folders get the accent treatment so
   users can distinguish "things that will be generated" from grouping or
   static folders. */
.ftp__node--workspace > .ftp__row > .ftp__icon,
.ftp__node--workspace > .ftp__row > .ftp__name,
.ftp__node--extension > .ftp__row > .ftp__icon,
.ftp__node--extension > .ftp__row > .ftp__name {
    color: var(--color-info);
}

.ftp__node--workspace > .ftp__row > .ftp__name,
.ftp__node--extension > .ftp__row > .ftp__name {
    font-weight: 500;
}

.ftp__node--file > .ftp__row > .ftp__name { color: var(--color-text-muted); }

/* Marker pinned next to a node that's been added relative to an existing
   workspace — used by New Extension's sibling-extension preview. */
.ftp__badge {
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    padding: 1px 6px;
    border-radius: 999px;
    line-height: 1.4;
    margin-left: 6px;
}

.ftp__badge--new {
    background: var(--color-accent-soft);
    color: var(--color-accent);
}

.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(--color-text-secondary);
}

.form-section input[type="text"],
.form-section input[type="email"],
.form-section input[type="number"],
.form-section input[type="password"],
.form-section input[type="search"],
.form-section input[type="time"],
.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="number"],
.form-grid > input[type="password"],
.form-grid > input[type="search"],
.form-grid > input[type="time"],
.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="number"],
.admin-form input[type="password"],
.admin-form input[type="search"],
.admin-form input[type="time"],
.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(--color-border-strong);
    border-radius: var(--radius);
    font-family: inherit;
    font-size: 13.5px;
    background: var(--color-surface);
    color: var(--color-text);
}

.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(--color-bg);
    color: var(--color-text-secondary);
    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: 2px solid var(--color-accent);
    outline-offset: -1px;
    border-color: var(--color-accent);
}

/* 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(--color-text);
    -webkit-box-shadow: 0 0 0 1000px var(--color-surface) inset;
    caret-color: var(--color-text);
    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;
   AdminConfiguration places 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(--color-text-secondary);
}

.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(--color-text);
}

.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(--color-text);
}

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

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

.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(--color-valid);
    background: var(--color-surface);
    border: 1px solid var(--color-valid);
    border-radius: var(--radius);
    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(--color-surface);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius);
    cursor: pointer;
    transition: background 0.1s ease;
}

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

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

.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(--radius);
    border: 1px solid var(--color-border-strong);
    background: var(--color-surface);
    color: var(--color-text);
    font-size: 13.5px;
    font-weight: 500;
    cursor: pointer;
    white-space: nowrap;
    text-decoration: none;
}

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

.btn:hover { background: var(--color-bg); }

.btn--primary {
    background: var(--color-accent);
    border-color: var(--color-accent);
    color: white;
}

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

/* 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(--color-accent-soft);
    color: var(--color-accent);
    white-space: nowrap;
}

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

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

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

/* ---------- Dependency picker ---------- */

.dep-picker { display: flex; flex-direction: column; gap: 16px; }

.dep-picker__group { display: flex; flex-direction: column; gap: 8px; }

.dep-picker__category { display: flex; flex-direction: column; gap: 4px; }

.dep-picker__category-name {
    font-size: 12px;
    font-weight: 500;
    color: var(--color-text-muted);
    padding: 4px 0 2px;
}

.dep-picker__rows { display: flex; flex-direction: column; gap: 4px; }

.dep-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 10px;
    background: var(--color-surface);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius);
    cursor: pointer;
    transition: background 0.1s ease;
}

.dep-row:hover { background: var(--color-bg); }
.dep-row--selected { background: var(--color-accent-soft); border-color: var(--color-accent); }

.dep-row__body { display: flex; flex-direction: column; gap: 1px; flex: 1; min-width: 0; }
.dep-row__name { font-weight: 500; }
.dep-row__publisher { font-size: 12px; }

.dep-row__version {
    flex: 0 0 110px;
    padding: 5px 8px;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius);
    font-family: var(--font-mono);
    font-size: 12px;
    background: var(--color-surface);
}

.dep-picker__manual {
    display: grid;
    grid-template-columns: 2fr 1.5fr 1.5fr 1fr auto;
    gap: 6px;
    align-items: center;
}

.dep-picker__manual input {
    padding: 7px 9px;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius);
    font-size: 13px;
    background: var(--color-surface);
    min-width: 0;
}

.dep-picker__error { color: var(--color-danger); margin: 0; }

.dep-picker__manual-list { list-style: none; margin: 4px 0 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }

.dep-chip {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 10px;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    font-size: 13px;
}

.dep-chip__body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.dep-chip__id { font-family: var(--font-mono); font-size: 11px; }

.dep-chip__remove {
    border: 0;
    background: transparent;
    color: var(--color-text-muted);
    font-size: 18px;
    line-height: 1;
    cursor: pointer;
    padding: 0 4px;
}

.dep-chip__remove:hover { color: var(--color-danger); }

/* ---------- Success tip (New Extension) ---------- */

.success-tip {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: 14px 16px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.success-tip p { margin: 0; }

.success-tip code {
    font-family: var(--font-mono);
    font-size: 12px;
    background: var(--color-bg);
    padding: 1px 4px;
    border-radius: 3px;
}

.success-tip__snippet {
    margin: 0;
    padding: 8px 10px;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    font-family: var(--font-mono);
    font-size: 12px;
    overflow-x: auto;
}

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

#blazor-error-ui {
    background: var(--color-danger);
    color: white;
    padding: 0.6rem 1rem;
    box-shadow: 0 -1px 2px var(--color-shadow);
    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(--color-valid); }
.invalid { outline: 1px solid var(--color-error-text); }
.validation-message { color: var(--color-error-text); }

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

.theme-toggle {
    display: inline-flex;
    align-items: center;
    gap: 0;
    padding: 2px;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius);
    background: var(--color-bg);
    margin-right: 12px;
}

.theme-toggle__btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 24px;
    padding: 0;
    border: 0;
    border-radius: 4px;
    background: transparent;
    color: var(--color-text-muted);
    cursor: pointer;
}

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

.theme-toggle__btn--active {
    background: var(--color-surface);
    color: var(--color-text);
    box-shadow: 0 1px 2px var(--color-shadow);
}

.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(--color-border-strong);
    border-radius: var(--radius);
    background: transparent;
    color: var(--color-text);
    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(--color-bg);
    border-color: var(--color-accent);
    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(--color-text-secondary);
    font-weight: 400;
}

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

.user-button__icon { color: var(--color-text-muted); flex: 0 0 auto; }

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

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

.login-page {
    max-width: 360px;
    margin: 32px auto;
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.login-form { gap: 18px; }

.login-form .btn {
    align-self: flex-start;
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.tab-bar--auth { margin-bottom: 0; }

.login-form__inline-link {
    align-self: flex-start;
    font-size: 12.5px;
    color: var(--color-text-muted);
}

.login-form__inline-link:hover { color: var(--color-accent); }

.form-error {
    color: var(--color-error-text);
    background: var(--color-surface);
    border: 1px solid var(--color-error-text);
    border-radius: var(--radius);
    padding: 8px 12px;
    margin: 0 0 16px;
    font-size: 13px;
}

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

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

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

/* ---------- Admin dashboard ---------- */

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

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

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

.admin-tile__icon { color: var(--color-text-secondary); flex: 0 0 auto; }

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

.admin-tile__title { font-weight: 500; }

.admin-tile__caption {
    font-size: 12px;
    color: var(--color-text-muted);
}

.admin-tile--placeholder { opacity: 0.7; }

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

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

.admin-section {
    margin-top: 32px;
    padding-top: 20px;
    border-top: 1px solid var(--color-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(--color-text);
}

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

.logo-preview {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
    background: var(--color-bg);
    border: 1px dashed var(--color-border);
    border-radius: var(--radius);
    margin-bottom: 12px;
    min-height: 120px;
}

.logo-preview__img {
    max-width: 220px;
    max-height: 120px;
    display: block;
}

.org-file-list {
    list-style: none;
    padding: 0;
    margin: 0 0 16px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.org-file-row {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 10px 12px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
}

.org-file-row__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    font-size: 13px;
}

.org-file-row__head code {
    font-family: var(--font-mono);
    font-size: 12.5px;
}

.org-file-row__body { margin: 0; }

.org-file-row__content {
    margin: 0;
    padding: 8px 10px;
    background: var(--color-bg);
    border-radius: var(--radius);
    font-family: var(--font-mono);
    font-size: 12px;
    white-space: pre-wrap;
    word-break: break-word;
    max-height: 180px;
    overflow: auto;
}

.org-file-row__actions {
    display: flex;
    gap: 8px;
}

.admin-configuration__danger {
    border-top-color: rgba(207, 34, 46, 0.4);
}

/* ---------- Audit log ---------- */

.audit-page { max-width: 1100px; }

.audit-page__limit-note { margin-top: 12px; font-size: 12.5px; }

/* Search and filter toolbars used by the SiteAdmin pages. The wider filter
   form wraps onto multiple rows on narrower screens; the search form is an
   input-group: input and button share an edge with no gap so they read as
   a single control. */
.admin-search-form {
    display: flex;
    align-items: stretch;
    margin: 16px 0 20px;
    max-width: 560px;
}

.admin-search-form .admin-search-input {
    flex: 1;
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;
    border-right-width: 0;
}

.admin-search-form .admin-search-input:focus { border-right-width: 1px; }

.admin-search-form > .btn {
    border-top-left-radius: 0;
    border-bottom-left-radius: 0;
}

/* When an icon-only button lives in the search input-group it should match
   the input's height (stretched by the form's align-items: stretch) rather
   than its own 28px square. Aspect-ratio keeps it square against whatever
   height the surrounding input ends up at. */
.admin-search-form > .btn--icon {
    width: auto;
    height: auto;
    padding: 0 10px;
    aspect-ratio: 1 / 1;
}

.admin-filter-form {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    align-items: end;
    gap: 12px 16px;
    margin: 16px 0 20px;
    padding: 16px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
}

.admin-filter-form > label {
    display: flex;
    flex-direction: column;
    gap: 4px;
    font-size: 12px;
    font-weight: 500;
    letter-spacing: 0.02em;
    color: var(--color-text-secondary);
    text-transform: uppercase;
}


.audit-panel { margin-top: 28px; }

.audit-panel__header {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 8px;
}

.audit-panel__icon { color: var(--color-text-secondary); }

.audit-panel__title {
    font-size: 16px;
    font-weight: 500;
    margin: 0;
}

.audit-table summary {
    cursor: pointer;
    color: var(--color-text-secondary);
    font-size: 12.5px;
}

.audit-table summary:hover { color: var(--color-text); }

.audit-snapshot {
    margin: 6px 0 0;
    padding: 10px 12px;
    background: var(--color-surface-alt, var(--color-surface));
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    font-family: var(--font-mono);
    font-size: 12px;
    line-height: 1.45;
    white-space: pre-wrap;
    word-break: break-word;
    max-width: 720px;
    max-height: 400px;
    overflow: auto;
}

.audit-action {
    display: inline-block;
    padding: 1px 8px;
    border-radius: 999px;
    font-size: 11.5px;
    font-weight: 500;
    text-transform: lowercase;
    border: 1px solid var(--color-border);
    background: var(--color-surface);
    color: var(--color-text-secondary);
}

.audit-action--created { color: #1a7f37; border-color: rgba(26, 127, 55, 0.4); }

.audit-action--updated { color: #9a6700; border-color: rgba(154, 103, 0, 0.4); }

.audit-action--deleted { color: #cf222e; border-color: rgba(207, 34, 46, 0.4); }

.audit-diff { margin-top: 16px; }

.audit-diff__header {
    display: flex;
    align-items: baseline;
    gap: 12px;
    margin-bottom: 8px;
    flex-wrap: wrap;
}

.audit-diff__title { margin: 0; font-size: 16px; font-weight: 500; }

.audit-diff__icon { color: var(--color-text-secondary); }

.audit-diff__labels { margin: 0; display: inline-flex; gap: 8px; font-size: 12.5px; }

.audit-diff__meta {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 4px 24px;
    margin: 12px 0 18px;
}

.audit-diff__meta div { display: flex; gap: 8px; align-items: baseline; }

.audit-diff__meta dt { color: var(--color-text-secondary); font-size: 12.5px; margin: 0; }

.audit-diff__meta dd { margin: 0; font-size: 13px; }

.audit-diff__table { table-layout: fixed; width: 100%; }

.audit-diff__cell {
    font-family: var(--font-mono);
    font-size: 12px;
    word-break: break-word;
    vertical-align: top;
}

.audit-diff__kind {
    display: inline-block;
    padding: 1px 8px;
    border-radius: 999px;
    font-size: 11.5px;
    font-weight: 500;
    text-transform: lowercase;
    border: 1px solid var(--color-border);
}

.audit-diff__kind--added { color: #1a7f37; border-color: rgba(26, 127, 55, 0.4); }
.audit-diff__kind--removed { color: #cf222e; border-color: rgba(207, 34, 46, 0.4); }
.audit-diff__kind--changed { color: #9a6700; border-color: rgba(154, 103, 0, 0.4); }

.audit-diff__redacted {
    color: var(--color-text-secondary);
    font-style: italic;
}

.audit-diff__row--added .audit-diff__cell--after { background: rgba(26, 127, 55, 0.08); }
.audit-diff__row--removed .audit-diff__cell--before { background: rgba(207, 34, 46, 0.08); }
.audit-diff__row--changed .audit-diff__cell--before { background: rgba(207, 34, 46, 0.05); }
.audit-diff__row--changed .audit-diff__cell--after { background: rgba(26, 127, 55, 0.05); }

/* ---------- Bulk action toolbar ---------- */

.bulk-bar {
    position: sticky;
    top: 0;
    z-index: 5;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: 10px 12px;
    margin-bottom: 12px;
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.04);
}

.bulk-bar__summary { font-size: 13px; }

.bulk-bar__actions { display: flex; flex-wrap: wrap; gap: 6px; margin-left: auto; }

.bulk-bar__error {
    width: 100%;
    margin: 0;
    color: #cf222e;
    font-size: 12.5px;
}

.bulk-bar__success {
    width: 100%;
    margin: 0;
    color: #1a7f37;
    font-size: 12.5px;
}

.bulk-failures {
    margin-top: 10px;
    border: 1px solid rgba(207, 34, 46, 0.4);
    border-radius: var(--radius);
    padding: 10px 12px;
    background: rgba(207, 34, 46, 0.05);
}

.bulk-failures h3 { margin: 0 0 6px; font-size: 13px; }

.bulk-failures ul { margin: 0; padding-left: 18px; font-size: 12.5px; }

.bulk-checkbox { width: 32px; text-align: center; }

/* ---------- Admin pages (templates list + edit) ---------- */

.admin-page { max-width: 1100px; }

.admin-page__header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 16px;
    margin-bottom: 16px;
}

.admin-page__header h1 { margin: 0 0 6px; }

.admin-page__header p { margin: 0; }

.admin-page__header-actions {
    display: flex;
    align-items: center;
    gap: 8px;
    flex: 0 0 auto;
}

.admin-page__toolbar {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 12px;
}

/* Compact inline select used inside data-table rows (e.g. role picker on the
   Users page). Standard form-section padding makes the control overpower
   the rest of the row; this tightens it without losing the focus ring. */
.row-role-select {
    padding: 4px 8px;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius);
    background: var(--color-surface);
    color: var(--color-text);
    font: inherit;
    font-size: 12.5px;
}

/* Trailing action row for "content creation" buttons that sit at the bottom
   of the list they relate to (e.g. New template, New module, New snippet).
   The top-right corner is reserved for navigation (Back to admin); creation
   actions live with the data they create. */
.admin-page__footer-actions {
    display: flex;
    justify-content: flex-start;
    gap: 8px;
    margin-top: 20px;
    padding-top: 16px;
    border-top: 1px solid var(--color-border);
}

.data-table__row--muted td { opacity: 0.65; }

.btn--danger {
    background: #cf222e;
    border-color: #cf222e;
    color: white;
}

.btn--danger:hover { background: #a40e26; }

.form-success {
    color: var(--color-valid);
    background: var(--color-surface);
    border: 1px solid var(--color-valid);
    border-radius: var(--radius);
    padding: 8px 12px;
    /* Separate the toast from the form below — without bottom margin the
       success message sat flush against the next section header. */
    margin: 0 0 16px;
    font-size: 13px;
}

.form-field-error {
    display: block;
    color: var(--color-error-text);
    font-size: 12px;
    margin-top: 4px;
}

/* Used by the "Import config" section on the builder pages — keeps the
   field-keyed validation errors visible without obscuring the rest of the
   form. */
ul.form-field-error {
    margin: 4px 0 0;
    padding-left: 20px;
    list-style: disc;
}

.form-section textarea.json-editor {
    font-family: var(--font-mono);
    font-size: 12.5px;
    line-height: 1.5;
}

/* ---------- Template detail (read-only /templates/{key}) ---------- */

.template-detail { max-width: 1100px; }

.template-detail__header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 16px;
    margin-bottom: 16px;
}

.template-detail__header h1 { margin: 0 0 6px; }

.template-detail__header p { margin: 0; }

.template-detail__meta { margin-bottom: 24px; }

.template-detail__section { margin-bottom: 24px; }

.template-detail__section h2 {
    font-size: 16px;
    margin: 0 0 8px;
}

.template-detail__section textarea.json-editor {
    font-family: var(--font-mono);
    font-size: 12.5px;
    line-height: 1.5;
    width: 100%;
    padding: 8px 10px;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius);
    background: var(--color-surface);
    color: var(--color-text);
    resize: vertical;
}

.template-detail__actions {
    display: flex;
    gap: 12px;
    margin-top: 16px;
}

.kv-grid {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: 6px 16px;
    margin: 0 0 8px;
    font-size: 13px;
}

.kv-grid dt {
    color: var(--color-text-muted, #57606a);
    font-weight: 500;
}

.kv-grid dd { margin: 0; }

/* Two-column layout: editor on the left, live preview on the right.
   Same shape as the New Workspace page's workspace-layout grid so the
   admin and end-user surfaces feel related. */
.admin-template-edit__layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 320px;
    gap: 32px;
    align-items: start;
    max-width: 1240px;
}

.admin-template-edit__editor { min-width: 0; }

.admin-template-edit__preview {
    position: sticky;
    top: 16px;
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.preview-card__hint {
    margin: 0 0 8px;
    font-size: 12px;
}

/* Collapsible variant used on the admin template editor: the <details>
   element gets the card chrome, the <summary> becomes the clickable header,
   and content sits in a padded body div. Keeps the card padding consistent
   whether the panel is open or closed. */
.preview-card--collapsible {
    padding: 0;
    max-height: none;
    overflow: visible;
}

.preview-card__summary {
    list-style: none;
    cursor: pointer;
    user-select: none;
    padding: 12px 16px;
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 11px;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-text-secondary);
}

.preview-card__summary::-webkit-details-marker { display: none; }

.preview-card__summary::before {
    content: "";
    width: 0;
    height: 0;
    border-style: solid;
    border-width: 4px 0 4px 6px;
    border-color: transparent transparent transparent currentColor;
    transition: transform 0.15s ease;
}

.preview-card--collapsible[open] > .preview-card__summary::before {
    transform: rotate(90deg);
}

.preview-card__body {
    padding: 0 16px 14px;
}

.preview-card--scroll[open] {
    max-height: calc(100vh - 200px);
    overflow: auto;
}

.mustache-vars {
    margin: 0;
    display: grid;
    grid-template-columns: max-content 1fr;
    column-gap: 12px;
    row-gap: 6px;
    font-size: 12px;
}

.mustache-vars dt { margin: 0; }
.mustache-vars dt code { font-size: 12px; white-space: nowrap; }
.mustache-vars dd { margin: 0; color: var(--color-text-muted); }
.mustache-vars dd code { font-size: 11px; }

.admin-template-edit__form { max-width: 880px; }

.admin-template-edit__mode {
    display: inline-flex;
    gap: 0;
    margin-bottom: 16px;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: 2px;
    background: var(--color-surface);
}

.admin-template-edit__mode-btn {
    border: 1px solid transparent;
    background: transparent;
}

.admin-template-edit__mode-btn--active {
    background: var(--color-bg);
    border-color: var(--color-border);
}

.admin-template-edit__toml-form { max-width: 880px; }

/* The CodeMirror 6 editor mounts into this div. We give it a fixed height
   so the gutter and content area share a stable scroll context, and let
   the inner .cm-editor fill it. Theme colours come from the CodeMirror
   extension in AdminTemplateEdit.razor.js — we only frame the box. */
.admin-template-edit__toml {
    height: 540px;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--color-surface);
}

.admin-template-edit__toml .cm-editor {
    height: 100%;
    font-family: var(--font-mono);
    font-size: 12.5px;
}

.admin-template-edit__toml .cm-scroller {
    line-height: 1.5;
}

.admin-template-edit__toml-issues {
    margin-top: 8px;
}

.admin-template-edit__actions {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-top: 16px;
    flex-wrap: wrap;
}

.folder-editor__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 8px;
}

.folder-editor__table input[type="text"] {
    width: 100%;
    padding: 6px 8px;
    font-size: 13px;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-surface);
    color: var(--color-text);
}

.folder-editor__handle { width: 1%; white-space: nowrap; }

.folder-editor__order { display: flex; gap: 4px; }

.folder-editor__list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.folder-editor__row {
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-surface);
}

.folder-editor__row-head {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    padding: 8px;
}

.folder-editor__path {
    flex: 1 1 auto;
    min-width: 0;
}

.folder-editor__path input[type="text"] {
    width: 100%;
    padding: 6px 8px;
    font-size: 13px;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-bg);
    color: var(--color-text);
}

.folder-editor__files {
    border-top: 1px solid var(--color-border);
    padding: 8px;
    display: flex;
    flex-direction: column;
    gap: 8px;
    background: var(--color-bg);
}

.folder-editor__files-empty { margin: 0; }

.folder-editor__file {
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-surface);
    padding: 8px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.folder-editor__file-head {
    display: flex;
    align-items: flex-start;
    gap: 8px;
}

.folder-editor__file-content {
    width: 100%;
    min-height: 160px;
}

/* Per-row field grid used by the module dependency editor and the catalogue
   editor. Sits inside a .folder-editor__row beneath the GUID/order/remove
   header so the four metadata fields wrap predictably on narrow viewports. */
.dep-editor__fields {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 8px;
    padding: 0 8px 8px;
}

.dep-editor__fields input[type="text"] {
    width: 100%;
    padding: 6px 8px;
    font-size: 13px;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-bg);
    color: var(--color-text);
}

/* Module dependency editor: catalogue picker row above the selected-rows list,
   read-only GUID/name/publisher rendered as labels inside each row, and a
   small badge for legacy rows whose GUID isn't in the current catalogue. */
.mod-dep-add {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 8px;
}

.mod-dep-add select {
    flex: 1;
    min-width: 0;
    padding: 6px 8px;
    font-size: 13px;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-bg);
    color: var(--color-text);
}

.mod-dep-row__heading {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: baseline;
    gap: 4px;
    flex-wrap: wrap;
    padding: 0 8px;
}

.mod-dep-row__name { font-weight: 500; }

.mod-dep-row__legacy {
    font-size: 11px;
    padding: 1px 6px;
    border-radius: 999px;
    background: var(--color-bg);
    color: var(--color-text-muted);
    border: 1px solid var(--color-border);
}

.mod-dep-row__fields {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
    gap: 8px;
    padding: 0 8px 8px;
}

.mod-dep-row__id code {
    display: block;
    font-family: var(--font-mono);
    font-size: 12px;
    word-break: break-all;
}

.mod-dep-row__version label {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.mod-dep-row__version input[type="text"] {
    width: 100%;
    padding: 6px 8px;
    font-size: 13px;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-bg);
    color: var(--color-text);
}

/* ---------- Generate button loading state ---------- */

/* The default state hides the spinner and the busy label. Toggling the
   modifier class swaps which span is visible; the wrapper's width is
   stable because both labels are display:inline-block of similar length. */
.btn__spinner,
.btn__label-busy { display: none; }

.btn--loading .btn__label { display: none; }
.btn--loading .btn__label-busy { display: inline-flex; align-items: center; gap: 6px; }

.btn--loading .btn__spinner {
    display: inline-block;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    border: 2px solid currentColor;
    border-right-color: transparent;
    animation: spin 0.8s linear infinite;
    margin-right: 6px;
}

.btn--loading {
    cursor: wait;
    opacity: 0.85;
}

@keyframes spin { to { transform: rotate(360deg); } }

/* ---------- 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(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: 20px;
    box-shadow: 0 12px 32px var(--color-shadow);
}

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

.confirm-modal__message {
    margin: 0 0 16px;
    color: var(--color-text-muted);
    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(--font-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;
}

/* Snippets tool — browser, detail, admin queue, editor. */
.snippets-browser__toolbar {
    display: flex;
    align-items: center;
    gap: 12px;
    margin: 12px 0 20px;
}

.snippets-browser__search {
    flex: 1;
    max-width: 480px;
}

.snippet-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: grid;
    gap: 12px;
    grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
}

.snippet-card {
    border: 1px solid var(--color-border, #d0d7de);
    border-radius: 6px;
    padding: 14px 16px;
    background: var(--color-surface, #fff);
}

.snippet-card__title {
    display: block;
    font-weight: 600;
    margin-bottom: 4px;
}

.snippet-card__badge {
    display: inline-block;
    margin-left: 8px;
    font-size: 0.75em;
    padding: 1px 6px;
    border-radius: 8px;
    background: #f6f8fa;
    color: #6e7681;
}

.snippet-card__description {
    margin: 8px 0;
    color: var(--color-muted, #57606a);
}

.snippet-card__keywords {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
}

.snippet-card__keyword {
    font-size: 0.75em;
    padding: 2px 6px;
    border-radius: 8px;
    background: #f6f8fa;
    color: #57606a;
}

.snippet-detail__header {
    display: flex;
    align-items: baseline;
    gap: 12px;
    margin-top: 16px;
}

.snippet-detail__description {
    white-space: pre-wrap;
    margin: 8px 0 16px;
}

.snippet-detail__files {
    list-style: none;
    padding: 0;
    display: grid;
    gap: 16px;
}

.snippet-file-view {
    border: 1px solid var(--color-border, #d0d7de);
    border-radius: 6px;
    overflow: hidden;
}

.snippet-file-view__header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 6px 12px;
    background: #f6f8fa;
    border-bottom: 1px solid var(--color-border, #d0d7de);
}

.snippet-file-view__content {
    margin: 0;
    padding: 12px;
    overflow-x: auto;
    font-size: 0.85em;
    line-height: 1.45;
}

.snippet-files {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.snippet-file {
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius);
    padding: 10px 12px;
    background: var(--color-surface);
}

.snippet-file--expanded { padding-bottom: 12px; }

.snippet-file__row {
    display: flex;
    gap: 10px;
    align-items: flex-end;
}

.snippet-file--expanded .snippet-file__row { margin-bottom: 10px; }

.snippet-file__toggle {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 32px;
    margin-bottom: 1px;
    border: none;
    border-radius: var(--radius);
    background: transparent;
    color: var(--color-text-secondary);
    cursor: pointer;
}

.snippet-file__toggle:hover {
    background: var(--color-bg);
    color: var(--color-text);
}

.snippet-file__name {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
}

.snippet-file__name input {
    width: 100%;
    padding: 8px 10px;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius);
    font-family: inherit;
    font-size: 13.5px;
    background: var(--color-surface);
    color: var(--color-text);
}

.snippet-file__actions {
    display: flex;
    gap: 4px;
    flex: 0 0 auto;
}

.snippet-file__content {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.snippet-file__content textarea {
    width: 100%;
    padding: 8px 10px;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius);
    background: var(--color-surface);
    color: var(--color-text);
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.85em;
    resize: vertical;
}

.snippet-suggestion-list {
    list-style: none;
    padding: 0;
    display: grid;
    gap: 20px;
}

.snippet-suggestion {
    border: 1px solid var(--color-border, #d0d7de);
    border-radius: 6px;
    padding: 16px;
}

/* Applied when /admin/snippets/suggestions?focus={id} matches this row, so
   the admin lands directly on the suggestion the Review link pointed at. */
.snippet-suggestion--focused {
    border-color: var(--color-accent);
    box-shadow: 0 0 0 2px var(--color-accent-soft);
}

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

.snippet-suggestion__header h2 { margin: 0; }

.snippet-suggestion__note {
    min-width: 220px;
}

