/* AL Dev Toolbox — tool page styles.
   Everything specific to the user-facing tools: templates browser and
   read-only detail, New Workspace / New Extension forms with the folder
   tree preview and dependency picker, snippets, Object Explorer (release
   browser, module/object views, source file viewer, diff), generate
   button loading state, and the mustache-variables hint. */

/* ---------- 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(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r);
    overflow: hidden;
    font-size: 13px;
}
.data-table th, .data-table td {
    padding: 8px 12px;
    text-align: left;
    border-bottom: 1px solid var(--border);
}
.data-table th {
    background: var(--bg);
    font-weight: 500;
    color: var(--ink-4);
    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(--mono); font-size: 12.5px; }

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

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

/* ============================================================
   New Workspace / New Extension — restyled to the design hand-off
   (.design/translator/styles/screens.css "workspace"). Everything below is
   scoped under .workspace-page so the shared primitives (.module-card,
   .section-label, .form-section, form inputs) keep their default look on the
   admin pages that also use them. The form wraps the whole page so the
   Generate button stays inside it for generate.js' loading plumbing.
   ============================================================ */
/* The page spans the full content width so the action bar's background can go
   edge to edge; the grid and the action bar's inner content are what cap at
   1320px and centre, so the form + button stay aligned under the content. */
.content:has(.workspace-page) { padding-bottom: 0; }

.workspace-page {
    min-height: 100%;
    display: flex;
    flex-direction: column;
}

.workspace-shell {
    flex: 1;
    display: flex;
    flex-direction: column;
}

.workspace-shell > .workspace-layout { flex: 1; }

/* Page head — bigger title + lead paragraph (design .page-head). Lives inside
   the left column so the preview rail rises to the same top line. */
.workspace-page .page-header { margin-bottom: 22px; }
.workspace-page .page-header h1 { font-size: 27px; font-weight: 700; letter-spacing: -0.5px; margin: 0 0 8px; }
.workspace-page .page-header p { color: var(--ink-3); font-size: 14px; max-width: 760px; line-height: 1.55; margin: 0; }

/* Two-column shell: form on the left, sticky preview rail on the right.
   Capped + centred (the page itself is full-width for the action bar). */
.workspace-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 392px;
    gap: 32px;
    align-items: start;
    width: 100%;
    max-width: 1320px;
    margin-inline: auto;
}

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

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

/* Preview → the design's elevated .card with a header strip. */
.preview-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow);
    overflow: hidden;
}

.preview-card__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 13px 16px;
    border-bottom: 1px solid var(--border);
}

.preview-card__head .section-label { margin: 0; }

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

/* The file-tree body scrolls when the tree is taller than the viewport;
   the short rail cards (import config, after-download tip) don't. */
.preview-card__body--scroll {
    padding: 12px 14px;
    max-height: calc(100vh - 260px);
    overflow: auto;
}

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

/* A touch more room above the file picker so it isn't cramped against the
   card-head divider. */
.import-card .preview-card__body { padding-top: 18px; }

.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(--ink-4);
    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: 16px;
}

/* Stat tiles → the design's .stat: big tabular number over a micro-label. */
.stat-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow);
    padding: 16px 18px;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.stat-card__value {
    font-size: 30px;
    font-weight: 800;
    line-height: 1;
    letter-spacing: -1px;
    color: var(--ink);
    font-variant-numeric: tabular-nums;
}

.stat-card--accent .stat-card__value { color: var(--blue); }

.stat-card__label {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.9px;
    text-transform: uppercase;
    color: var(--ink-4);
}

/* ---- scoped form controls (design .fld / .cap-label / .input) ---- */
.workspace-page .section-label {
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.9px;
    text-transform: uppercase;
    color: var(--ink-4);
    margin-bottom: 2px;
}

.workspace-page .form-section input[type="text"],
.workspace-page .form-section input[type="number"],
.workspace-page .form-section select,
.workspace-page .form-section textarea {
    border: 1px solid var(--border-input);
    border-radius: var(--r);
    padding: 10px 13px;
    font-size: 14px;
}

.workspace-page .form-section input[type="text"],
.workspace-page .form-section input[type="number"],
.workspace-page .form-section select {
    height: 40px;
    padding-top: 0;
    padding-bottom: 0;
}

/* Field helper text (the <small class="muted"> / .caption under inputs). */
.workspace-page .form-section small.muted,
.workspace-page .form-section .caption {
    color: var(--ink-3);
    font-size: 12.5px;
    line-height: 1.5;
}

/* Inline mustache/version chips in helper copy. */
.workspace-page .form-section small code,
.workspace-page .form-section .caption code {
    font-family: var(--mono);
    font-size: 11.5px;
    color: var(--ink-2);
    background: var(--surface-sunken);
    border: 1px solid var(--border);
    border-radius: 5px;
    padding: 1px 5px;
}

/* ---- module cards → the design's selectable .mod ---- */
.workspace-page .module-list { gap: 10px; }

.workspace-page .module-card {
    align-items: center;
    gap: 13px;
    padding: 14px 16px;
    border: 1px solid var(--border-input);
    border-radius: var(--r-lg);
    transition: border-color 0.12s ease, box-shadow 0.12s ease, background 0.12s ease;
}

.workspace-page .module-card:hover { background: var(--surface); border-color: var(--border-strong); }

.workspace-page .module-card:has(input:checked) {
    border-color: var(--blue);
    background: var(--blue-50);
    box-shadow: 0 0 0 3px var(--blue-50);
}

:root[data-theme="dark"] .workspace-page .module-card:has(input:checked) { background: #121a2a; }

/* Hide the native checkbox; a styled .module-card__check renders the box. */
.workspace-page .module-card > input[type="checkbox"] {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
    margin: 0;
}

.workspace-page .module-card__check {
    width: 20px;
    height: 20px;
    flex: 0 0 auto;
    border-radius: 6px;
    border: 1.6px solid var(--border-strong);
    background: var(--surface);
    display: grid;
    place-items: center;
    color: transparent;
    transition: background 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}

.workspace-page .module-card:has(input:checked) .module-card__check {
    background: var(--blue);
    border-color: var(--blue);
    color: #fff;
}

.workspace-page .module-card__body { flex: 1; gap: 4px; }
.workspace-page .module-card__name { font-size: 14px; font-weight: 600; color: var(--ink); }
.workspace-page .module-card__caption {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--ink-3);
}
.workspace-page .module-card__caption svg { width: 13px; height: 13px; color: var(--ink-4); }

/* Modules header tally row. */
.workspace-page .module-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
}
.workspace-page .module-head .selcount { font-size: 12.5px; color: var(--ink-3); }
.workspace-page .module-head .selcount b { color: var(--ink); font-variant-numeric: tabular-nums; }

/* ---- sticky action bar (design .actionbar) ---- */
.workspace-page .actionbar {
    position: sticky;
    bottom: 0;
    margin: 24px -32px 0;
    padding: 16px 32px;
    background: color-mix(in srgb, var(--surface) 90%, transparent);
    backdrop-filter: blur(8px);
    border-top: 1px solid var(--border);
    box-shadow: 0 -8px 18px -6px rgba(15, 23, 42, 0.10);
}

:root[data-theme="dark"] .workspace-page .actionbar { box-shadow: 0 -8px 20px -6px rgba(0, 0, 0, 0.5); }

.workspace-page .actionbar__inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    width: 100%;
    max-width: 1320px;
    margin-inline: auto;
}

.workspace-page .actionbar__info { font-size: 13px; color: var(--ink-3); }
.workspace-page .actionbar__info b { color: var(--ink); }

.btn--lg { padding: 11px 18px; font-size: 14px; }

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

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

.ftp.ftp--root {
    font-family: var(--mono);
    font-size: 12.5px;
    line-height: 1.9;
    color: var(--ink-2);
}

.ftp__children {
    padding-left: 18px;
    border-left: 1px dashed var(--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(--ink); }

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

.ftp__chevron--placeholder { visibility: hidden; }

.ftp__icon {
    display: inline-flex;
    align-items: center;
    color: var(--ink-4);
    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(--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(--ink-3); }

/* 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(--blue-50);
    color: var(--blue);
}

/* ---------- 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(--ink-3);
    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(--surface);
    border: 1px solid var(--border-strong);
    border-radius: var(--r);
    cursor: pointer;
    transition: background 0.1s ease;
}

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

.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(--border-strong);
    border-radius: var(--r);
    font-family: var(--mono);
    font-size: 12px;
    background: var(--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(--border-strong);
    border-radius: var(--r);
    font-size: 13px;
    background: var(--surface);
    min-width: 0;
}

.dep-picker__error { color: var(--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(--bg);
    border: 1px solid var(--border);
    border-radius: var(--r);
    font-size: 13px;
}

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

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

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

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

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

.success-tip p { margin: 0; }

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

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

/* ---------- Mustache variables hint ---------- */

.mustache-hint {
    margin: 0 0 16px;
    padding: 10px 12px;
    border: 1px solid var(--border);
    border-radius: var(--r);
    background: var(--surface-2, var(--surface));
    font-size: 13px;
}

.mustache-hint > summary {
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-weight: 600;
    list-style: none;
}

.mustache-hint > summary::-webkit-details-marker { display: none; }

.mustache-hint__intro {
    margin: 8px 0 6px;
    font-size: 12px;
}

.mustache-hint__list {
    margin: 0;
    display: grid;
    grid-template-columns: max-content 1fr;
    column-gap: 16px;
    row-gap: 4px;
}

.mustache-hint__list dt code {
    font-size: 12px;
}

.mustache-hint__list dd {
    margin: 0;
    color: var(--ink-3);
    font-size: 12px;
}

/* ---------- 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(--mono);
    font-size: 12.5px;
    line-height: 1.5;
    width: 100%;
    padding: 8px 10px;
    border: 1px solid var(--border-strong);
    border-radius: var(--r);
    background: var(--surface);
    color: var(--ink);
    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(--ink-3, #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;
}

/* Mirrors admin-template-edit__layout for the /admin/templates/files page.
   The mustache catalogue now lists 18 variables (with the per-extension
   app.json inputs); the inline MustacheVarsHint that used to sit above the
   file list was crowding the editor. */
.admin-template-files__layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 320px;
    gap: 32px;
    align-items: start;
    max-width: 1240px;
}

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

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

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

.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(--ink-4);
}

.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(--ink-3); }
.mustache-vars dd code { font-size: 11px; }

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

/* The row-table editors (catalogue, application versions) opt into the wider
   Object Explorer width — their tables have more columns than the structured
   template form, which keeps the default 880px cap. */
.admin-page.admin-page--wide { max-width: 1320px; }
.admin-page--wide .admin-template-edit__form { max-width: none; }

/* Section heading inside the structured form. Gives long pages a scannable
   outline so admins can find Identity / Versioning & ID ranges / Modules /
   Always-included files / Workspace settings overlay / Extensions without
   reading every label. Sits between sections; a thin separator above the
   text echoes the panel rhythm of the surrounding cards. */
.admin-template-edit__group-heading {
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ink-4);
    margin: 24px 0 4px;
    padding-top: 16px;
    border-top: 1px solid var(--border);
}

.admin-template-edit__group-heading:first-of-type {
    margin-top: 8px;
    padding-top: 0;
    border-top: 0;
}

/* Read-only reference panel showing the org-wide workspace settings
   above the per-template overlay textarea. <details> so it collapses
   by default and doesn't dominate the section. */
.admin-template-edit__org-base {
    margin-bottom: 8px;
    border: 1px solid var(--border);
    border-radius: var(--r);
    background: var(--bg);
}

.admin-template-edit__org-base > summary {
    cursor: pointer;
    padding: 6px 10px;
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 12.5px;
    color: var(--ink-4);
    list-style: none;
}

.admin-template-edit__org-base > summary::-webkit-details-marker { display: none; }
.admin-template-edit__org-base > summary::marker { content: ""; }

.admin-template-edit__org-base[open] > summary {
    border-bottom: 1px solid var(--border);
}

.admin-template-edit__org-base-body {
    margin: 0;
    padding: 10px 12px;
    font-family: var(--mono, monospace);
    font-size: 12.5px;
    color: var(--ink);
    white-space: pre;
    overflow-x: auto;
    max-height: 220px;
}

/* Pill tabs. Originally introduced for the Form / TOML toggle on the
   template editor; now also used to navigate sub-pages of the per-org
   Administration surface (where each tab is an <a href> to a sibling
   route rather than an in-page button). The container is the same; only
   the inner elements differ. */
.pill-tabs {
    display: inline-flex;
    gap: 0;
    margin-bottom: 16px;
    border: 1px solid var(--border);
    border-radius: var(--r);
    padding: 2px;
    background: var(--surface);
}

/* Equal-width variant (PillTabs Equal="true"): the row fills its container and
   every tab takes an equal share, so labels of different lengths don't give the
   tabs different widths. Used by the Import Release header. */
.pill-tabs--equal {
    display: flex;
}
.pill-tabs--equal .pill-tab {
    flex: 1 1 0;
    justify-content: center;
}

.pill-tab {
    border: 1px solid transparent;
    background: transparent;
}

.pill-tab--active {
    background: var(--bg);
    border-color: var(--border);
}

/* Anchor variant is used when pill tabs are route navigation links
   (PillTabs.razor); the button variant covers in-page mode toggles
   like Piper's Text/Table switcher. Both share the same size/spacing so
   the visual language matches across the app. */
a.pill-tab,
button.pill-tab {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    border-radius: calc(var(--r) - 2px);
    color: var(--ink);
    text-decoration: none;
    font-size: 13px;
    line-height: 1.2;
}

button.pill-tab {
    font: inherit;
    font-size: 13px;
    cursor: pointer;
}

a.pill-tab:hover,
button.pill-tab:hover { text-decoration: none; }
a.pill-tab.pill-tab--active,
button.pill-tab.pill-tab--active { color: var(--ink); font-weight: 500; }

.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 wwwroot/code-editor.js — we only frame the box. */
.admin-template-edit__toml {
    height: 540px;
    border: 1px solid var(--border-strong);
    border-radius: var(--r);
    overflow: hidden;
    background: var(--surface);
}

.admin-template-edit__toml .cm-editor {
    height: 100%;
    font-family: var(--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(--border);
    border-radius: var(--r);
    background: var(--surface);
    color: var(--ink);
}

.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(--border);
    border-radius: var(--r);
    background: var(--surface);
}

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

/* Match the up/down/remove buttons to the height of the path input so the
   row reads as one line rather than three slightly-different mini-controls.
   Scoped to the template editor's extension/folder list — other pages (e.g.
   AdminApplicationVersions) reuse `.folder-editor__*` classes with their own
   button sizing that mustn't be bumped to 30px. */
.extension-editor__list .folder-editor__row-head {
    align-items: center;
}

.extension-editor__list .folder-editor__row-head > .btn--sm,
.extension-editor__list .folder-editor__order .btn--sm {
    min-height: 30px;
}

.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(--border);
    border-radius: var(--r);
    background: var(--bg);
    color: var(--ink);
}

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

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

.folder-editor__file {
    border: 1px solid var(--border);
    border-radius: var(--r);
    background: var(--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;
}

/* Buttons under a recursive folder's expanded body: "Add file" / "Add subfolder". */
.folder-editor__add-row {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
}

/* Inline checkbox used inside a file-header row (Example toggle). */
.check-row.check-row--inline {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    margin: 0;
    white-space: nowrap;
    font-size: 13px;
}

/* Visual nesting cue for child folders inside the recursive editor. The
   border-left tracks depth without indenting via padding so reorder buttons
   stay flush with the parent's edge. */
.folder-editor__row--depth-1 { border-left: 2px solid var(--border-strong, var(--border)); }
.folder-editor__row--depth-2 { border-left: 2px solid var(--border-strong, var(--border)); margin-left: 4px; }
.folder-editor__row--depth-3 { border-left: 2px solid var(--border-strong, var(--border)); margin-left: 8px; }

/* Row-table editor (catalogue, application versions): a toolbar that acts on
   the selected row sits above an editable data-table where every cell is an
   inline input. Reuses the Object Explorer elevated-card table styling. */
.row-editor {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.row-editor__toolbar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
}

.row-editor__divider {
    width: 1px;
    align-self: stretch;
    min-height: 20px;
    background: var(--border);
    margin: 0 2px;
}

/* Elevated card look, mirroring .object-explorer__browser .data-table. */
.row-editor__table.data-table {
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    border-collapse: separate;
    border-spacing: 0;
    box-shadow: var(--shadow);
    background: var(--surface);
    table-layout: fixed;
}

.row-editor__table.data-table thead th {
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.8px;
    text-transform: uppercase;
    color: var(--ink-4);
    background: var(--surface-2);
    border-bottom: 1px solid var(--border);
    padding: 10px 12px;
}

.row-editor__table.data-table thead th:first-child { border-top-left-radius: var(--r-lg); }
.row-editor__table.data-table thead th:last-child { border-top-right-radius: var(--r-lg); }

.row-editor__table.data-table tbody td {
    padding: 6px 8px;
    border-bottom: 1px solid var(--border);
    vertical-align: top;
}

.row-editor__table.data-table tbody tr:last-child td { border-bottom: 0; }
.row-editor__table.data-table tbody tr { transition: background 0.1s ease; }
.row-editor__table.data-table tbody tr:hover { background: var(--surface-2); }

/* Selected row wins over :hover so the highlight is unambiguous. */
.row-editor__table.data-table tbody tr.is-selected,
.row-editor__table.data-table tbody tr.is-selected:hover {
    background: var(--blue-50);
    box-shadow: inset 3px 0 0 0 var(--blue-700);
}

/* The trailing "ghost" row is the always-present add placeholder — dim its
   placeholder text a touch so it reads as the next-entry line, not real data. */
.row-editor__table.data-table tbody tr.is-ghost input::placeholder { opacity: 0.55; }

/* Inline-cell inputs read as table text until focused. */
.row-editor__table input[type="text"] {
    width: 100%;
    padding: 6px 8px;
    font-size: 13px;
    border: 1px solid transparent;
    border-radius: var(--r);
    background: transparent;
    color: var(--ink);
}

.row-editor__table input[type="text"]:hover {
    border-color: var(--border);
    background: var(--surface);
}

.row-editor__table input[type="text"]:focus {
    outline: none;
    border-color: var(--blue-700);
    background: var(--surface);
    box-shadow: 0 0 0 2px var(--blue-50);
}

.row-editor__cell-center { text-align: center; }
.row-editor__cell-center input[type="checkbox"] { margin: 6px 0 0; }

/* "In use by N templates" pill; full list lives in the title= tooltip. */
.row-editor__usage {
    display: inline-block;
    min-width: 20px;
    padding: 1px 7px;
    border-radius: 999px;
    font-size: 12px;
    font-variant-numeric: tabular-nums;
    background: var(--surface-sunken);
    color: var(--ink-3);
    border: 1px solid var(--border);
    cursor: help;
}

/* Column sizing for the two row-table editors. */
.row-editor__col-guid { width: 22rem; }
.row-editor__col-key { width: 12rem; }
.row-editor__col-version { width: 9rem; }
.row-editor__col-category { width: 11rem; }
.row-editor__col-flag { width: 7rem; }

/* FieldError sits under its input inside the cell. */
.row-editor__table .form-field-error { display: block; margin-top: 2px; }

/* Extension list — each extension is a folder-editor-style row with a richer
   body of nested sections (metadata, dependencies, folders). */
.extension-editor__list {
    gap: 16px;
}

.extension-editor__row {
    background: var(--bg);
}

.extension-editor__body {
    border-top: 1px solid var(--border);
    padding: 12px;
    display: flex;
    flex-direction: column;
    gap: 12px;
    background: var(--surface);
}

.extension-editor__body .form-section { margin: 0; }

/* Dependency-row body uses the existing dep-editor__fields grid; this rule
   adds the per-row select+remove header spacing without touching that grid. */
.dep-row .folder-editor__path select {
    width: 100%;
    padding: 6px 8px;
    font-size: 13px;
    border: 1px solid var(--border);
    border-radius: var(--r);
    background: var(--bg);
    color: var(--ink);
}

/* 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(--border);
    border-radius: var(--r);
    background: var(--bg);
    color: var(--ink);
}

/* 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(--border);
    border-radius: var(--r);
    background: var(--bg);
    color: var(--ink);
}

.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(--bg);
    color: var(--ink-3);
    border: 1px solid var(--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(--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(--border);
    border-radius: var(--r);
    background: var(--bg);
    color: var(--ink);
}

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

/* ---------- Snippets ---------- */
/* 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(--border, #d0d7de);
    border-radius: 6px;
    padding: 14px 16px;
    background: var(--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: var(--bg);
    border: 1px solid var(--border);
    color: var(--ink-3);
}

.snippet-card__description {
    margin: 8px 0;
    color: var(--ink-3);
}

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

.snippet-card__keyword {
    font-size: 0.75em;
    padding: 2px 8px;
    border-radius: 8px;
    background: var(--bg);
    border: 1px solid var(--border);
    color: var(--ink-3);
}

.snippet-detail--with-outline {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 240px;
    gap: 24px;
    align-items: start;
}

.snippet-detail__main {
    min-width: 0;
}

.snippet-detail__topbar {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
}

.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__instructions {
    margin: 16px 0 20px;
    padding: 12px 16px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 6px;
}

.snippet-detail__instructions h2 {
    margin-top: 0;
    font-size: 1.1em;
}

.snippet-detail__instructions-body :first-child {
    margin-top: 0;
}

.snippet-detail__instructions-body :last-child {
    margin-bottom: 0;
}

.snippet-detail__instructions-body pre {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 4px;
    padding: 8px 12px;
    overflow-x: auto;
}

.snippet-detail__instructions-body code {
    font-family: var(--mono, ui-monospace, SFMono-Regular, monospace);
    font-size: 0.9em;
}

.snippet-detail .snippet-card__keywords {
    margin-bottom: 20px;
}

.snippet-detail h2 {
    margin-top: 8px;
}

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

.snippet-file-view {
    border: 1px solid var(--border);
    border-radius: 6px;
    overflow: hidden;
    background: var(--surface);
}

.snippet-file-view__header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 8px;
    padding: 4px 12px 4px 6px;
    background: var(--bg);
    color: var(--ink);
    border-bottom: 1px solid var(--border);
}

.snippet-file-view--collapsed .snippet-file-view__header {
    border-bottom-color: transparent;
}

.snippet-file-view__toggle {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex: 1 1 auto;
    min-width: 0;
    background: transparent;
    border: 0;
    padding: 4px 6px;
    border-radius: 4px;
    color: inherit;
    cursor: pointer;
    text-align: left;
    font: inherit;
}

.snippet-file-view__toggle:hover {
    background: var(--surface);
}

.snippet-file-view__toggle code {
    color: var(--ink);
    font-family: var(--mono);
    font-size: 12.5px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}

.snippet-file-view__header code {
    color: var(--ink);
    font-family: var(--mono);
    font-size: 12.5px;
}

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

.snippet-file-view--collapsed .snippet-file-view__content {
    display: none;
}

.snippet-outline {
    position: sticky;
    top: 16px;
    align-self: start;
    max-height: calc(100vh - 32px);
}

.snippet-outline__inner {
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--surface);
    padding: 12px 14px;
    overflow: auto;
    max-height: calc(100vh - 32px);
}

.snippet-outline__title {
    font-size: 0.85em;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    margin: 0 0 8px;
    color: var(--ink-3, var(--ink));
}

.snippet-outline__list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 4px;
}

.snippet-outline__link {
    display: block;
    padding: 4px 6px;
    border-radius: 4px;
    font-family: var(--mono);
    font-size: 12.5px;
    color: var(--ink);
    text-decoration: none;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.snippet-outline__link:hover {
    background: var(--bg);
}

@media (max-width: 960px) {
    .snippet-detail--with-outline {
        grid-template-columns: 1fr;
    }
    .snippet-outline {
        position: static;
        max-height: none;
    }
    .snippet-outline__inner {
        max-height: none;
    }
}

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

.snippet-file {
    border: 1px solid var(--border-strong);
    border-radius: var(--r);
    padding: 10px 12px;
    background: var(--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(--r);
    background: transparent;
    color: var(--ink-4);
    cursor: pointer;
}

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

.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(--border-strong);
    border-radius: var(--r);
    font-family: inherit;
    font-size: 13.5px;
    background: var(--surface);
    color: var(--ink);
}

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

.snippet-file__actions .btn {
    height: 34px;
    padding: 0 10px;
}

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

.snippet-file__content textarea {
    width: 100%;
    padding: 8px 10px;
    border: 1px solid var(--border-strong);
    border-radius: var(--r);
    background: var(--surface);
    color: var(--ink);
    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(--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(--blue);
    box-shadow: 0 0 0 2px var(--blue-50);
}

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

/* ---------- Object Explorer ---------- */
/* Release browser, module/object detail, search filters, results tables. */
.object-explorer__filters {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    align-items: end;
    margin: 16px 0;
}

/* Each filter field grows to share the row evenly; the search box gets a
   double share so it stays the widest. The reset button hugs its content so
   the inputs fill the whole width up to it (instead of an empty grid track
   eating the trailing space). flex-wrap drops fields onto a second row on
   narrow viewports — no media query needed. */
.object-explorer__filters .field { flex: 1 1 180px; min-width: 0; }
.object-explorer__filters .field--search { flex: 2 1 240px; }
.object-explorer__filters .object-explorer__filters-reset { flex: 0 0 auto; }

/* Per-object C/AL Version List, shown under the object name in the results
   table (issue #271). Long; truncated with the full value on hover (title). */
.oe-version-list {
    margin-top: 2px;
    max-width: 360px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-family: var(--mono, "SFMono-Regular", Consolas, monospace);
    font-size: 11px;
}

/* Sortable column headers in the version browser. Keeps the <th>'s
   default look but turns the inner button into a hover-able click target
   with a small arrow on the active sort. */
.data-table__sort-button {
    appearance: none;
    background: transparent;
    border: 0;
    padding: 0;
    margin: 0;
    color: inherit;
    cursor: pointer;
    font: inherit;
    font-weight: inherit;
    text-align: inherit;
    text-transform: inherit;
    letter-spacing: inherit;
}

.data-table__sort-button:hover {
    color: var(--text-1, #d8d8e0);
}

.data-table__sort-button.is-active {
    color: var(--text-1, #d8d8e0);
}

.data-table__sort-indicator {
    font-size: 10px;
    margin-left: 2px;
}

/* `.field` is referenced from a handful of forms but never defined globally
   until now. Stack label + control vertically with consistent spacing so
   the Object Explorer filter row lines up evenly across search inputs and
   select boxes. */
.object-explorer__filters .field {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
}

.object-explorer__filters .field__label {
    font-size: 12.5px;
    font-weight: 600;
    color: var(--text-2, #b0b0c2);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

/* "Include inherited (base) objects" toggle in the filter row. Unlike the
   other fields it carries a checkbox + caption rather than a full-width
   control, so keep it a touch wider and lay the box out inline with its text,
   bottom-aligned with the sibling inputs. */
.object-explorer__filters .object-explorer__inherited-toggle { flex: 1 1 240px; }
.object-explorer__inherited-toggle .oe-checkline {
    display: flex;
    align-items: center;
    gap: 8px;
    min-height: 36px;
    font-size: 13px;
    color: var(--text-2, #b0b0c2);
}
.object-explorer__inherited-toggle .oe-checkline input { flex: 0 0 auto; }

/* Visual styling for the Object Explorer's select boxes — the filter
   row on the version browser and the "Compare with" picker on the file
   header both fall outside the .form-section / .admin-form scopes that
   own the global input styling, so without this they render with
   browser defaults (white background, system font) and clash with the
   dark UI. The .admin-search-input on the filter row already brings
   its own block. */
.object-explorer__filters .field__input,
.object-explorer__compare .field__input,
.source-viewer__compare-picker .field__input {
    width: 100%;
    box-sizing: border-box;
    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);
}

.object-explorer__filters .field__input:focus,
.object-explorer__compare .field__input:focus,
.source-viewer__compare-picker .field__input:focus {
    outline: 2px solid var(--blue);
    outline-offset: -1px;
    border-color: var(--blue);
}

/* Custom chevron on the <select> variants so they read as intentional
   dropdowns rather than carrying the browser-default arrow (which
   ignores our dark/light tokens and looks bolted on). Kept slim: the
   padding-right just makes room for the chevron, the rest of the
   sizing matches the inputs alongside. */
.object-explorer__filters select.field__input,
.object-explorer__compare select.field__input,
.source-viewer__compare-picker select.field__input {
    appearance: none;
    -webkit-appearance: none;
    padding-right: 28px;
    background-image:
        linear-gradient(45deg, transparent 50%, var(--ink-3) 50%),
        linear-gradient(135deg, var(--ink-3) 50%, transparent 50%);
    background-position:
        calc(100% - 14px) 50%,
        calc(100% - 9px) 50%;
    background-size: 5px 5px, 5px 5px;
    background-repeat: no-repeat;
    cursor: pointer;
}
.object-explorer__filters select.field__input:focus,
.object-explorer__compare select.field__input:focus,
.source-viewer__compare-picker select.field__input:focus {
    background-image:
        linear-gradient(45deg, transparent 50%, var(--blue) 50%),
        linear-gradient(135deg, var(--blue) 50%, transparent 50%);
}

.object-explorer__filters .admin-search-input {
    width: 100%;
    box-sizing: border-box;
}

/* The reset button aligns to the bottom of the filter row (no label above
   it), so size it to match the inputs' height instead of the shared 28×28
   .btn--icon square. Width hugs the icon so the inputs keep the rest of the
   row. */
.object-explorer__filters-reset .btn--icon {
    width: auto;
    height: 38px;
    padding: 0 12px;
}

.object-explorer__row {
    cursor: pointer;
}

/* Multi-select "Object type" filter: a <details> disclosure styled as a
   dropdown. The <summary> reuses .field__input chrome; the panel floats over
   the rows below with a scrollable checkbox list. */
.kind-filter {
    position: relative;
}

.kind-filter__summary {
    list-style: none;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

.kind-filter__summary::-webkit-details-marker {
    display: none;
}

.kind-filter__summary::after {
    content: "";
    width: 0;
    height: 0;
    border-left: 4px solid transparent;
    border-right: 4px solid transparent;
    border-top: 5px solid var(--ink-3);
    flex: 0 0 auto;
}

.kind-filter[open] .kind-filter__summary {
    outline: 2px solid var(--blue);
    outline-offset: -1px;
    border-color: var(--blue);
}

.kind-filter__panel {
    position: absolute;
    z-index: 20;
    top: calc(100% + 4px);
    left: 0;
    min-width: 100%;
    max-height: 280px;
    overflow-y: auto;
    padding: 6px;
    border: 1px solid var(--border-strong);
    border-radius: var(--r);
    background: var(--surface);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
}

.kind-filter__option {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 5px 8px;
    border-radius: var(--r);
    font-size: 13px;
    white-space: nowrap;
    cursor: pointer;
}

.kind-filter__option:hover {
    background: var(--bg);
}

/* Fixed column widths on the objects grid so sorting / lazy-loading new rows
   can't reflow the table as the content per page changes. Name + Namespace
   (the two width-less <col>s) share the remaining space; long values wrap
   rather than widen their column. */
.data-table--objects {
    table-layout: fixed;
    width: 100%;
}

.data-table--objects td {
    overflow-wrap: anywhere;
}

/* Type (kind keywords like "reportextension") and ID (negative interface ids
   like -818523667) must never wrap — give them room and keep them single-line. */
.data-table--objects td:first-child,
.data-table--objects td:nth-child(2) {
    white-space: nowrap;
    overflow-wrap: normal;
}

.data-table--objects .col-type { width: 10rem; }
.data-table--objects .col-id { width: 7rem; }
.data-table--objects .col-extension { width: 12rem; }
.data-table--objects .col-lines { width: 5rem; }
.data-table--objects .col-actions { width: 14rem; }

/* ============================================================
   Object Explorer — restyled to the design hand-off
   (.design/translator/styles/screens.css "Object Explorer"). Scoped under
   .object-explorer__browser; keeps the existing markup classes and all four
   search scopes (Objects / Procedures / File content / Compare). The table is
   given a card look WITHOUT overflow:hidden so the row split-button menu
   (absolutely positioned) is never clipped.
   ============================================================ */

/* header */
.object-explorer__browser .admin-page__header h1 {
    font-size: 27px;
    font-weight: 700;
    letter-spacing: -0.5px;
}

/* filter micro-labels → the design's .flabel */
.object-explorer__filters .field__label {
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.8px;
    text-transform: uppercase;
    color: var(--ink-4);
}

/* results table → elevated card. The same look is shared by the admin Object
   Explorer's read-only tables via the .data-table--card modifier, so admin and
   user-facing release tables read as the same component. */
.object-explorer__browser .data-table,
.data-table--card {
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    border-collapse: separate;
    border-spacing: 0;
    box-shadow: var(--shadow);
    background: var(--surface);
}

.object-explorer__browser .data-table thead th,
.data-table--card thead th {
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.8px;
    text-transform: uppercase;
    color: var(--ink-4);
    background: var(--surface-2);
    border-bottom: 1px solid var(--border);
    padding: 12px 16px;
}

.object-explorer__browser .data-table thead th:first-child,
.data-table--card thead th:first-child { border-top-left-radius: var(--r-lg); }
.object-explorer__browser .data-table thead th:last-child,
.data-table--card thead th:last-child { border-top-right-radius: var(--r-lg); }

.object-explorer__browser .data-table tbody td,
.data-table--card tbody td {
    padding: 12px 16px;
    border-bottom: 1px solid var(--border);
    font-size: 13.5px;
    vertical-align: middle;
}

.object-explorer__browser .data-table tbody tr:last-child td,
.data-table--card tbody tr:last-child td { border-bottom: 0; }
.object-explorer__browser .data-table tbody tr,
.data-table--card tbody tr { transition: background 0.1s ease; }
.object-explorer__browser .data-table tbody tr:hover,
.data-table--card tbody tr:hover { background: var(--surface-2); }

/* object cells */
.object-explorer__browser .otype {
    font-family: var(--mono);
    font-size: 11px;
    font-weight: 600;
    text-transform: lowercase;
    padding: 2px 8px;
    border-radius: 5px;
    white-space: nowrap;
    border: 1px solid transparent;
    color: var(--ink-3);
    background: var(--surface-sunken);
}

.object-explorer__browser .otype.codeunit { color: var(--blue-700); background: var(--blue-50); border-color: var(--blue-100); }
.object-explorer__browser .otype.table { color: var(--st-final); background: var(--st-final-bg); }
.object-explorer__browser .otype.page { color: var(--st-untrans); background: var(--st-untrans-bg); }
.object-explorer__browser .otype.report { color: #9333ea; background: color-mix(in srgb, #9333ea 12%, transparent); }
:root[data-theme="dark"] .object-explorer__browser .otype.report { color: #c084fc; }

.object-explorer__browser .oid {
    font-family: var(--mono);
    font-size: 12.5px;
    color: var(--ink-4);
    font-variant-numeric: tabular-nums;
}

.object-explorer__browser .oname { color: var(--blue-700); font-weight: 600; }
.object-explorer__browser .oext { font-size: 12.5px; color: var(--ink-2); }
.object-explorer__browser .ons { font-family: var(--mono); font-size: 12px; color: var(--ink-3); }
.object-explorer__browser .ons .ns-tail { color: var(--ink); }

/* actions column — sized to the split-button, right-aligned */
.object-explorer__browser .oe-cell-actions { text-align: right; white-space: nowrap; }

/* ============================================================
   Object Explorer — landing / release picker
   (.design/explorer-cookbook/styles/screens2.css). Featured "latest import"
   hero + source tabs with counts + version-grouped release cards. Class names
   (rel-*, rh-*, rc-*, rg-*, src-tabs) are unique to this screen.
   ============================================================ */
.oe-landing { max-width: 1280px; }

.oe-landing .page-head { margin-bottom: 22px; }
.oe-landing .page-head h1 { margin: 0; font-size: 27px; font-weight: 700; letter-spacing: -0.5px; }
.oe-landing .page-head .sub { margin: 8px 0 0; color: var(--ink-3); font-size: 14px; max-width: 680px; line-height: 1.55; }

/* source tabs (segmented) */
.src-tabs {
    display: inline-flex;
    gap: 3px;
    margin-bottom: 26px;
    background: var(--surface-sunken);
    border: 1px solid var(--border);
    border-radius: 11px;
    padding: 4px;
}
.src-tabs button {
    appearance: none;
    border: 0;
    background: transparent;
    font: inherit;
    font-size: 13px;
    font-weight: 600;
    color: var(--ink-3);
    padding: 8px 15px;
    border-radius: 8px;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    transition: background 0.12s, color 0.12s, box-shadow 0.12s;
}
.src-tabs button svg { width: 16px; height: 16px; color: var(--ink-4); }
.src-tabs button:hover { color: var(--ink); }
.src-tabs button.on { background: var(--surface); color: var(--ink); box-shadow: var(--shadow-xs); }
.src-tabs button.on svg { color: var(--blue); }
.src-tabs .src-n {
    font-size: 11px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    border-radius: 999px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--surface-sunken);
    color: var(--ink-4);
    border: 1px solid var(--border);
}
.src-tabs button.on .src-n { background: var(--blue-50); color: var(--blue-700); border-color: var(--blue-100); }

/* featured "latest import" hero */
.rel-hero {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 28px;
    align-items: stretch;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-xl);
    box-shadow: var(--shadow);
    overflow: hidden;
    margin-bottom: 30px;
    position: relative;
}
.rel-hero::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 4px;
    background: var(--blue);
}
.rel-hero .rh-main { padding: 26px 28px; display: flex; flex-direction: column; gap: 13px; justify-content: center; }
.rh-cap { display: flex; align-items: center; gap: 12px; }
.rh-title { margin: 0; font-size: 30px; font-weight: 800; letter-spacing: -0.8px; color: var(--ink); line-height: 1; }
.rh-meta { display: flex; align-items: center; gap: 11px; flex-wrap: wrap; font-size: 13px; color: var(--ink-3); }
.rh-meta .mono { color: var(--ink-2); font-size: 12.5px; }
.rh-date { display: inline-flex; align-items: center; gap: 6px; }
.rh-date svg { color: var(--ink-4); }
.rel-hero .rh-side {
    background: var(--surface-2);
    border-left: 1px solid var(--border);
    padding: 24px 28px;
    display: flex;
    flex-direction: column;
    gap: 18px;
    justify-content: center;
    min-width: 280px;
}
.rh-stat { display: flex; flex-direction: column; gap: 3px; }
.rh-num { font-size: 38px; font-weight: 800; color: var(--ink); line-height: 1; letter-spacing: -1.5px; font-variant-numeric: tabular-nums; }
.rh-lbl { font-size: 11px; font-weight: 700; letter-spacing: 0.9px; text-transform: uppercase; color: var(--ink-4); }
.rh-actions { display: flex; gap: 10px; }
.rh-actions .btn { flex: 1; justify-content: center; }

/* hero collapses to a single column on narrow viewports */
@media (max-width: 720px) {
    .rel-hero { grid-template-columns: 1fr; }
    .rel-hero .rh-side { border-left: 0; border-top: 1px solid var(--border); min-width: 0; }
}

.rel-count { font-size: 13px; color: var(--ink-3); margin-bottom: 18px; }
.rel-count b { color: var(--ink); font-variant-numeric: tabular-nums; }

/* Source-repo links under a customer release's title. */
.oe-release-repos { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; margin-top: 2px; }
.oe-release-repos a { word-break: break-all; }

/* Release search box on the Object Explorer landing. */
.rel-search {
    display: flex;
    align-items: center;
    gap: 8px;
    border: 1px solid var(--border-input);
    border-radius: var(--r);
    padding: 0 13px;
    height: 40px;
    margin: 16px 0 18px;
    color: var(--ink-3);
}
.rel-search:focus-within { border-color: var(--blue); color: var(--ink); }
.rel-search input {
    flex: 1 1 auto;
    border: none;
    outline: none;
    background: transparent;
    font-size: 14px;
    color: var(--ink);
    height: 100%;
}

/* version-grouped release cards */
.rel-group { margin-bottom: 8px; }
.rel-group-head { display: flex; align-items: center; gap: 12px; padding: 18px 0 14px; }
.rg-dot { width: 9px; height: 9px; border-radius: 999px; background: var(--blue); box-shadow: 0 0 0 4px var(--blue-50); flex: 0 0 auto; }
.rg-title { font-size: 13px; font-weight: 700; color: var(--ink); letter-spacing: 0.2px; }
.rg-line { flex: 1; height: 1px; background: var(--border); }
.rg-count { font-size: 11.5px; color: var(--ink-4); font-variant-numeric: tabular-nums; }

.rel-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(296px, 1fr)); gap: 14px; }
/* A customer card is a <button> drilling into that customer's releases — fill the grid cell. */
button.rel-card { width: 100%; box-sizing: border-box; }

/* Breadcrumb back to the customer list from one customer's releases. */
.rel-crumb { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; }
.rel-back {
    display: inline-flex; align-items: center; gap: 5px;
    appearance: none; background: none; border: 0; font: inherit; cursor: pointer;
    color: var(--ink-3); padding: 4px 0;
}
.rel-back:hover { color: var(--blue); }
.rel-crumb-title { font-size: 18px; font-weight: 700; color: var(--ink); margin: 0; }
.rel-card {
    appearance: none;
    text-align: left;
    font: inherit;
    text-decoration: none;
    cursor: pointer;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-xs);
    padding: 16px 18px;
    display: flex;
    flex-direction: column;
    gap: 13px;
    transition: border-color 0.14s, box-shadow 0.14s, transform 0.14s;
}
.rel-card:hover { border-color: var(--blue); box-shadow: var(--shadow); transform: translateY(-2px); text-decoration: none; }
.rel-card .rc-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; }
.rel-card .rc-name { font-size: 15px; font-weight: 700; color: var(--ink); letter-spacing: -0.2px; }
.rel-card .rc-ver { font-size: 11.5px; color: var(--ink-3); margin-top: 3px; }
.rel-card .rc-arrow { color: var(--ink-4); transition: transform 0.14s, color 0.14s; flex: 0 0 auto; margin-top: 1px; display: inline-flex; }
.rel-card:hover .rc-arrow { color: var(--blue); transform: translateX(3px); }
.rel-card .rc-foot { display: flex; align-items: center; justify-content: space-between; font-size: 12px; color: var(--ink-3); }
.rc-files b { color: var(--ink); font-variant-numeric: tabular-nums; }
.rc-date { display: inline-flex; align-items: center; gap: 5px; color: var(--ink-4); }

/* Per-extension provenance lines on a customer release card: which extension(s)
   the build produced, with the short commit hash + date that distinguish builds. */
.rc-builds { display: flex; flex-direction: column; gap: 6px; }
.rc-build {
    display: flex;
    align-items: center;
    gap: 7px;
    font-size: 12px;
    color: var(--ink-3);
    min-width: 0;
}
.rc-build > svg { color: var(--ink-4); flex: 0 0 auto; }
.rc-build-name { color: var(--ink-2); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rc-build-commit { display: inline-flex; align-items: center; gap: 6px; margin-left: auto; flex: 0 0 auto; font-size: 11px; color: var(--ink-4); }
.rc-build-sha { color: var(--ink-4); }
.rc-build-date { color: var(--ink-4); }

/* empty state (customer tab / no packages) — also reused by the cookbook */
.rel-empty {
    border: 1px dashed var(--border-strong);
    border-radius: var(--r-xl);
    background: var(--surface-2);
    padding: 52px 32px;
    text-align: center;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 11px;
}
.rel-empty-ico { width: 58px; height: 58px; border-radius: 16px; background: var(--surface); border: 1px solid var(--border); display: grid; place-items: center; color: var(--ink-4); box-shadow: var(--shadow-xs); margin-bottom: 4px; }
.rel-empty-h { font-size: 17px; font-weight: 700; color: var(--ink); }
.rel-empty-p { font-size: 13.5px; color: var(--ink-3); max-width: 460px; line-height: 1.55; margin: 0; }
.rel-empty .btn { margin-top: 8px; }

/* ============================================================
   Shared card + toast + recipe-type badge primitives
   (.design/explorer-cookbook) — used by the Cookbook + Recipe screens.
   ============================================================ */
.card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow);
}
.card-head {
    padding: 13px 16px;
    border-bottom: 1px solid var(--border);
    display: flex;
    align-items: center;
    justify-content: space-between;
}
.card-head .cap-label { margin: 0; }

.toast {
    position: fixed;
    bottom: 22px;
    left: 50%;
    transform: translateX(-50%) translateY(8px);
    background: var(--ink);
    color: #fff;
    padding: 10px 16px;
    border-radius: 10px;
    font-size: 13px;
    font-weight: 500;
    box-shadow: var(--shadow-lg);
    z-index: 90;
    display: flex;
    align-items: center;
    gap: 9px;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.18s, transform 0.18s;
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
.toast svg { width: 16px; height: 16px; color: var(--good); }
:root[data-theme="dark"] .toast { background: #1c2430; border: 1px solid var(--border-strong); color: #f1f5f9; }

.rtype {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex: 0 0 auto;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.4px;
    text-transform: uppercase;
    padding: 4px 10px;
    border-radius: 7px;
}
.rtype svg { width: 13px; height: 13px; }
.rtype.snippet { color: var(--st-trans); background: var(--st-trans-bg); }
.rtype.pattern { color: var(--code-num); background: color-mix(in srgb, var(--code-num) 12%, transparent); }
.rtype.module { color: var(--st-final); background: var(--st-final-bg); }

/* deprecated tag (not in the design study; the app has deprecated recipes) */
.rcd-deprecated,
.rd-deprecated {
    font-size: 11px;
    font-weight: 600;
    color: var(--st-fuzzy);
    background: var(--st-fuzzy-bg);
    border-radius: 999px;
    padding: 2px 9px;
    white-space: nowrap;
}

/* ============================================================
   Cookbook grid
   ============================================================ */
.cookbook { max-width: 1280px; }
.cb-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 24px; margin-bottom: 24px; }
.cb-head h1 { margin: 0; font-size: 27px; font-weight: 700; color: var(--ink); letter-spacing: -0.5px; }
.cb-head .sub { margin: 8px 0 0; color: var(--ink-3); font-size: 14px; max-width: 680px; line-height: 1.55; }
.cb-head .btn { flex: 0 0 auto; }

.cb-toolbar { display: flex; align-items: center; gap: 14px; margin-bottom: 24px; flex-wrap: wrap; }
.cb-search { position: relative; flex: 1; min-width: 260px; }
.cb-search > svg { position: absolute; left: 13px; top: 50%; transform: translateY(-50%); color: var(--ink-4); width: 17px; height: 17px; pointer-events: none; }
.cb-search .input {
    width: 100%;
    height: 40px;
    font: inherit;
    font-size: 14px;
    color: var(--ink);
    background: var(--surface);
    border: 1px solid var(--border-input);
    border-radius: var(--r);
    padding: 0 13px 0 40px;
    outline: none;
    transition: border-color 0.12s, box-shadow 0.12s;
}
.cb-search .input::placeholder { color: var(--ink-4); }
.cb-search .input:focus { border-color: var(--blue); box-shadow: 0 0 0 3px var(--blue-50); }

.cb-pills { display: inline-flex; gap: 8px; }
.cb-pill {
    appearance: none;
    font: inherit;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    padding: 8px 15px;
    border-radius: 9px;
    border: 1px solid var(--border-input);
    background: var(--surface);
    color: var(--ink-2);
    transition: background 0.12s, color 0.12s, border-color 0.12s, box-shadow 0.12s;
}
.cb-pill:hover { background: var(--surface-sunken); }
.cb-pill.on { background: var(--blue); border-color: var(--blue); color: #fff; box-shadow: var(--shadow-xs); }

.cb-toggle { display: inline-flex; align-items: center; gap: 9px; font-size: 13px; color: var(--ink-2); cursor: pointer; user-select: none; }
.cb-toggle input { position: absolute; opacity: 0; width: 0; height: 0; }
.cb-toggle .cbx-box { width: 19px; height: 19px; border-radius: 6px; border: 1.6px solid var(--border-strong); background: var(--surface); display: grid; place-items: center; color: transparent; transition: background 0.12s, border-color 0.12s, color 0.12s; }
.cb-toggle input:checked + .cbx-box { background: var(--blue); border-color: var(--blue); color: #fff; }
.cb-toggle .cbx-box svg { width: 12px; height: 12px; }

.cb-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); gap: 18px; }
.recipe-card {
    appearance: none;
    text-align: left;
    font: inherit;
    text-decoration: none;
    cursor: pointer;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-xs);
    padding: 20px;
    display: flex;
    flex-direction: column;
    gap: 13px;
    transition: border-color 0.14s, box-shadow 0.14s, transform 0.14s;
}
.recipe-card:hover { border-color: var(--blue); box-shadow: var(--shadow); transform: translateY(-2px); text-decoration: none; }
.rcd-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.rcd-min { display: inline-flex; align-items: center; gap: 5px; font-size: 11.5px; color: var(--ink-4); white-space: nowrap; }
.rcd-min svg { color: var(--ink-4); }
.recipe-card h3 { margin: 0; font-size: 16px; font-weight: 700; color: var(--ink); letter-spacing: -0.2px; line-height: 1.3; }
.recipe-card:hover h3 { color: var(--blue-700); }
.rcd-desc {
    margin: 0;
    font-size: 13px;
    color: var(--ink-3);
    line-height: 1.55;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.rcd-tags { display: flex; flex-wrap: wrap; gap: 6px; }
.rcd-tag {
    font-size: 11px;
    color: var(--ink-3);
    background: var(--surface-sunken);
    border: 1px solid var(--border);
    border-radius: 999px;
    padding: 2px 9px;
    white-space: nowrap;
}
.rcd-tag.more { color: var(--ink-4); font-weight: 600; }
.rcd-foot {
    margin-top: auto;
    padding-top: 13px;
    border-top: 1px solid var(--border);
    display: flex;
    align-items: center;
    justify-content: space-between;
    font-size: 12.5px;
    color: var(--ink-3);
}
.rcd-files { display: inline-flex; align-items: center; gap: 6px; }
.rcd-files svg { color: var(--ink-4); }
.rcd-open { display: inline-flex; align-items: center; gap: 5px; color: var(--ink-4); font-weight: 600; transition: gap 0.14s, color 0.14s; }
.recipe-card:hover .rcd-open { color: var(--blue); gap: 8px; }

/* ============================================================
   Recipe detail
   ============================================================ */
.recipe-detail { max-width: 1180px; }
.rd-topbar { display: flex; align-items: center; gap: 12px; margin-bottom: 22px; }
.rd-grid { display: grid; grid-template-columns: 1fr 264px; gap: 32px; align-items: start; }
.rd-main { min-width: 0; }
.rd-head { margin-bottom: 26px; }
.rd-badges { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 13px; }
.rd-min { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--ink-3); }
.rd-min svg { color: var(--ink-4); }
.rd-min .mono { color: var(--ink-4); font-size: 11.5px; }
.rd-head h1 { margin: 0; font-size: 26px; font-weight: 700; color: var(--ink); letter-spacing: -0.5px; line-height: 1.25; }
.rd-desc { margin: 12px 0 0; font-size: 14px; color: var(--ink-2); line-height: 1.6; max-width: 760px; }
.rd-tags { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 16px; }

.rd-instructions { margin-bottom: 26px; }
.rd-instructions-body { font-size: 14px; color: var(--ink-2); line-height: 1.6; max-width: 760px; }
.rd-instructions-body :first-child { margin-top: 0; }
.rd-instructions-body code { font-family: var(--mono); font-size: 12.5px; background: var(--surface-sunken); border: 1px solid var(--border); border-radius: 5px; padding: 1px 5px; }

.rd-files-h { display: flex; align-items: center; gap: 10px; margin-bottom: 14px; }
.rd-files-h .cap-label { margin: 0; }
.rd-files-n { font-size: 12px; color: var(--ink-4); font-variant-numeric: tabular-nums; }

/* code block */
.codeblock { border: 1px solid var(--border); border-radius: var(--r-lg); overflow: hidden; background: var(--surface); box-shadow: var(--shadow-xs); margin-bottom: 18px; }
.cb-bar { display: flex; align-items: center; justify-content: space-between; padding: 9px 12px 9px 10px; background: var(--surface-2); border-bottom: 1px solid var(--border); }
.codeblock.collapsed .cb-bar { border-bottom: 0; }
.cb-name {
    appearance: none;
    border: 0;
    background: transparent;
    font: inherit;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-family: var(--mono);
    font-size: 12.5px;
    font-weight: 600;
    color: var(--ink);
    min-width: 0;
}
.cb-name .mono { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cb-name .chev { color: var(--ink-4); display: inline-flex; transition: transform 0.15s; }
.codeblock.collapsed .cb-name .chev { transform: rotate(-90deg); }
.cb-name > svg { width: 15px; height: 15px; flex: 0 0 auto; }
.cb-name .cb-lines { font-family: var(--sans); font-size: 11px; font-weight: 500; color: var(--ink-4); margin-left: 4px; white-space: nowrap; flex: 0 0 auto; }
.cb-copy {
    appearance: none;
    font: inherit;
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 11px;
    border-radius: 7px;
    border: 1px solid var(--border-input);
    background: var(--surface);
    color: var(--ink-2);
    transition: background 0.12s, color 0.12s, border-color 0.12s;
    flex: 0 0 auto;
}
.cb-copy:hover { background: var(--surface-sunken); color: var(--ink); }
.cb-copy svg { color: var(--ink-4); }
.cb-copy:hover svg { color: var(--blue); }

.cb-body { overflow-x: auto; background: var(--surface); }
/* white-space:normal on pre/code so the inter-row whitespace this is rendered
   with doesn't add blank lines; .cl-c keeps the code's own spacing (pre). */
.cb-body pre { margin: 0; white-space: normal; }
.cb-body code { display: block; font-family: var(--mono); font-size: 12.5px; line-height: 1.7; padding: 12px 0; white-space: normal; }
.cb-body .cl { display: grid; grid-template-columns: 46px 1fr; }
.cb-body .cl-n { text-align: right; padding-right: 16px; color: var(--ink-4); opacity: 0.65; user-select: none; font-variant-numeric: tabular-nums; }
.cb-body .cl-c { white-space: pre; padding-right: 20px; color: var(--ink-2); }

.tok-kw { color: var(--blue-700); font-weight: 600; }
.tok-type { color: var(--code-type); }
.tok-str { color: var(--st-final); }
.tok-id { color: var(--st-fuzzy); }
.tok-num { color: var(--code-num); }
.tok-com { color: var(--ink-4); font-style: italic; }
.tok-punc, .tok-txt { color: var(--ink-2); }

/* recipe rail */
.rd-rail { position: sticky; top: 30px; display: flex; flex-direction: column; gap: 16px; }
.rail-files { padding: 8px; display: flex; flex-direction: column; gap: 2px; }
.rail-file {
    appearance: none;
    font: inherit;
    text-align: left;
    text-decoration: none;
    cursor: pointer;
    width: 100%;
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 8px 10px;
    border-radius: 8px;
    border: 0;
    background: transparent;
    color: var(--ink-2);
    font-family: var(--mono);
    font-size: 11.5px;
    transition: background 0.12s, color 0.12s;
}
.rail-file svg { color: var(--ink-4); flex: 0 0 auto; }
.rail-file .rf-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rail-file:hover { background: var(--surface-sunken); color: var(--ink); text-decoration: none; }
.rail-file.on { background: var(--blue-50); color: var(--blue-700); }
.rail-file.on svg { color: var(--blue); }

.rd-meta {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow);
    padding: 16px;
    display: flex;
    flex-direction: column;
    gap: 13px;
}
.rdm-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; font-size: 12.5px; color: var(--ink-3); }
.rdm-row b { color: var(--ink); }
.rdm-row b.mono { font-size: 11.5px; }
.rd-download { width: 100%; justify-content: center; margin-top: 4px; }

@media (max-width: 980px) {
    .rd-grid { grid-template-columns: 1fr; }
    .rd-rail { position: static; flex-direction: row; flex-wrap: wrap; }
    .rd-rail > * { flex: 1; min-width: 240px; }
}


/* Bottom-of-list sentinel that triggers the next lazy-load page. */
.oe-scroll-sentinel {
    padding: 12px 0;
    text-align: center;
    font-size: 12.5px;
}

/* "Show more" control for ranked (search) results — the match set is already
   in memory, so this just reveals the next batch of rows rather than fetching.
   Centered to read as the end-of-list affordance, like the scroll sentinel. */
.oe-show-more {
    padding: 12px 0;
    text-align: center;
}

/* Version-compare page sections — each kind of change gets its own
   block under a small heading. Spaced apart so the eye doesn't bleed
   between added / removed / changed rows. */
/* Header trailing block on the version browser — pulls the
   "Compare with" picker and the "All versions" link together so they
   sit on the right side of the page header without fighting the title
   block on narrow widths. */
.object-explorer__header-actions {
    display: flex;
    align-items: end;
    gap: 12px;
    flex-wrap: wrap;
}

.version-compare__section {
    margin: 18px 0;
}
.version-compare__section h2 {
    font-size: 13px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-2, #b0b0c2);
    margin: 0 0 8px;
    display: flex;
    align-items: baseline;
    gap: 8px;
}

/* Status pill on the right end of each compare row. Colours intentionally
   muted — these aren't action buttons, they're metadata. */
.version-compare__badge {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 3px;
    font-size: 11.5px;
    font-weight: 600;
    text-transform: lowercase;
    letter-spacing: 0.02em;
}
.version-compare__badge--added {
    background: color-mix(in srgb, #2ea043 22%, transparent);
    color: #4cd067;
}
.version-compare__badge--removed {
    background: color-mix(in srgb, #f85149 22%, transparent);
    color: #ff8a82;
}
.version-compare__badge--changed {
    background: color-mix(in srgb, #d29922 22%, transparent);
    color: #ecbe4b;
}

.object-explorer__row:hover {
    background: var(--surface-hover, rgba(124, 124, 144, 0.08));
}

.object-explorer__type {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 3px;
    background: var(--surface-2, rgba(124, 124, 144, 0.12));
    color: var(--text-2, #b0b0c2);
    font-size: 11.5px;
    font-weight: 600;
    text-transform: lowercase;
    letter-spacing: 0.02em;
}

.object-explorer__crumbs {
    display: flex;
    gap: 6px;
    align-items: center;
    font-size: 13px;
    color: var(--text-2, #b0b0c2);
    margin-bottom: 12px;
}

.object-explorer__crumbs a {
    color: var(--text-2, #b0b0c2);
    text-decoration: none;
}

.object-explorer__crumbs a:hover {
    text-decoration: underline;
}

.object-explorer__file-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    gap: 16px;
    margin-bottom: 12px;
}

.object-explorer__file-header h1 {
    display: flex;
    gap: 10px;
    align-items: baseline;
    margin: 0;
}

.object-explorer__compare {
    min-width: 240px;
}

.object-explorer__row-actions {
    display: flex;
    gap: 6px;
    align-items: center;
    flex-wrap: wrap;
}

/* When the row-actions live in their own <td>, keep the cell tight so
   the column doesn't claim a third of the table width. width: 1%
   collapses the cell to its content; nowrap keeps the buttons on one
   line even when there's room. */
.object-explorer__row-actions--cell {
    width: 1%;
    white-space: nowrap;
}

/* Suffix shown after the symbol name on the procedure-search rows —
   reads as a muted "(signature)" hint that doesn't compete with the
   name. Truncated by the parent <td>'s overflow on narrow viewports. */
.object-explorer__row-sig {
    margin-left: 6px;
    font-family: var(--mono, ui-monospace, "SF Mono", Menlo, Consolas, monospace);
}

/* Snippet column on the content-search results table. Trimmed to a
   single line + ellipsis so a 200-char line doesn't blow up the row
   height; the row click + the link both navigate to the matching
   line in the file viewer, so seeing the start is enough. */
.object-explorer__row-snippet {
    display: block;
    max-width: 70ch;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 12.5px;
}

/* Upload form: native file inputs are ugly and inconsistent across browsers.
   Hide the input visually and let the <label for=...> button stand in.
   `.file-picker__status` gets the filename(s) written by the page script. */
.object-explorer-upload .file-picker {
    display: inline-flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
}

.object-explorer-upload .file-picker input[type="file"] {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    border: 0;
}

.object-explorer-upload .file-picker__button {
    cursor: pointer;
}

.object-explorer-upload .file-picker__status {
    font-size: 13px;
}

.object-explorer-upload .field {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-bottom: 16px;
}

/* Generic `.field` layout — admin forms that pair a label, an input, and a
   short caption use this triplet of classes. The Object Explorer filter
   bars and the legacy upload form each defined their own scoped versions
   above; this block makes the same layout available to any admin page
   (specifically the Release import form) without a parent-class
   gymnastics step. Input styling (border, padding, focus ring) still
   comes from the `.form-section input[type="…"]` rules earlier in this
   file, which already match by descendant. */
.field {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-bottom: 16px;
    min-width: 0;
}

/* Respect the `hidden` attribute — the display:flex above would otherwise beat
   the UA `[hidden] { display: none }`, leaving JS-toggled fields visible. */
.field[hidden] {
    display: none;
}

.field__label {
    font-size: 12.5px;
    font-weight: 600;
    color: var(--text-2, #b0b0c2);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.field__caption {
    font-size: 12.5px;
    line-height: 1.4;
}

/* Search-mode tabs on the Release detail page. Mirrors the legacy
   VersionBrowser's segmented control — three options, single-select, the
   active one carries a brighter background. */
.oe-search-tabs {
    display: inline-flex;
    border: 1px solid var(--border-strong);
    border-radius: var(--r);
    overflow: hidden;
    margin-bottom: 16px;
}

.oe-search-tab {
    background: transparent;
    border: 0;
    padding: 6px 14px;
    color: var(--text-2, #b0b0c2);
    font: inherit;
    font-size: 13px;
    cursor: pointer;
    border-right: 1px solid var(--border-strong);
}

.oe-search-tab:last-child {
    border-right: 0;
}

.oe-search-tab:hover {
    background: rgba(124, 124, 144, 0.08);
}

.oe-search-tab--active {
    background: var(--blue, #ffd54f);
    color: var(--bg, #1a1a26);
    font-weight: 600;
}

/* ---------- Source-file viewer ---------- */
/* SourceFileViewer.razor — IDE-style layout: page header pinned at top,
   code area scrolls inside the cm-editor, the outline is always next to
   it. The page itself doesn't scroll (height: 100% inside .content's
   bounded scrollport) — that's the pattern users expect from a code
   viewer. Narrow viewports drop
   back to the page-scroll behaviour because internal scrolling
   feels cramped on small screens. */
.source-viewer {
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 0;
}

.source-viewer > .admin-page__header {
    flex: 0 0 auto;
}

.source-viewer__layout {
    display: flex;
    align-items: stretch;
    flex: 1 1 0;
    min-height: 0;
    gap: 0;
}

/* Drag handle between the editor column and the outline. Stretches the
   full height of the layout; the JS handler updates a CSS custom
   property (`--source-viewer-outline-width`) on the layout root, which
   the outline reads from `.source-viewer__outline-inner` so the resize
   stays cheap (no React-style relayout, just the two columns flexing).
   The hover hairline matches the toolbar accent colour so the handle
   feels discoverable without dominating the layout. */
.source-viewer__resizer {
    flex: 0 0 12px;
    cursor: col-resize;
    position: relative;
    user-select: none;
    /* Layout breathing room — visually equivalent to the previous gap
       of 12px so existing screenshots still line up. */
    margin: 0 4px;
}

.source-viewer__resizer::before {
    content: "";
    position: absolute;
    inset: 0 5px;
    border-radius: 2px;
    background: transparent;
    transition: background 80ms ease-out;
}

.source-viewer__resizer:hover::before,
.source-viewer__resizer.is-dragging::before {
    background: var(--blue);
    opacity: 0.55;
}

@media (max-width: 1100px) {
    .source-viewer {
        height: auto;
        min-height: 100%;
    }
    .source-viewer__layout {
        flex: 0 0 auto;
        flex-direction: column;
    }
    .source-viewer__code .cm-editor {
        height: auto;
    }
    .source-viewer__outline-inner {
        height: auto;
        max-height: calc(100vh - var(--top-h, 52px) - 36px);
    }
    /* The drag handle only makes sense in the side-by-side layout. */
    .source-viewer__resizer {
        display: none;
    }
}

.source-viewer__code {
    flex: 1 1 0;
    min-width: 0;
    min-height: 0;
    /* Match the outline column's framed look — same border, same
       corner radius, same surface. overflow:hidden also clips the
       cm-editor's rounded corners so the editor body, search panel
       and bottom status bar all sit inside the rounded box.
       CodeMirror's own cm-scroller handles horizontal scrolling. */
    overflow: hidden;
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow);
    background: var(--surface);
}

/* Bound cm-editor to the code column's height so cm-scroller actually
   scrolls instead of letting the file extend off the page. The
   editor's own border is suppressed — the wrapper carries the frame
   so the inner gutter/scroller live edge-to-edge inside the radius. */
.source-viewer__code .cm-editor {
    height: 100%;
    border: 0;
    border-radius: inherit;
    background: transparent;
}

.source-viewer__outline {
    /* Width is driven by --source-viewer-outline-width on the layout
       root; the drag handler updates that and the column flexes here.
       The clamp matches what the JS handler enforces, duplicated here
       so a stale localStorage value still renders a usable column. */
    flex: 0 0 auto;
    align-self: stretch;
    display: flex;
    flex-direction: column;
    width: clamp(220px,
                 var(--source-viewer-outline-width, 340px),
                 720px);
}

.source-viewer__outline-inner {
    /* Width is driven by the layout's --source-viewer-outline-width
       custom property, set by the drag-handle JS handler. The fallback
       (340px) matches the previous default when JS hasn't loaded or
       the user hasn't dragged yet. The two boundaries keep the column
       readable while still letting the editor have space; the drag
       handler clamps to the same range. */
    width: 100%;
    height: 100%;
    overflow-y: auto;
    overflow-x: hidden;
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow);
    padding: 12px 14px;
    background: var(--surface);
}


/* ── Tab strip ───────────────────────────────────────────────── */

.source-viewer__tabs {
    display: flex;
    gap: 4px;
    margin: 0 0 12px 0;
    padding: 0 0 4px 0;
    border-bottom: 1px solid var(--border-strong);
}

.source-viewer__tab {
    flex: 0 0 auto;
    padding: 6px 10px;
    background: transparent;
    border: none;
    border-bottom: 2px solid transparent;
    color: var(--ink-3);
    font: inherit;
    font-size: 12.5px;
    font-weight: 500;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.source-viewer__tab:hover {
    color: var(--ink);
}

.source-viewer__tab.is-active {
    color: var(--ink);
    border-bottom-color: var(--blue);
}

.source-viewer__tab[hidden] {
    display: none;
}

/* Right-anchor the Help tab so it sits opposite the navigational tabs. */
.source-viewer__tab--end {
    margin-left: auto;
}

.source-viewer__help {
    margin: 4px 0 0 0;
    font-size: 13px;
    line-height: 1.5;
}

.source-viewer__help dt {
    margin-top: 10px;
    font-weight: 600;
    color: var(--ink);
}

.source-viewer__help dt:first-of-type {
    margin-top: 0;
}

.source-viewer__help dd {
    margin: 2px 0 0 0;
    color: var(--ink-4);
}

.source-viewer__help kbd {
    display: inline-block;
    padding: 1px 6px;
    border-radius: 4px;
    border: 1px solid var(--border-strong);
    background: var(--surface-2, rgba(124, 124, 144, 0.12));
    font-family: var(--mono);
    font-size: 11.5px;
    line-height: 1.4;
}

.source-viewer__tab-count {
    display: inline-block;
    min-width: 18px;
    padding: 0 5px;
    background: var(--surface-2);
    border-radius: 999px;
    font-size: 10.5px;
    text-align: center;
    color: var(--ink-3);
}

.source-viewer__panel {
    display: none;
}

.source-viewer__panel.is-active {
    display: block;
}

.source-viewer__outline h2 {
    margin: 0 0 8px 0;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--text-2, #b0b0c2);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

/* Matches the global form-input styling so the filter doesn't feel
   foreign next to the rest of the app's text inputs. Same padding,
   border, radius and background as <c>.admin-form input[type="text"]</c>;
   only the bottom margin is panel-specific. */
.source-viewer__outline-filter,
.source-viewer__refs-filter {
    width: 100%;
    box-sizing: border-box;
    padding: 8px 10px;
    margin: 0 0 10px 0;
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: var(--r);
    color: var(--ink);
    font-family: inherit;
    font-size: 13.5px;
}

.source-viewer__outline-filter::placeholder,
.source-viewer__refs-filter::placeholder {
    color: var(--ink-4);
}

.source-viewer__outline-filter:focus,
.source-viewer__refs-filter:focus {
    outline: 2px solid var(--blue);
    outline-offset: -1px;
    border-color: var(--blue);
}

.source-viewer__outline-section + .source-viewer__outline-section {
    margin-top: 8px;
}

.source-viewer__outline-section-toggle {
    display: flex;
    align-items: baseline;
    gap: 6px;
    width: 100%;
    margin: 0;
    padding: 4px 0;
    background: none;
    border: 0;
    color: var(--text-2, #b0b0c2);
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    cursor: pointer;
    text-align: left;
}

.source-viewer__outline-section-toggle:hover {
    color: var(--text-1, #e6e6f0);
}

.source-viewer__outline-section-chevron {
    display: inline-block;
    width: 10px;
    transition: transform 80ms ease-out;
    transform: rotate(0deg);
    font-size: 13px;
    line-height: 1;
}

.source-viewer__outline-section-chevron.is-open {
    transform: rotate(90deg);
}

.source-viewer__outline-section-title {
    flex: 0 0 auto;
}

.source-viewer__outline-section-count {
    color: var(--text-3, #7a7a8a);
    font-weight: 500;
}

.source-viewer__outline-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.source-viewer__outline-item {
    line-height: 1.5;
    /* 13px (not 14) so the JetBrains Mono symbol names sit at the same
       apparent size as the editor's code, which renders in the system
       monospace face — JetBrains Mono is visibly larger at a given px. */
    font-size: 13px;
}

.source-viewer__outline-item--child {
    padding-left: 16px;
}

.source-viewer__outline-item a,
.source-viewer__outline-item .source-viewer__outline-link {
    text-decoration: none;
    display: flex;
    align-items: baseline;
    gap: 6px;
    padding: 1px 0;
    /* Rows fit the panel width — long names truncate with ellipsis on
       the .source-viewer__outline-sig span. The user can widen the
       panel via the resize handle on the outline-inner to see more. */
    width: 100%;
    min-width: 0;
    box-sizing: border-box;
    overflow: hidden;
}

/* Same-file outline rows render as <button> instead of <a> so the
   click handler can bypass Blazor's enhanced-nav pipeline and
   update the URL via history.replaceState — Nav.NavigateTo's
   streaming diff strips CodeMirror's runtime-injected style tags.
   Strip the default button chrome so the row stays visually
   identical to the anchor variant used for cross-page object jumps. */
.source-viewer__outline-link {
    background: none;
    border: 0;
    cursor: pointer;
    color: inherit;
    font: inherit;
    text-align: left;
}

.source-viewer__outline-link:hover .source-viewer__outline-name {
    text-decoration: underline;
}

.source-viewer__outline-name {
    /* AL identifiers in monospace — matches the editor's font and keeps
       parameter signatures visually aligned. Names truncate with
       ellipsis when the panel isn't wide enough; the row's title
       attribute carries the full text on hover, and the resize handle
       on .source-viewer__outline-inner lets the user widen the panel
       to see more. */
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-family: var(--mono);
}

.source-viewer__outline-sig {
    /* The signature is the one column allowed to elide. flex: 1 1 0
       + min-width: 0 lets it shrink to nothing so the line number
       and (when needed) the next row's name stay aligned. The full
       text always sits on the row's title attribute. */
    flex: 1 1 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-family: var(--mono);
    font-size: 13px;
    min-width: 0;
}

.source-viewer__outline-line {
    flex: 0 0 auto;
    margin-left: auto;
    padding-left: 8px;
    font-size: 13px;
    font-variant-numeric: tabular-nums;
    color: var(--text-3, #7a7a8a);
}

/* Kind badge — IDE-style pill next to each outline row. The label
   indicates what kind of symbol the row represents (field, trigger,
   procedure, etc.); the colour tint groups related kinds so the eye
   can scan a long list quickly. Full kind name lives on the row's
   title attribute for hover. */
.source-viewer__outline-badge {
    flex: 0 0 auto;
    display: inline-block;
    padding: 1px 6px;
    border-radius: 3px;
    font-family: var(--mono);
    font-size: 10.5px;
    font-weight: 500;
    letter-spacing: 0.02em;
    text-transform: lowercase;
    line-height: 1.4;
    color: var(--ink);
    background: var(--surface-2, rgba(124, 124, 144, 0.12));
    border: 1px solid var(--border, rgba(124, 124, 144, 0.2));
    white-space: nowrap;
}

.source-viewer__outline-badge--field {
    background: rgba(75, 139, 255, 0.14);
    border-color: rgba(75, 139, 255, 0.35);
    color: #6ba3ff;
}

.source-viewer__outline-badge--action {
    background: rgba(255, 184, 64, 0.16);
    border-color: rgba(255, 184, 64, 0.4);
    color: #f0b85a;
}

.source-viewer__outline-badge--trigger {
    background: rgba(76, 201, 114, 0.14);
    border-color: rgba(76, 201, 114, 0.35);
    color: #4cc972;
}

.source-viewer__outline-badge--event {
    background: rgba(229, 159, 64, 0.16);
    border-color: rgba(229, 159, 64, 0.4);
    color: #f0a85a;
}

.source-viewer__outline-badge--label {
    /* Cyan family — distinct from fields (blue), procedures (purple),
       and triggers/events (green/orange). Labels show up frequently in
       large codeunits and benefit from being visually separable so a
       developer triangulating a customer-reported error string can
       spot them at a glance. */
    background: rgba(80, 190, 200, 0.16);
    border-color: rgba(80, 190, 200, 0.4);
    color: #6ec9d2;
}

.source-viewer__outline-badge--proc {
    background: rgba(186, 134, 255, 0.16);
    border-color: rgba(186, 134, 255, 0.4);
    color: #c39bff;
}

.source-viewer__outline-badge--object {
    background: rgba(124, 124, 144, 0.18);
    border-color: rgba(124, 124, 144, 0.4);
    color: var(--ink-3);
}

.source-viewer__outline-find-heading {
    margin-top: 16px;
    padding-top: 12px;
    border-top: 1px solid var(--border-strong);
}

.source-viewer__find-list {
    list-style: none;
    margin: 0 0 12px 0;
    padding: 0;
}

.source-viewer__find-list li {
    line-height: 1.4;
    padding: 2px 0;
}

.source-viewer__find-list a,
.source-viewer__find-list .source-viewer__outline-link {
    text-decoration: none;
    display: flex;
    gap: 6px;
    align-items: baseline;
}

.source-viewer__find-snippet {
    font-size: 11.5px;
    color: var(--text-2, #b0b0c2);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.source-viewer__notice {
    margin-top: 12px;
    padding: 8px 10px;
    border: 1px dashed var(--border-strong);
    border-radius: var(--r);
    font-size: 12.5px;
}

/* Floating notice toast (`showFloatingToast` in source-viewer.js). Sits
   under the user's mouse so feedback for in-editor gestures ("No
   definition found", "Couldn't reach the server") doesn't slip below
   the viewport in the way the bottom-of-outline notice did. Fixed
   positioning + a z-index above the editor's gutter so it always
   floats on top. */
.source-viewer__toast {
    position: absolute;
    z-index: 1000;
    max-width: 320px;
    padding: 8px 12px;
    background: var(--surface-2, #262a30);
    color: var(--ink, #e6e7ea);
    border: 1px solid var(--border-strong, #3a3e47);
    border-radius: var(--r, 6px);
    box-shadow: 0 4px 16px var(--shadow-color, rgba(0, 0, 0, 0.4));
    font-size: 12.5px;
    line-height: 1.4;
    pointer-events: none;
}

.source-viewer__refs-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 8px;
}

.source-viewer__refs-target {
    margin: 0;
    flex: 1 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.source-viewer__refs-close {
    flex: 0 0 auto;
}

.source-viewer__refs-list {
    list-style: none;
    margin: 8px 0 0 0;
    padding: 0;
}

.source-viewer__refs-item {
    padding: 2px 0;
    line-height: 1.4;
}

/* Whole row is wrapped in <a> for keyboard / middle-click navigation.
   Kill the default accent colour on the link itself — the kind badge
   carries the "what is this" signal now, and the row's text should sit
   as body copy, not as a wall of blue. The hover background keeps the
   row feeling clickable. */
.source-viewer__refs-item a {
    text-decoration: none;
    display: block;
    padding: 6px 8px;
    border-radius: var(--r);
    color: var(--ink);
}

.source-viewer__refs-item a:hover {
    background: var(--surface-sunken);
}

.source-viewer__refs-item a:hover .source-viewer__refs-name {
    text-decoration: underline;
}

/* Refs groups borrow the outline-section chevron + heading styles for
   collapsibility. The vertical rhythm between groups matches the
   outline panel so the two read as a paired pattern. */
.source-viewer__refs-group + .source-viewer__refs-group {
    margin-top: 8px;
}

.source-viewer__refs-group:not(.is-open) .source-viewer__refs-list {
    display: none;
}

/* Member sub-row: indented under the object-row so the visual hierarchy
   reads object → member → call-site snippet. Badge keeps the row in sync
   with the outline pane's chip vocabulary (proc / local / trigger / …). */
.source-viewer__refs-member-row {
    display: flex;
    gap: 6px;
    align-items: baseline;
    margin-top: 3px;
    margin-left: 4px;
    min-width: 0;
}

.source-viewer__refs-member-name {
    font-family: var(--mono);
    font-size: 12.5px;
    color: var(--ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
    flex: 1 1 auto;
}

/* Outline right-click menu — one-item popover for Find references on a
   procedure / field / trigger / object row. Positioned by JS at the
   click point. */
.source-viewer__outline-menu {
    position: fixed;
    z-index: 100;
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: var(--r);
    box-shadow: 0 4px 12px var(--shadow-color, rgba(0, 0, 0, 0.4));
    padding: 4px 0;
    min-width: 180px;
}

.source-viewer__outline-menu-item {
    display: block;
    width: 100%;
    padding: 6px 12px;
    background: transparent;
    border: 0;
    color: var(--ink);
    font: inherit;
    font-size: 12.5px;
    text-align: left;
    cursor: pointer;
}

.source-viewer__outline-menu-item:hover {
    background: var(--surface-2, rgba(124, 124, 144, 0.12));
}

/* Object-row: badge + name on the left, module/line meta pinned right.
   Tabular row layout means the eye scans the badge column first, then the
   name, then drifts right for the location — same rhythm as the outline. */
.source-viewer__refs-row-top {
    display: flex;
    gap: 6px;
    align-items: baseline;
}

.source-viewer__refs-line {
    flex: 0 0 auto;
    font-size: 11px;
    font-family: var(--mono, "SFMono-Regular", Consolas, monospace);
}

.source-viewer__refs-snippet {
    display: block;
    margin-top: 4px;
    margin-left: 4px;
    font-family: var(--mono, "SFMono-Regular", Consolas, monospace);
    font-size: 12px;
    color: var(--ink-3);
    background: var(--surface-2);
    padding: 3px 8px;
    border-left: 2px solid var(--border-strong);
    border-radius: 0 3px 3px 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.source-viewer__refs-item.is-current a {
    background: var(--blue-50, rgba(99, 102, 241, 0.15));
    font-weight: 500;
}

.source-viewer__refs-name {
    font-family: var(--mono, "SFMono-Regular", Consolas, monospace);
    font-size: 13px;
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
    flex: 1 1 auto;
}

/* Hover-only tooltip for a refs row. Stays out of the document flow —
   appended to <body> by source-viewer.js so the row can stay visually
   tight while the extension / file path / kind details surface on
   demand. */
.source-viewer__refs-tooltip {
    position: absolute;
    z-index: 200;
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: var(--r);
    box-shadow: 0 6px 18px var(--shadow-color);
    padding: 8px 10px;
    font-size: 12px;
    line-height: 1.45;
    color: var(--ink);
    pointer-events: none;
}

.source-viewer__refs-tooltip[hidden] {
    display: none;
}

.source-viewer__refs-tooltip-where {
    font-weight: 600;
    margin-bottom: 2px;
}

.source-viewer__refs-tooltip-loc {
    font-family: var(--mono);
    font-size: 11.5px;
    color: var(--ink-3);
    word-break: break-all;
}

.source-viewer__refs-tooltip-member {
    margin-top: 6px;
    font-family: var(--mono);
    font-size: 11.5px;
}

.source-viewer__refs-tooltip-kind {
    margin-top: 6px;
    font-size: 11px;
}
.source-viewer__body {
    padding: 0;
    margin: 0;
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: var(--r);
    overflow-x: auto;
    max-height: calc(100vh - 220px);
    overflow-y: auto;
}

.source-viewer__body > code {
    display: block;
    font-family: var(--mono, "SFMono-Regular", Consolas, monospace);
    font-size: 12.5px;
    line-height: 1.5;
}

.source-viewer__line {
    display: grid;
    grid-template-columns: 4rem 1fr;
    gap: 12px;
    padding: 0 12px;
    white-space: pre;
}

.source-viewer__line:hover {
    background: rgba(124, 124, 144, 0.08);
}

.source-viewer__line--hit {
    background: rgba(255, 213, 79, 0.14);
    border-left: 3px solid var(--blue, #ffd54f);
    padding-left: 9px;
}

.source-viewer__lineno {
    text-align: right;
    color: var(--text-2, #b0b0c2);
    user-select: none;
}

.source-viewer__text {
    white-space: pre;
}

.object-explorer-upload .field__label {
    font-size: 12.5px;
    font-weight: 600;
    color: var(--text-2, #b0b0c2);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.object-explorer-upload .form-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 16px;
}

/* The default `display: none` on `[hidden]` would normally hide this
   panel, but specifying `display: flex` unconditionally would beat
   that. Scope the flex layout to the visible state instead so the
   `hidden` attribute keeps working as a plain on/off toggle. */
.upload-progress:not([hidden]) {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-top: 16px;
    padding: 12px 16px;
    background: var(--surface-2, rgba(124, 124, 144, 0.08));
    border: 1px solid var(--border, #2a2a35);
    border-radius: 6px;
}

.upload-progress p {
    margin: 0;
}

.upload-progress__spinner {
    width: 18px;
    height: 18px;
    border: 2px solid var(--border, #2a2a35);
    border-top-color: var(--text-1, #d8d8e0);
    border-radius: 50%;
    animation: upload-spin 0.8s linear infinite;
    flex-shrink: 0;
}

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

/* When the upload is in flight: visually lock down the form so the user
   knows input is captured and that re-clicking is a no-op. Pointer
   events are blocked on the inputs section (everything inside
   .form-section), while the progress panel and its parent form-actions
   stay interactive enough to read but not re-submit. The submit
   button itself carries .btn--loading + the disabled attribute. */
.object-explorer-upload.is-uploading .form-section {
    opacity: 0.55;
    pointer-events: none;
    user-select: none;
}

/* Disabled buttons get a visual cue too — the .btn class doesn't have a
   :disabled rule anywhere else and the browser default barely dims it,
   so the user thinks the click didn't take. Applies globally; nothing
   else relies on disabled buttons looking active. */
.btn:disabled,
.btn[disabled],
.btn[aria-disabled="true"] {
    opacity: 0.55;
    cursor: not-allowed;
}

/* Diff line decorations applied by CodeMirror's Decoration.line(). Selectors
   live in the global stylesheet (not the scoped CodeDiffViewer.razor.css)
   because CodeMirror renders .cm-line outside the Blazor component's scope-id
   wrapper, so ::deep can't reach it. */
.cm-line--diff-added { background: rgba(46, 160, 67, 0.18); }
.cm-line--diff-removed { background: rgba(248, 81, 73, 0.18); }
.cm-line--diff-modified { background: rgba(210, 153, 34, 0.18); }

/* Click affordances on Object Explorer tokens.
   - cm-symbol-decl (procedure / field / object-header *declarations*):
     solid underline at half opacity. The name is "the source" — hover
     keeps the same line but brightens for an explicit "yes, this is
     clickable" signal.
   - cm-symbol-ref (call / field-access *reference sites*): dotted
     underline. Reads as a hyperlink — the user expects to follow it
     somewhere. Hover brightens to mirror the link affordance.
   Both get cursor: pointer so the hand confirms interactivity before
   the user even needs the underline to read. */
.cm-symbol-decl,
.cm-symbol-ref {
    cursor: pointer;
    text-decoration-color: color-mix(in srgb, currentColor 45%, transparent);
    text-underline-offset: 3px;
    transition: text-decoration-color 80ms ease-out;
}
.cm-symbol-decl {
    text-decoration: underline solid currentColor;
}
.cm-symbol-ref {
    text-decoration: underline dotted currentColor;
}
.cm-symbol-decl:hover,
.cm-symbol-ref:hover {
    text-decoration-color: currentColor;
}

/* When the user holds Cmd/Ctrl over the editor, hint that identifier-
   shaped tokens are clickable for "Go to definition". We can't pre-
   resolve which tokens have a target without running a parser, so this is
   an honest "anything could be navigable" affordance — the click itself
   does the resolution. The selectors hit CodeMirror's syntax-highlight
   tok-* classes plus our declaration marks. */
.cm-modifier-down,
.cm-modifier-down .cm-line {
    cursor: pointer;
}
.cm-modifier-down .tok-variableName,
.cm-modifier-down .tok-typeName,
.cm-modifier-down .tok-propertyName,
.cm-modifier-down .tok-className,
.cm-modifier-down .tok-keyword,
.cm-modifier-down .cm-symbol-decl,
.cm-modifier-down .cm-symbol-ref {
    text-decoration: underline;
    text-decoration-style: solid;
    text-decoration-color: currentColor;
    text-underline-offset: 2px;
}

.cm-symbol-menu {
    position: fixed;
    z-index: 1000;
    background: var(--surface-1, #1a1c22);
    border: 1px solid var(--border, #2a2a35);
    border-radius: 6px;
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.25);
    padding: 4px;
    min-width: 160px;
    font-size: 13px;
}

.cm-symbol-menu__item {
    appearance: none;
    background: transparent;
    border: 0;
    width: 100%;
    text-align: left;
    padding: 6px 10px;
    border-radius: 4px;
    color: var(--text-1, #d8d8e0);
    cursor: pointer;
    font: inherit;
}

.cm-symbol-menu__item:hover:not(.cm-symbol-menu__item--disabled) {
    background: var(--surface-hover, rgba(124, 124, 144, 0.16));
}

.cm-symbol-menu__item--disabled {
    color: var(--text-muted, rgba(216, 216, 224, 0.45));
    cursor: not-allowed;
}

/* CodeMirror @codemirror/search panel (Ctrl/Cmd-F). The default
   styling renders bare inputs/buttons; bring them in line with the
   app's button + input look. */
.cm-panels.cm-panels-top {
    border-bottom: 1px solid var(--border-strong);
    background: var(--surface);
}

/* Bottom-docked status bar (built by buildStatusBarExtension in
   code-editor.js). Sits below cm-scroller and inherits theme colours
   from the editor's container. Left/right split mirrors VS Code's
   layout — cursor position on the left, document totals on the right. */
.cm-panels.cm-panels-bottom {
    border-top: 1px solid var(--border-strong);
    background: var(--surface);
}

.cm-status-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 3px 10px;
    font-size: 11.5px;
    font-variant-numeric: tabular-nums;
    color: var(--ink-3);
    font-family: var(--mono);
}

.cm-status-bar__left,
.cm-status-bar__right {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.cm-search.cm-panel {
    padding: 8px 10px;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    background: var(--surface);
    color: var(--ink);
    font-family: inherit;
}

.cm-search .cm-textfield {
    font-family: inherit;
    font-size: 13px;
    padding: 4px 8px;
    color: var(--ink);
    background: var(--surface-2, var(--bg));
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm, 4px);
    outline: none;
}

.cm-search .cm-textfield:focus {
    border-color: var(--blue);
}

.cm-search .cm-button {
    font-family: inherit;
    font-size: 12.5px;
    padding: 4px 10px;
    color: var(--ink);
    background: transparent;
    background-image: none;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm, 4px);
    cursor: pointer;
}

.cm-search .cm-button:hover {
    background: var(--surface-2, rgba(124, 124, 144, 0.12));
}

.cm-search label {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 12.5px;
    color: var(--ink-3);
    cursor: pointer;
}

.cm-search label input[type="checkbox"] {
    accent-color: var(--blue);
    margin: 0;
}

.cm-panel button[name="close"] {
    margin-left: auto;
    padding: 0 8px;
    font-size: 16px;
    line-height: 1;
    color: var(--ink-3);
    background: transparent;
    border: 0;
    cursor: pointer;
}

.cm-panel button[name="close"]:hover {
    color: var(--ink);
}

/* Sticky highlight on the line the user navigated to via a deep link
   or a References-panel click. Backing colour comes from
   --blue-50 so it tracks the active theme. The actual
   line.background rule lives in CM6's baseTheme (currentLineTheme in
   code-editor.js) so it survives CodeMirror's row virtualisation. */

/* File viewer layout: code editor + right-rail inspector panel. The
   editor fills the remaining width and grows to its content height —
   long files extend the page rather than scrolling internally. The
   panel stays in view via `position: sticky` so the outline / refs
   are always one glance away. Stacks vertically on narrow viewports. */
.object-explorer__file-layout {
    display: flex;
    gap: 16px;
    align-items: flex-start;
}

.object-explorer__file-layout > .code-viewer-host {
    flex: 1 1 auto;
    min-width: 0;
}

@media (max-width: 1100px) {
    .object-explorer__file-layout {
        flex-direction: column;
    }
}

.inspector-panel {
    /* Scale with viewport — narrow browser still gets the minimum, wide
       monitors get more room for reference snippets. */
    flex: 0 0 clamp(280px, 28vw, 520px);
    display: flex;
    flex-direction: column;
    /* Sticky-follow on scroll. The nearest scrolling ancestor is
       .content (`overflow-y: auto`), so the panel pins to the top of
       the work column once it would otherwise scroll out of view.
       max-height caps it to the viewport so long outlines get their
       own internal scrollbar instead of overflowing the screen. */
    position: sticky;
    top: 16px;
    max-height: calc(100vh - var(--top-h) - 32px);
    border: 1px solid var(--border, #2a2a35);
    border-radius: 6px;
    background: var(--surface-1, #1a1c22);
    overflow: hidden;
    font-size: 13px;
}

@media (max-width: 1100px) {
    /* In the stacked layout sticky would pin the panel to the top of
       the column, hiding the editor as the user scrolls — unhelpful.
       Drop back to its natural flow position. */
    .inspector-panel {
        position: static;
        max-height: 60vh;
    }
}

.inspector-panel__crumbs {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px;
    padding: 8px 10px;
    border-bottom: 1px solid var(--border, #2a2a35);
    background: var(--surface-2, rgba(124, 124, 144, 0.08));
    font-size: 12.5px;
}

.inspector-panel__crumb {
    appearance: none;
    background: transparent;
    border: 0;
    padding: 2px 6px;
    border-radius: 4px;
    color: inherit;
    font: inherit;
    cursor: default;
    max-width: 160px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.inspector-panel__crumb--link {
    color: var(--text-2, #b0b0c2);
    cursor: pointer;
}

.inspector-panel__crumb--link:hover {
    background: var(--surface-hover, rgba(124, 124, 144, 0.16));
    color: var(--text-1, #d8d8e0);
}

.inspector-panel__crumb--current {
    color: var(--text-1, #d8d8e0);
    font-weight: 600;
}

.inspector-panel__crumb-sep {
    color: var(--text-3, #6b6b80);
}

.inspector-panel__body {
    flex: 1 1 auto;
    overflow-y: auto;
    padding: 8px 10px 12px;
}

.inspector-panel__empty {
    margin: 12px 4px;
}

.inspector-panel__filter {
    margin-bottom: 8px;
}

.inspector-panel__filter-input {
    width: 100%;
    padding: 6px 8px;
    border: 1px solid var(--border, #2a2a35);
    border-radius: 4px;
    background: var(--surface-2, rgba(124, 124, 144, 0.08));
    color: var(--text-1, #d8d8e0);
    font: inherit;
    font-size: 12.5px;
}

.inspector-panel__filter-input::placeholder {
    color: var(--text-3, #6b6b80);
}

.inspector-panel__sections,
.inspector-panel__items,
.inspector-panel__refs-files,
.inspector-panel__refs-hits {
    list-style: none;
    margin: 0;
    padding: 0;
}

.inspector-panel__section + .inspector-panel__section {
    margin-top: 12px;
}

.inspector-panel__section-title {
    margin: 0 0 4px 0;
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-2, #b0b0c2);
    display: flex;
    gap: 6px;
    align-items: baseline;
}

/* Collapsible section header — same typography as the static title, plus
   a leading chevron and a button cursor so it's discoverable. The chevron
   itself is a vendored Lucide icon, so no rotation animation; we swap
   chevron-right / chevron-down between collapsed and expanded states. */
.inspector-panel__section-toggle {
    appearance: none;
    background: transparent;
    border: 0;
    padding: 4px 0;
    margin: 0 0 4px 0;
    width: 100%;
    font: inherit;
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-2, #b0b0c2);
    display: flex;
    gap: 6px;
    align-items: center;
    cursor: pointer;
    text-align: left;
}
.inspector-panel__section-toggle:hover {
    color: var(--text-1, #d8d8e0);
}
.inspector-panel__section-title-text {
    flex: 0 0 auto;
}

/* Full-viewport invisible backdrop used to dismiss the outline row's
   right-click menu on outside-click. Sits below the menu (z-index 999
   vs the menu's 1000). Pointer-events: auto so the click is caught. */
.cm-symbol-menu-backdrop {
    position: fixed;
    inset: 0;
    z-index: 999;
    background: transparent;
}

.inspector-panel__item {
    display: flex;
    align-items: center;
    gap: 2px;
    border-radius: 4px;
}

.inspector-panel__item:hover {
    background: var(--surface-hover, rgba(124, 124, 144, 0.10));
}

.inspector-panel__item-link {
    flex: 1 1 auto;
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 8px;
    padding: 4px 6px;
    color: inherit;
    text-decoration: none;
    font-family: var(--mono, ui-monospace, "SF Mono", Menlo, Consolas, monospace);
    font-size: 12.5px;
    min-width: 0;
}

/* Override the global `a:hover { text-decoration: underline }` — the row
   already changes background on hover, the redundant underline reads as
   noise. */
.inspector-panel__item-link:hover {
    text-decoration: none;
}

.inspector-panel__item-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    flex: 0 1 auto;
    min-width: 0;
}

/* Field type / procedure signature, rendered between the name and the
   line-number badge. Truncated with ellipsis so a 200-character method
   signature doesn't push the line off-row; full text is on the title
   attribute so hovering reveals it. */
.inspector-panel__item-sig {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    flex: 1 1 auto;
    min-width: 0;
    font-family: var(--mono, ui-monospace, "SF Mono", Menlo, Consolas, monospace);
}

.inspector-panel__item-line {
    flex-shrink: 0;
}

.inspector-panel__item-action {
    appearance: none;
    background: transparent;
    border: 0;
    padding: 4px 6px;
    border-radius: 4px;
    color: var(--text-3, #6b6b80);
    cursor: pointer;
    /* Only reveal the find-references button while the row is hovered or
       the button itself is focused — keeps the row visually quiet at rest. */
    opacity: 0;
    transition: opacity 80ms ease-out;
}

.inspector-panel__item:hover .inspector-panel__item-action,
.inspector-panel__item-action:focus {
    opacity: 1;
}

.inspector-panel__item-action:hover {
    background: var(--surface-hover, rgba(124, 124, 144, 0.16));
    color: var(--text-1, #d8d8e0);
}

.inspector-panel__refs-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 6px;
    margin: 4px 0 12px 0;
}

.inspector-panel__refs-section + .inspector-panel__refs-section {
    margin-top: 14px;
}

.inspector-panel__refs-file {
    border: 1px solid var(--border, #2a2a35);
    border-radius: 4px;
    overflow: hidden;
    margin-top: 8px;
}

.inspector-panel__refs-file-header {
    display: flex;
    align-items: baseline;
    gap: 6px;
    padding: 4px 8px;
    background: var(--surface-2, rgba(124, 124, 144, 0.08));
    font-size: 12px;
}

.inspector-panel__refs-hit {
    display: grid;
    grid-template-columns: 40px 1fr;
    gap: 8px;
    padding: 4px 8px;
    border-top: 1px solid var(--border, #2a2a35);
    text-decoration: none;
    color: inherit;
    font-family: var(--mono, ui-monospace, "SF Mono", Menlo, Consolas, monospace);
    font-size: 12px;
}

.inspector-panel__refs-hit:hover {
    background: var(--surface-hover, rgba(124, 124, 144, 0.10));
    /* Suppress the global `a:hover` underline — background change is enough. */
    text-decoration: none;
}

.inspector-panel__refs-hit-line {
    color: var(--text-3, #6b6b80);
    text-align: right;
}

.inspector-panel__refs-hit-snippet {
    color: var(--text-1, #d8d8e0);
    white-space: pre;
    overflow-x: auto;
}

/* ---------- References page ---------- */
.object-explorer__references .references__section {
    margin-top: 24px;
}

.references__section h2 {
    font-size: 15px;
    margin: 0 0 12px 0;
}

.references__toggle {
    appearance: none;
    background: transparent;
    border: 0;
    padding: 0;
    color: inherit;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font: inherit;
    font-size: 15px;
    font-weight: 600;
}

.references__possibly-related-explainer {
    margin: 4px 0 12px 22px;
}

.references__file {
    border: 1px solid var(--border, #2a2a35);
    border-radius: 6px;
    overflow: hidden;
    margin-bottom: 12px;
}

.references__file-header {
    padding: 8px 12px;
    background: var(--surface-2, rgba(124, 124, 144, 0.08));
    display: flex;
    align-items: baseline;
    gap: 8px;
}

.references__hits {
    list-style: none;
    margin: 0;
    padding: 0;
}

.references__hit {
    border-top: 1px solid var(--border, #2a2a35);
}

.references__hit-link {
    display: grid;
    grid-template-columns: 48px 1fr;
    gap: 12px;
    padding: 6px 12px;
    text-decoration: none;
    color: inherit;
    font-family: var(--mono, ui-monospace, "SF Mono", Menlo, Consolas, monospace);
    font-size: 12.5px;
}

.references__hit-link:hover {
    background: var(--surface-hover, rgba(124, 124, 144, 0.12));
}

.references__hit-line {
    color: var(--text-3, #6b6b80);
    text-align: right;
    user-select: none;
}

.references__hit-snippet {
    color: var(--text-1, #d8d8e0);
    white-space: pre;
    overflow-x: auto;
}



/* Account security & admin user-create additions (M-AccountSecurity) */
.invite-link-box {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 8px;
    padding: 8px 10px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--r);
    font-family: var(--mono);
    font-size: 12.5px;
    overflow-x: auto;
}
.invite-link-box code {
    white-space: nowrap;
    flex: 1;
}

.inline-checkbox {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
}
.inline-checkbox input {
    width: auto;
}

.email-change-row td {
    background: var(--bg);
    padding: 12px 16px;
}

/* ---------- Release & file compare ---------- */
/* Side-by-side diff viewer (/object-explorer/compare/file): two CodeMirror
   panes laid out as a 2-column grid. Each pane is a full `.source-viewer`
   shell minus the outline DOM, so the existing CodeMirror styling carries
   through unchanged. Below 1100px we stack vertically.

   Line-level diff colouring uses CodeMirror's line decoration mechanism
   (see code-editor.js → buildLineDecorationExtensions). Lines flagged
   inserted/deleted/modified get a full-row tint; imaginary rows pad the
   shorter side so both panes line up visually.

   Colours pulled from the existing theme palette to stay dark-mode safe.
*/

/* Page shell: mirror the normal source-viewer's pattern — flex column
   that fills .content's grid-row height, so the panes can take the
   remaining space below the header without a hard-coded calc(). */
.oe-compare-file {
    padding: 16px;
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 0;
}
.oe-compare-file__header {
    flex: 0 0 auto;
    align-items: flex-start;
    gap: 16px;
}
/* Override the 72ch prose cap inherited from `.admin-page__header p`
   (admin.css) so the full "Release · Module · Path" labels show instead of
   wrapping early. The extra ancestor class wins the specificity tie against
   admin.css, which loads after tools.css. */
.oe-compare-file__header .oe-compare-file__breadcrumbs p {
    margin: 0 0 4px;
    max-width: none;
}
.oe-compare-file__panes {
    /* Fills the rest of .oe-compare-file. grid-template-rows: 1fr is what
       lets the inner .source-viewer { height: 100% } resolve correctly —
       without it, the row would be auto-sized and the cm-editor would
       collapse to zero height. */
    flex: 1 1 0;
    min-height: 0;
    display: grid;
    grid-template-columns: 1fr 1fr;
    grid-template-rows: 1fr;
    gap: 12px;
    margin-top: 12px;
}
.oe-compare-file__panes > .source-viewer--compare {
    border: 1px solid var(--border);
    border-radius: 6px;
    overflow: hidden;
    background: var(--surface);
    /* Row so the editor and the KDiff3-style overview ruler sit side by side
       (the base .source-viewer is a column). */
    flex-direction: row;
    /* min-height: 0 keeps the grid item from forcing the cm-scroller's
       intrinsic content height up the cascade — without it, long files
       blow the viewport on browsers that compute grid items' min size
       as min-content. */
    min-height: 0;
}
@media (max-width: 1100px) {
    .oe-compare-file__panes {
        grid-template-columns: 1fr;
        /* Stack vertically and give each pane half the available space. */
        grid-template-rows: 1fr 1fr;
    }
}

/* Diff line tints — applied to <div class="cm-line"> rows. The colour
   variables fall back to the named lights so each pane reads the same in
   light and dark themes. */
.cm-line.cm-diff-inserted   { background-color: rgba(38, 176, 80, 0.16); }
.cm-line.cm-diff-deleted    { background-color: rgba(179, 33, 33, 0.18); }
.cm-line.cm-diff-modified   { background-color: rgba(234, 179, 8, 0.20); }
.cm-line.cm-diff-imaginary  { background-color: var(--surface-sunken); color: var(--ink-3); }

/* Alignment filler — a blank block widget (built in code-editor.js's
   buildFillerDecorationExtensions) that pads the shorter compare pane so
   matching lines stay aligned KDiff3-style. A faint diagonal hatch over the
   muted surface reads as "no content here" without drawing the eye like real
   code, with hairline borders marking where the gap opens and closes. */
.cm-diff-filler {
    background-color: var(--surface-sunken);
    background-image: repeating-linear-gradient(
        135deg,
        transparent 0,
        transparent 5px,
        var(--border) 5px,
        var(--border) 6px);
    border-top: 1px solid var(--border);
    border-bottom: 1px solid var(--border);
    opacity: 0.6;
}

/* Diff change-bar gutter — a thin column (built in code-editor.js's
   buildDiffGutterExtensions) that paints one coloured cell per changed line so
   the run of changes is visible at a glance. Colours mirror the line tints but
   fully opaque to read as a solid bar. */
.cm-diff-gutter { width: 4px; }
.cm-diff-gutter .cm-gutterElement { padding: 0; }
.cm-diff-gutter-mark { width: 4px; }
.cm-diff-gutter-inserted { background-color: rgb(38, 176, 80); }
.cm-diff-gutter-deleted  { background-color: rgb(179, 33, 33); }
.cm-diff-gutter-modified { background-color: rgb(234, 179, 8); }

/* KDiff3-style overview ruler (compare panes, built in source-viewer.js's
   buildDiffOverview). A thin full-height strip on the right edge of each pane
   that maps every changed line in the WHOLE file to a coloured mark, so the
   spread of changes is visible without scrolling. Each mark is a button that
   jumps the editor to that change. */
.oe-diff-overview {
    position: relative;
    flex: 0 0 14px;
    align-self: stretch;
    background: var(--surface-sunken);
    border-left: 1px solid var(--border);
}
.oe-diff-overview__mark {
    position: absolute;
    left: 2px;
    right: 2px;
    padding: 0;
    border: 0;
    border-radius: 1px;
    min-height: 3px;
    cursor: pointer;
    opacity: 0.85;
}
.oe-diff-overview__mark:hover {
    left: 0;
    right: 0;
    opacity: 1;
    outline: 1px solid var(--ink-3);
}
.oe-diff-overview__mark--inserted  { background-color: rgb(38, 176, 80); }
.oe-diff-overview__mark--deleted   { background-color: rgb(179, 33, 33); }
.oe-diff-overview__mark--modified  { background-color: rgb(234, 179, 8); }
.oe-diff-overview__mark--imaginary { background-color: var(--border); }

/* Change summary line in the compare header. */
.oe-compare-file__summary { margin: 6px 0 0; font-weight: 500; }

/* Compare-with-release picker on the single-file viewer header.
   Sits stacked under the Download button on the right edge. The
   picker collapses to one row inside its container (the field label
   stays above the select for accessibility, but no min-width pushes
   it wider than the outline column). */
.source-viewer__compare-picker {
    display: flex;
    align-items: stretch;
    width: 100%;
}
.source-viewer__compare-picker .field {
    width: 100%;
    min-width: 0;
}

/* Header actions wrapper — sits to the right of the breadcrumb and
   stacks the Download button + Compare-with-release picker
   vertically. The column width tracks the outline panel's width so
   the two controls always read as a visual pair with the outline
   below them (rather than the picker stretching wider than its
   own outline column did). */
.source-viewer__header-actions {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 6px;
    margin-left: auto;
    width: var(--source-viewer-outline-width, 340px);
    max-width: 100%;
}
.source-viewer__header-actions > .btn {
    width: 100%;
    justify-content: center;
    text-align: center;
}
.source-viewer__header-actions .field__label {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--ink-3);
}

/* Status-row badges in the Compare-with-release results table. Reuse the
   same flat-pill shape as the existing kind badges but with semantic colour. */
.badge--success { background-color: rgba(38, 176, 80, 0.18); color: var(--good); padding: 2px 8px; border-radius: 999px; font-size: 12px; }
.badge--danger  { background-color: rgba(179, 33, 33, 0.18); color: var(--danger); padding: 2px 8px; border-radius: 999px; font-size: 12px; }
.badge--warning { background-color: rgba(234, 179, 8, 0.20); color: #8a6d00; padding: 2px 8px; border-radius: 999px; font-size: 12px; }
@media (prefers-color-scheme: dark) {
    .badge--warning { color: #ffd05a; }
}

/* ---- split-button + dropdown row actions (.ra) ----
   Shared globally (rather than scoped to RowActionsMenu) so any results row or
   factbox list can mount the same split button — the Object Explorer source rows
   and the customer-build history both use it. Behaviour (one-open-at-a-time,
   close-on-outside-click / scroll / Escape) is wired for every details.ra__menu
   by wwwroot/row-actions-menu.js. Values from the Object Explorer design study
   (.design/translator/styles/screens.css). The popup is positioned absolutely
   under the caret; keep the surrounding table/list wrapper overflow visible so
   it isn't clipped. */

/* stretch so the caret (a <summary> inside a <details>) matches the height of
   the primary button rather than sizing to its own short content */
.ra { display: inline-flex; align-items: stretch; }

.ra__main,
.ra__caret {
    border: 1px solid var(--border-input);
    background: var(--surface);
    color: var(--ink-2);
    font: inherit;
    font-size: 12.5px;
    font-weight: 600;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 7px;
    transition: background 0.12s, color 0.12s, border-color 0.12s;
    text-decoration: none;
}

.ra__main { padding: 7px 12px; border-radius: var(--r) 0 0 var(--r); }
.ra__main:hover { background: var(--surface-sunken); color: var(--ink); text-decoration: none; }
.ra__main:hover svg { color: var(--blue); }
.ra__main svg { color: var(--ink-4); flex: 0 0 auto; }

/* Caret is the <summary> of the menu's <details>; strip the native marker. */
.ra__caret {
    padding: 7px 8px;
    border-left: 0;
    border-radius: 0 var(--r) var(--r) 0;
    list-style: none;
}
.ra__caret::-webkit-details-marker { display: none; }
.ra__caret::marker { content: ""; }
.ra__caret svg { color: var(--ink-4); transition: transform 0.15s; }
.ra__caret:hover { background: var(--surface-sunken); color: var(--ink); }
.ra__caret:hover svg { color: var(--blue); }

.ra__menu { position: relative; display: inline-flex; }
.ra__menu[open] > .ra__caret { background: var(--blue-50); border-color: var(--blue); color: var(--blue-700); }
.ra__menu[open] > .ra__caret svg { color: var(--blue); transform: rotate(180deg); }

/* Solo trigger: a single square icon button (kebab) that opens the menu, for
   tight spots like the project Builds factbox where a labelled split button
   crowds the row. Same menu, just a one-icon affordance. */
.ra__solo {
    border: 1px solid var(--border-input);
    background: var(--surface);
    color: var(--ink-2);
    padding: 6px;
    border-radius: var(--r);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    list-style: none;
    transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.ra__solo::-webkit-details-marker { display: none; }
.ra__solo::marker { content: ""; }
.ra__solo svg { color: var(--ink-4); flex: 0 0 auto; }
.ra__solo:hover { background: var(--surface-sunken); color: var(--ink); }
.ra__solo:hover svg { color: var(--blue); }
.ra__menu[open] > .ra__solo { background: var(--blue-50); border-color: var(--blue); color: var(--blue-700); }
.ra__menu[open] > .ra__solo svg { color: var(--blue); }

/* Popup */
.ra__pop {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 11px;
    box-shadow: var(--shadow-lg);
    padding: 6px;
    min-width: 212px;
    z-index: 80;
}

.ra__item {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 10px;
    border: 0;
    background: transparent;
    font: inherit;
    font-size: 13px;
    font-weight: 500;
    color: var(--ink-2);
    border-radius: 7px;
    cursor: pointer;
    text-align: left;
    text-decoration: none;
    box-sizing: border-box;
}

.ra__item svg { width: 15px; height: 15px; color: var(--ink-4); flex: 0 0 auto; }
.ra__item:hover { background: var(--surface-sunken); color: var(--ink); text-decoration: none; }
.ra__item:hover svg { color: var(--blue); }
.ra__item--danger { color: var(--danger); }
.ra__item--danger:hover { background: var(--surface-sunken); color: var(--danger); }
.ra__item--danger svg,
.ra__item--danger:hover svg { color: var(--danger); }

.ra__divider { height: 1px; background: var(--border); margin: 5px 4px; }

/* "Compare with…" submenu */
.ra__sub { position: relative; }
.ra__item--parent { list-style: none; }
.ra__item--parent::-webkit-details-marker { display: none; }
.ra__item--parent::marker { content: ""; }
.ra__subcaret { margin-left: auto; transition: transform 0.15s; }
.ra__sub[open] > .ra__item--parent { color: var(--ink); background: var(--surface-sunken); }
.ra__sub[open] > .ra__item--parent .ra__subcaret { transform: rotate(90deg); color: var(--blue); }

.ra__sublist {
    margin: 2px 0 3px 19px;
    padding-left: 8px;
    border-left: 1px solid var(--border);
    display: flex;
    flex-direction: column;
}

.ra__item--leaf { padding: 7px 10px; }
.ra__item--leaf .mono { font-size: 12px; color: var(--ink-3); font-family: var(--mono); }
.ra__item--leaf:hover .mono { color: var(--ink); }

/* ════════════════════════════════════════════════════════════════════════
   Projects + Artifacts tools  (recreated from the Claude Design handoff;
   see .design/artifacts.md). Uses the shared base.css tokens, so the screens
   theme light/dark automatically.
   ════════════════════════════════════════════════════════════════════════ */
.proj-page,
.art-page { max-width: 1100px; }

.proj-page .sub,
.art-page .sub { color: var(--ink-3); font-size: 14px; max-width: 760px; line-height: 1.55; margin: 6px 0 0; }

.art-page .plain-link,
.proj-page .plain-link { color: var(--blue); text-decoration: none; font-size: 13px; }
.art-page .plain-link:hover { text-decoration: underline; }
.art-fail { color: var(--danger); font-size: 13.5px; margin: 4px 0 10px; }

/* A latest-build chip that links into the Artifacts tool (Projects directory). */
.art-latest { display: inline-flex; align-items: center; gap: 8px; text-decoration: none; color: inherit; }
.art-latest:hover { text-decoration: none; }

.art-app__meta { color: var(--ink-3); font-size: 12.5px; }

/* ── Artifacts landing: header + toolbar ─────────────────────────────── */
.art-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 24px; margin-bottom: 22px; }
.art-head .ah-text h1 { margin: 0; }
.art-head .btn { flex: 0 0 auto; }

.art-toolbar { display: flex; align-items: center; gap: 14px; margin-bottom: 14px; }
.art-search { position: relative; flex: 1; max-width: 440px; }
.art-search > svg { position: absolute; left: 13px; top: 50%; transform: translateY(-50%); color: var(--ink-4); width: 17px; height: 17px; pointer-events: none; }
.art-search .input {
    width: 100%;
    height: 40px;
    font: inherit;
    font-size: 14px;
    color: var(--ink);
    background: var(--surface);
    border: 1px solid var(--border-input);
    border-radius: var(--r);
    padding: 0 13px 0 40px;
    outline: none;
    transition: border-color 0.12s, box-shadow 0.12s;
}
.art-search .input::placeholder { color: var(--ink-4); }
.art-search .input:focus { border-color: var(--blue); box-shadow: 0 0 0 3px var(--blue-50); }
.art-toolbar .tb-sort { display: inline-flex; align-items: center; gap: 7px; font-size: 12.5px; color: var(--ink-3); margin-left: auto; white-space: nowrap; }
.art-toolbar .tb-sort b { color: var(--ink-2); font-weight: 600; }

.art-count { font-size: 13px; color: var(--ink-3); margin-bottom: 16px; }
.art-count b { color: var(--ink); font-variant-numeric: tabular-nums; }
.art-count .sep { margin: 0 8px; color: var(--border-strong); }

/* ── Artifacts landing: project list (scales to ~100 projects) ───────── */
.art-list { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg); box-shadow: var(--shadow-xs); }
.alr {
    display: grid;
    grid-template-columns: minmax(280px, 2.2fr) minmax(190px, 1.2fr) 116px minmax(140px, 1fr) 44px;
    align-items: center; gap: 18px;
    padding: 0 20px; min-height: 60px;
    border-bottom: 1px solid var(--border);
}
.alr:last-child { border-bottom: 0; }
.alr.head {
    min-height: 40px; background: var(--surface-2);
    font-size: 10.5px; font-weight: 700; letter-spacing: .8px; text-transform: uppercase; color: var(--ink-4);
    border-radius: var(--r-lg) var(--r-lg) 0 0;
}
.alr.proj { position: relative; transition: background .1s; }
.alr.proj:hover { background: var(--surface-2); }

/* col 1 — project identity. The name is a stretched link covering the row;
   the actions cell sits above it so its buttons stay clickable. */
.al-proj { display: flex; align-items: center; gap: 13px; min-width: 0; }
.al-pico { width: 34px; height: 34px; border-radius: 9px; flex: 0 0 auto; background: var(--blue-50); color: var(--blue); display: grid; place-items: center; }
.al-ptext { min-width: 0; }
.al-pname { font-size: 14.5px; font-weight: 700; color: var(--ink); letter-spacing: -.2px; text-decoration: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: block; }
.al-rowlink::after { content: ""; position: absolute; inset: 0; }

/* A secondary link inside a stretched-link row (e.g. the pipeline row's project
   link) must sit above the row overlay to stay independently clickable. */
.al-sublink { position: relative; z-index: 1; display: inline-flex; align-items: center; gap: 4px; color: inherit; text-decoration: none; }
.al-sublink:hover { color: var(--blue); text-decoration: underline; }
.alr.proj:hover .al-pname { color: var(--blue-700); }
.al-pmeta { margin-top: 3px; display: flex; align-items: center; gap: 7px; font-size: 11.5px; color: var(--ink-4); }
.al-avatar { width: 16px; height: 16px; border-radius: 999px; flex: 0 0 auto; display: grid; place-items: center; font-size: 8px; font-weight: 700; color: var(--blue-700); background: var(--blue-100); }
.al-pmeta .reps { display: inline-flex; align-items: center; gap: 4px; }
.al-pmeta .reps svg { color: var(--ink-4); }

/* col 2 — latest build summary (commit on top, branch + BC chip below) */
.al-build { min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.al-commit { display: inline-flex; align-items: center; gap: 6px; font-family: var(--mono); font-size: 12.5px; font-weight: 600; color: var(--ink-2); }
.al-commit svg { color: var(--ink-4); flex: 0 0 auto; }
.al-bmeta { display: inline-flex; align-items: center; gap: 7px; font-size: 11px; color: var(--ink-4); }
.al-bmeta .br { display: inline-flex; align-items: center; gap: 4px; min-width: 0; max-width: 160px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.al-bmeta .br svg { color: var(--ink-4); flex: 0 0 auto; }
.al-ver { font-family: var(--mono); font-size: 10px; color: var(--ink-3); background: var(--surface-sunken); border: 1px solid var(--border); border-radius: 4px; padding: 1px 6px; white-space: nowrap; }

/* col 4 — date */
.al-date { font-size: 12.5px; color: var(--ink-3); white-space: nowrap; }

/* col 5 — actions (download + kebab), lifted above the stretched row link */
.al-act { position: relative; z-index: 1; display: flex; align-items: center; justify-content: flex-end; gap: 8px; }
/* While the kebab menu is open, raise this row's actions above the rows below
   so the popover isn't trapped under their (z-indexed) action cells. */
.al-act:has(.ra__menu[open]) { z-index: 50; }

/* ── Artifacts detail: breadcrumb + header ───────────────────────────── */
.det-bc { display: flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--ink-4); margin-bottom: 16px; }
.det-bc a { color: var(--ink-3); text-decoration: none; display: inline-flex; align-items: center; gap: 6px; }
.det-bc a:hover { color: var(--blue); }
.det-bc .cur { color: var(--ink-2); font-weight: 600; }

.det-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 24px; margin-bottom: 6px; }
.det-id { display: flex; align-items: center; gap: 15px; min-width: 0; }
.det-pico { width: 50px; height: 50px; border-radius: 13px; flex: 0 0 auto; background: var(--blue-50); color: var(--blue); display: grid; place-items: center; }
.det-title h1 { margin: 0; }
.det-sub { margin-top: 8px; display: flex; align-items: center; gap: 9px; font-size: 13px; color: var(--ink-3); flex-wrap: wrap; }
.det-sub .av { width: 20px; height: 20px; border-radius: 999px; display: grid; place-items: center; font-size: 9px; font-weight: 700; color: var(--blue-700); background: var(--blue-100); }
.det-sub .meta { display: inline-flex; align-items: center; gap: 6px; }
.det-sub .meta svg { color: var(--ink-4); }
.det-actions { display: flex; align-items: center; gap: 10px; flex: 0 0 auto; }

/* ── Artifacts detail: two-column layout + cards ─────────────────────── */
/* Fixed 264px rail to match the Cookbook detail (.rd-grid); the main column takes the rest. */
.det-grid { display: grid; grid-template-columns: minmax(0, 1fr) 264px; gap: 18px; margin-top: 24px; align-items: start; }
.det-col { display: flex; flex-direction: column; gap: 18px; min-width: 0; }
/* Collapse to a single column on narrow viewports, matching the Cookbook (.rd-grid). */
@media (max-width: 980px) {
    .det-grid { grid-template-columns: 1fr; }
}

.det-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg); box-shadow: var(--shadow-xs); overflow: hidden; }
.det-card.hero { border-color: var(--blue); box-shadow: 0 0 0 1px var(--blue), var(--shadow); }
.dc-head { display: flex; align-items: center; justify-content: space-between; gap: 14px; padding: 14px 18px; border-bottom: 1px solid var(--border); }
.dc-head .dc-t { font-size: 11px; font-weight: 700; letter-spacing: .8px; text-transform: uppercase; color: var(--ink-4); display: inline-flex; align-items: center; gap: 8px; }
.dc-head .dc-t svg { color: var(--ink-4); }
.dc-head .al-date { font-size: 11.5px; }
.dc-body { padding: 16px 18px; }

/* latest-build hero summary line */
.lb-top { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 14px; }
.lb-commit { display: inline-flex; align-items: center; gap: 7px; font-family: var(--mono); font-size: 15px; font-weight: 700; color: var(--ink); }
.lb-commit svg { color: var(--ink-4); flex: 0 0 auto; }
.lb-branch { display: inline-flex; align-items: center; gap: 5px; font-size: 12.5px; color: var(--ink-3); }
.lb-branch svg { color: var(--ink-4); }
.lb-ver { font-family: var(--mono); font-size: 11px; color: var(--ink-3); background: var(--surface-sunken); border: 1px solid var(--border); border-radius: 5px; padding: 2px 7px; }
.lb-when { font-size: 12px; color: var(--ink-4); margin-left: auto; }
.lb-deliv { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 4px 0 11px; }
.lb-deliv .lbd-label { font-size: 12px; font-weight: 600; color: var(--ink-2); }
.lb-explore { margin-top: 14px; }

/* deliverable rows */
.app-list { display: flex; flex-direction: column; background: var(--surface); border: 1px solid var(--border); border-radius: var(--r); overflow: hidden; }
.app-row { display: grid; grid-template-columns: 30px minmax(0, 1fr) auto auto; align-items: center; gap: 13px; padding: 11px 14px; border-bottom: 1px solid var(--border); }
.app-row:last-child { border-bottom: 0; }
.app-row:hover { background: var(--surface-2); }
.app-ico { width: 30px; height: 30px; border-radius: 7px; background: var(--good-bg); color: var(--good); display: grid; place-items: center; }
.app-name { font-family: var(--mono); font-size: 13px; font-weight: 600; color: var(--ink); word-break: break-all; }
.app-pub { margin-top: 2px; font-size: 11px; color: var(--ink-4); }
.app-size { font-family: var(--mono); font-size: 11.5px; color: var(--ink-3); white-space: nowrap; font-variant-numeric: tabular-nums; }

/* per-repo changelog */
.chg { margin-top: 18px; }
.chg-h { font-size: 12px; font-weight: 600; color: var(--ink-2); margin-bottom: 10px; }
.chg-repo { margin-bottom: 13px; }
.chg-repo:last-child { margin-bottom: 0; }
.chg-repo .cr-name { display: inline-flex; align-items: center; gap: 6px; font-family: var(--mono); font-size: 12px; font-weight: 600; color: var(--ink-2); margin-bottom: 6px; }
.chg-repo .cr-name svg { color: var(--ink-4); }
.chg-repo ul { list-style: none; margin: 0; padding: 0 0 0 18px; display: flex; flex-direction: column; gap: 5px; }
.chg-repo li { position: relative; font-size: 12.5px; color: var(--ink-3); line-height: 1.5; }
.chg-repo li::before { content: ""; position: absolute; left: -14px; top: 7px; width: 5px; height: 5px; border-radius: 999px; background: var(--border-strong); }
.chg-repo li.chg-note { font-style: italic; }
.chg-repo li.chg-note::before { background: transparent; }
.chg-repo li .sha { font-family: var(--mono); font-size: 11px; color: var(--ink-4); }

/* build history timeline */
/* Fixed tracks for status / when / actions so they line up row-to-row (each row
   is its own grid); the message column (1fr) takes the slack and wraps. */
.hist-row { display: grid; grid-template-columns: 20px minmax(0, 1fr) 104px 116px 132px; align-items: center; gap: 13px; padding: 12px 18px; border-bottom: 1px solid var(--border); }
.hist-row:last-child { border-bottom: 0; }
.hist-row:hover { background: var(--surface-2); }
.hist-rail { display: grid; place-items: center; }
.hist-rail .hdot { width: 9px; height: 9px; border-radius: 999px; }
.hist-rail .hdot.ready { background: var(--good); }
.hist-rail .hdot.failed { background: var(--danger); }
.hist-rail .hdot.building, .hist-rail .hdot.queued { background: var(--st-untrans); }
.hist-commit { font-family: var(--mono); font-size: 13px; font-weight: 600; color: var(--ink); }
.hist-msg { margin-top: 3px; font-size: 11.5px; color: var(--ink-4); line-height: 1.45; text-wrap: pretty; }
.hist-msg .hist-fail { color: var(--danger); }
.hist-msg .hist-more { margin-left: 6px; color: var(--ink-3); font-weight: 600; white-space: nowrap; }
.hist-msg .hist-none { font-style: italic; }
.hist-when { font-size: 12px; color: var(--ink-4); white-space: nowrap; }
.hist-act { display: flex; align-items: center; justify-content: flex-end; gap: 10px; }
.hist-apps { font-size: 11.5px; color: var(--ink-4); white-space: nowrap; }

/* build log terminal */
.logbox { background: var(--surface-sunken); border: 1px solid var(--border); border-radius: var(--r); overflow: hidden; }
.logbox-h { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 9px 13px; border-bottom: 1px solid var(--border); font-size: 11.5px; color: var(--ink-3); }
.logbox-h .lh-l { display: inline-flex; align-items: center; gap: 8px; min-width: 0; }
.logbox-h .lh-l svg { color: var(--ink-4); flex: 0 0 auto; }
.logbox-h .lh-l .sha { font-family: var(--mono); font-weight: 600; color: var(--ink-2); }
.logbox pre { margin: 0; padding: 13px 15px; font-family: var(--mono); font-size: 11.5px; line-height: 1.7; color: var(--ink-2); max-height: 360px; overflow: auto; white-space: pre-wrap; word-break: break-word; }
.logbox .l-ok   { color: var(--good); }
.logbox .l-warn { color: var(--st-untrans); }
.logbox .l-err  { color: var(--danger); }
.logbox .l-dim  { color: var(--ink-4); }

/* side-rail project factbox */
.pj-meta { display: flex; flex-direction: column; }
.pj-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 9px 0; border-bottom: 1px solid var(--border); font-size: 12.5px; }
.pj-row:first-child { padding-top: 0; }
.pj-row:last-child { border-bottom: 0; }
.pj-k { color: var(--ink-4); }
.pj-v { color: var(--ink-2); font-weight: 600; display: inline-flex; align-items: center; gap: 7px; min-width: 0; }
.pj-v .av.sm { width: 18px; height: 18px; border-radius: 999px; flex: 0 0 auto; display: grid; place-items: center; font-size: 8px; font-weight: 700; color: var(--blue-700); background: var(--blue-100); }
.pj-link {
    margin-top: 14px; display: flex; align-items: center; gap: 9px;
    padding: 10px 12px; border-radius: var(--r-md, var(--r));
    background: var(--blue-50); color: var(--blue-700); border: 1px solid transparent;
    font-size: 13px; font-weight: 600; text-decoration: none; transition: border-color .12s, background .12s;
}
.pj-link:hover { border-color: var(--blue); background: var(--blue-100); }
.pj-link svg:last-child { margin-left: auto; color: var(--blue); }

/* side-rail repositories list (read-only; editing lives in the Projects tool) */
.repo-row { display: flex; align-items: center; gap: 11px; padding: 12px 0; border-bottom: 1px solid var(--border); }
.repo-row:first-child { padding-top: 0; }
.repo-row:last-child { border-bottom: 0; padding-bottom: 0; }
.repo-ico { width: 30px; height: 30px; border-radius: 8px; flex: 0 0 auto; background: var(--surface-sunken); border: 1px solid var(--border); color: var(--ink-3); display: grid; place-items: center; }
.repo-main { flex: 1; min-width: 0; }
.repo-name { font-size: 13px; font-weight: 600; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.repo-meta { margin-top: 3px; display: inline-flex; align-items: center; gap: 6px; font-family: var(--mono); font-size: 11px; color: var(--ink-4); }
.repo-meta svg { color: var(--ink-4); flex: 0 0 auto; }
.repo-link { flex: 0 0 auto; color: var(--ink-4); display: grid; place-items: center; padding: 4px; border-radius: 6px; }
.repo-link:hover { color: var(--blue); background: var(--surface-sunken); }

/* compare-builds picker (stacked for the narrow rail) */
.cmp-row { display: flex; flex-direction: column; gap: 8px; margin-top: 12px; }
.cmp-row .input {
    width: 100%;
    height: 36px;
    font: inherit;
    font-size: 13px;
    color: var(--ink);
    background: var(--surface);
    border: 1px solid var(--border-input);
    border-radius: var(--r);
    padding: 0 10px;
    outline: none;
    cursor: pointer;
    transition: border-color 0.12s, box-shadow 0.12s;
}
.cmp-row .input:focus { border-color: var(--blue); box-shadow: 0 0 0 3px var(--blue-50); }
.cmp-vs { font-size: 12px; color: var(--ink-4); text-align: center; }
.cmp-go { justify-content: center; }

/* ---------- Pipeline editor + extension picker (modal) ---------- */

.pe-field { display: flex; flex-direction: column; gap: 4px; margin: 0 0 16px; }
.pe-field .field__input {
    width: 100%;
    height: 36px;
    font: inherit;
    font-size: 13px;
    color: var(--ink);
    background: var(--surface);
    border: 1px solid var(--border-input);
    border-radius: var(--r);
    padding: 0 10px;
    outline: none;
    transition: border-color 0.12s, box-shadow 0.12s;
}
.pe-field .field__input:focus { border-color: var(--blue); box-shadow: 0 0 0 3px var(--blue-50); }
/* Native select chrome replaced with the app's caret, matching the OE pickers. */
.pe-field select.field__input {
    appearance: none;
    -webkit-appearance: none;
    cursor: pointer;
    padding-right: 28px;
    background-image:
        linear-gradient(45deg, transparent 50%, var(--ink-3) 50%),
        linear-gradient(135deg, var(--ink-3) 50%, transparent 50%);
    background-position: calc(100% - 14px) 50%, calc(100% - 9px) 50%;
    background-size: 5px 5px, 5px 5px;
    background-repeat: no-repeat;
}
.pe-field select.field__input:focus {
    background-image:
        linear-gradient(45deg, transparent 50%, var(--blue) 50%),
        linear-gradient(135deg, var(--blue) 50%, transparent 50%);
}

/* Project detail: the project's pipelines list. */
.pl-list { display: flex; flex-direction: column; gap: 6px; margin: 0 0 10px; }
.pl-item {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 10px;
    border: 1px solid var(--border);
    border-radius: var(--r);
    color: var(--ink);
    font-size: 13.5px;
    text-decoration: none;
}
.pl-item:hover { background: var(--surface-sunken); border-color: var(--blue); }

.nb-status { display: flex; align-items: center; gap: 9px; }

.nb-spin {
    width: 15px;
    height: 15px;
    border: 2px solid var(--border);
    border-top-color: var(--blue);
    border-radius: 50%;
    flex: 0 0 auto;
    animation: nb-spin 0.7s linear infinite;
}

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

.nb-list {
    display: flex;
    flex-direction: column;
    max-height: 340px;
    overflow-y: auto;
    border: 1px solid var(--border);
    border-radius: var(--r);
    margin: 0 0 10px;
}

.nb-row {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 10px 12px;
    cursor: pointer;
    border-bottom: 1px solid var(--border);
}

.nb-row:last-child { border-bottom: none; }
.nb-row:hover { background: var(--surface-sunken); }

.nb-row input[type="checkbox"] { margin-top: 2px; flex: 0 0 auto; cursor: pointer; }

.nb-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.nb-name { font-size: 13.5px; font-weight: 500; color: var(--ink); }
.nb-meta { font-size: 12px; color: var(--ink-3); }

.nb-foot {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 12.5px;
    color: var(--ink-3);
    margin: 0 0 14px;
}

.nb-sep { color: var(--ink-4); }
.nb-count { margin-left: auto; color: var(--ink-3); }

/* Discovery toolbar under the checklist: "Last discovered …" + Refresh. */
.pe-discovery {
    display: flex;
    align-items: center;
    gap: 12px;
    margin: 0 0 8px;
}
.pe-discovery .muted { font-size: 12.5px; }
.pe-discovery .btn { margin-left: auto; }

/* Why the primary action is disabled — shown only when it's user-correctable. */
.pe-hint { margin: 0 0 8px; font-size: 12.5px; }

.nb-linkbtn {
    background: none;
    border: none;
    padding: 0;
    font: inherit;
    font-size: 12.5px;
    color: var(--blue);
    cursor: pointer;
}

.nb-linkbtn:hover { text-decoration: underline; }

/* ════════════════════════════════════════════════════════════════════════
   Project SETTINGS — left sub-nav + one active section
   (recreated from the Claude Design "Project settings" handoff; see
   .design/artifacts.md). Sits inside .art-page.art-detail and reuses the
   shared base.css tokens, so it themes light/dark automatically.
   ════════════════════════════════════════════════════════════════════════ */
.set-grid { display: grid; grid-template-columns: 236px minmax(0, 1fr); gap: 30px; margin-top: 24px; align-items: start; }
@media (max-width: 880px) { .set-grid { grid-template-columns: 1fr; } }

/* ── left sub-nav ─────────────────────────────────────────────────────── */
.set-nav { position: sticky; top: 24px; display: flex; flex-direction: column; gap: 3px; }
.set-nav .cap-label { padding: 0 12px 8px; }
.set-nav-item {
    display: flex; align-items: center; gap: 11px; width: 100%; padding: 9px 12px;
    border-radius: var(--r); font-size: 13.5px; font-weight: 500; color: var(--ink-2);
    text-align: left; cursor: pointer; background: transparent; border: 1px solid transparent;
    font-family: inherit; transition: background .12s, color .12s;
}
.set-nav-item:hover { background: var(--surface-2); color: var(--ink); }
.set-nav-item.active { background: var(--blue-50); color: var(--blue-700); font-weight: 600; }
.set-nav-item svg { flex: 0 0 auto; }
.set-nav-item .sn-label { flex: 1; min-width: 0; }
.set-nav-item .sn-badge {
    font-size: 11px; font-weight: 600; font-variant-numeric: tabular-nums;
    background: var(--surface-sunken); border: 1px solid var(--border); color: var(--ink-3);
    border-radius: 999px; min-width: 20px; height: 20px; padding: 0 6px; display: grid; place-items: center;
}
.set-nav-item.active .sn-badge { background: var(--blue-100); border-color: transparent; color: var(--blue-700); }
.set-nav-item .sn-dot { width: 8px; height: 8px; border-radius: 999px; flex: 0 0 auto; }
.set-nav-item .sn-dot.off { background: var(--ink-4); box-shadow: 0 0 0 3px color-mix(in srgb, var(--ink-4) 18%, transparent); }
.set-nav-item .sn-dot.on  { background: var(--good); box-shadow: 0 0 0 3px var(--good-bg); }
.set-nav-divider { height: 1px; background: var(--border); margin: 10px 12px; }
.set-nav-item.danger { color: var(--danger); }
.set-nav-item.danger:hover, .set-nav-item.danger.active { background: var(--danger-bg, color-mix(in srgb, var(--danger) 12%, var(--surface))); color: var(--danger); }

/* ── content side ─────────────────────────────────────────────────────── */
.set-content { min-width: 0; }
.set-sec-head { margin-bottom: 18px; }
.set-sec-head h2 { margin: 0; font-size: 19px; font-weight: 700; color: var(--ink); letter-spacing: -.3px; display: flex; align-items: center; gap: 12px; }
.set-sec-head .desc { margin-top: 7px; font-size: 13px; color: var(--ink-3); line-height: 1.55; max-width: 620px; }
.set-pill { font-size: 11px; font-weight: 600; padding: 3px 9px; border-radius: 999px; display: inline-flex; align-items: center; gap: 6px; }
.set-pill .pd { width: 6px; height: 6px; border-radius: 999px; }
.set-pill.off { background: var(--surface-sunken); border: 1px solid var(--border); color: var(--ink-3); }
.set-pill.off .pd { background: var(--ink-4); }

/* "Connected / synced" green pill, shared shape with the build-status pills */
.state { font-size: 11px; font-weight: 600; padding: 3px 9px; border-radius: 999px; display: inline-flex; align-items: center; gap: 6px; }
.state .sd { width: 6px; height: 6px; border-radius: 999px; }
.state.ready { color: var(--good); background: var(--good-bg); }
.state.ready .sd { background: var(--good); }

.set-panel { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg); box-shadow: var(--shadow-xs); padding: 22px 24px; }
.set-panel + .set-panel { margin-top: 18px; }
.set-panel--danger { border-color: color-mix(in srgb, var(--danger) 35%, var(--border)); }
.set-foot { display: flex; align-items: center; gap: 10px; margin-top: 20px; padding-top: 18px; border-top: 1px solid var(--border); flex-wrap: wrap; }
.set-foot .note { font-size: 12px; color: var(--ink-4); margin-left: auto; }
.set-foot .note b { color: var(--ink-2); font-weight: 600; }

.set-subhead { display: flex; align-items: center; gap: 10px; margin: 26px 0 14px; }
.set-subhead .cap-label { margin: 0; }

.set-empty { display: flex; align-items: center; gap: 12px; padding: 18px; border: 1px dashed var(--border-strong); border-radius: var(--r); background: var(--surface-sunken); font-size: 13px; color: var(--ink-3); line-height: 1.5; }
.set-empty svg { color: var(--ink-4); flex: 0 0 auto; }

/* ── audit trail (read-only) ──────────────────────────────────────────── */
.av { border-radius: 999px; display: grid; place-items: center; font-weight: 700; color: var(--blue-700); background: var(--blue-100); }
.av.sm { width: 20px; height: 20px; font-size: 8.5px; flex: 0 0 auto; }
.audit { display: flex; flex-direction: column; }
.audit-row { display: grid; grid-template-columns: 150px 1fr auto; align-items: center; gap: 16px; padding: 13px 0; border-bottom: 1px solid var(--border); }
.audit-row:first-child { padding-top: 0; }
.audit-row:last-child { border-bottom: 0; padding-bottom: 0; }
.audit-k { font-size: 12.5px; color: var(--ink-4); }
.audit-v { font-size: 13px; font-weight: 600; color: var(--ink-2); display: inline-flex; align-items: center; gap: 8px; }
.audit-v.muted { font-weight: 500; }
.audit-t { font-family: var(--mono); font-size: 12px; color: var(--ink-3); white-space: nowrap; }

/* ── environments table (BC connection) ───────────────────────────────── */
.env-tbl { border: 1px solid var(--border); border-radius: var(--r); overflow: hidden; }
.env-row { display: grid; grid-template-columns: minmax(0, 1fr) 132px minmax(0, 1.1fr) auto; align-items: center; gap: 16px; padding: 0 16px; min-height: 62px; border-bottom: 1px solid var(--border); }
.env-row:last-child { border-bottom: 0; }
.env-row.head { min-height: 38px; background: var(--surface-2); font-size: 10.5px; font-weight: 700; letter-spacing: .8px; text-transform: uppercase; color: var(--ink-4); }
.env-id { display: flex; align-items: center; gap: 11px; min-width: 0; }
.env-ico { width: 32px; height: 32px; border-radius: 8px; flex: 0 0 auto; background: var(--surface-sunken); border: 1px solid var(--border); color: var(--ink-3); display: grid; place-items: center; }
.env-name { font-size: 13.5px; font-weight: 600; color: var(--ink); }
.env-company { font-size: 13px; color: var(--ink-2); min-width: 0; }
.env-act { display: flex; align-items: center; justify-content: flex-end; gap: 8px; }
/* Per-environment update window: a caption under the name + an inline editor strip. */
.env-window { margin-top: 2px; font-size: 11.5px; color: var(--ink-4); }
.env-window-edit { padding: 13px 16px; background: var(--surface-sunken); border-bottom: 1px solid var(--border); display: flex; flex-direction: column; gap: 8px; }
.env-window-edit:last-child { border-bottom: 0; }
.ewe-row { display: flex; align-items: flex-end; gap: 12px; flex-wrap: wrap; }
.ewe-time { display: flex; flex-direction: column; gap: 4px; font-size: 12px; font-weight: 600; color: var(--ink-3); }
.ewe-time .field__input {
    width: 130px; height: 36px; font: inherit; font-size: 13px; color: var(--ink);
    background: var(--surface); border: 1px solid var(--border-input); border-radius: var(--r);
    padding: 0 10px; outline: none; transition: border-color .12s, box-shadow .12s;
}
.ewe-time .field__input:focus { border-color: var(--blue); box-shadow: 0 0 0 3px var(--blue-50); }
.type-pill { display: inline-flex; align-items: center; gap: 7px; padding: 4px 10px; border-radius: 999px; font-size: 11.5px; font-weight: 600; background: var(--surface-sunken); border: 1px solid var(--border); color: var(--ink-2); width: max-content; }
.type-pill .td { width: 7px; height: 7px; border-radius: 999px; }
.type-pill.prod .td { background: var(--blue); }
.type-pill.sandbox .td { background: var(--st-untrans); }

/* ── releases list (Releases tool) ────────────────────────────────────── */
/* Inline warnings in the row meta: Force Sync mode and a vanished environment. */
.rpe-force, .rpe-missing { display: inline-flex; align-items: center; gap: 4px; color: var(--danger); font-weight: 600; }
.rpe-force svg, .rpe-missing svg { color: var(--danger); }
/* The Force-Sync / Production acknowledgement in the editor + release dialogs. */
.rpe-confirm { display: flex; align-items: flex-start; gap: 9px; margin-top: 12px; padding: 11px 13px; border: 1px solid var(--danger); border-radius: var(--r-sm); background: color-mix(in srgb, var(--danger) 7%, transparent); font-size: 12.5px; color: var(--ink-2); line-height: 1.4; }
.rpe-confirm input { margin-top: 2px; flex: 0 0 auto; }
/* Release dialog: the "when" picker row + the outside-window note. */
.rb-when-row { display: flex; align-items: center; gap: 8px; }
.rb-when-row .field__input { flex: 1; }
.rb-outside { display: inline-flex; align-items: center; gap: 5px; margin-top: 6px; color: var(--st-untrans); font-weight: 600; }
.rb-outside svg { color: var(--st-untrans); }

/* ── delivery history (release pipeline detail) ───────────────────────── */
.del-list { display: flex; flex-direction: column; gap: 10px; }
.del-row { border: 1px solid var(--border); border-radius: var(--r); padding: 13px 15px; background: var(--surface); }
.del-row-head { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.del-build { font-weight: 600; font-size: 13.5px; color: var(--ink); }
.del-when { font-size: 12px; color: var(--ink-4); }
.del-by { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--ink-3); margin-left: auto; }
.del-outside { display: inline-flex; align-items: center; gap: 4px; font-size: 11.5px; font-weight: 600; color: var(--st-untrans); }
.del-outside svg { color: var(--st-untrans); }
.del-actions { display: inline-flex; gap: 6px; }
.del-fail { margin: 9px 0 0; font-size: 12.5px; color: var(--danger); }
.del-apps { margin-top: 11px; display: flex; flex-direction: column; gap: 6px; }
.del-app { display: flex; align-items: center; gap: 9px; font-size: 12.5px; }
.del-app-dot { width: 8px; height: 8px; border-radius: 999px; flex: 0 0 auto; background: var(--ink-4); }
.del-app-dot--ok { background: var(--good); }
.del-app-dot--fail { background: var(--danger); }
.del-app-dot--busy { background: var(--st-untrans); }
.del-app-dot--skip { background: var(--border-strong); }
.del-app-dot--pending { background: var(--ink-4); opacity: .5; }
.del-app-name { font-weight: 600; color: var(--ink-2); }
.del-app-ver { color: var(--ink-4); font-variant-numeric: tabular-nums; }
.del-app-msg { color: var(--danger); }
@media (prefers-reduced-motion: no-preference) {
    .del-app-dot--busy { animation: del-pill-dot-pulse 1.4s ease-in-out infinite; }
}
@keyframes del-pill-dot-pulse { 0%,100% { opacity: 1; } 50% { opacity: .35; } }

/* ── pipelines list (links into the Pipelines tool) ───────────────────── */
.pipe-row { display: flex; align-items: center; gap: 12px; padding: 13px 14px; border: 1px solid var(--border); border-radius: var(--r); text-decoration: none; transition: border-color .12s, background .12s; }
.pipe-row + .pipe-row { margin-top: 10px; }
.pipe-row:hover { border-color: var(--blue); background: var(--surface-2); }
.pipe-ico { width: 34px; height: 34px; border-radius: 8px; background: var(--blue-50); color: var(--blue); display: grid; place-items: center; flex: 0 0 auto; }
.pipe-main { flex: 1; min-width: 0; }
.pipe-name { font-size: 13.5px; font-weight: 600; color: var(--ink); }
.pipe-row:hover .pipe-name { color: var(--blue-700); }
.pipe-meta { margin-top: 2px; font-size: 12px; color: var(--ink-4); }
.pipe-row .chev { margin-left: auto; color: var(--ink-4); display: grid; place-items: center; }

/* ============================================================================
   Your account (/account) — design handoff "Account settings.html".
   The page reuses the .set-grid sub-nav, .set-panel, .audit and .det-head
   primitives from the project-settings rework (#463); these .acc-* classes
   cover the account-specific bits the handoff adds: the identity avatar, the
   two-step-verification method cards, and the grid-based tables for passkeys,
   access tokens, connected assistants and repository providers.
   ============================================================================ */
.acc-avatar { width: 54px; height: 54px; border-radius: 999px; background: var(--blue-100); color: var(--blue-700); display: grid; place-items: center; font-size: 18px; font-weight: 700; flex: 0 0 auto; letter-spacing: .5px; }
.acc-rolepill { font-size: 11px; font-weight: 600; color: var(--blue-700); background: var(--blue-50); border-radius: 999px; padding: 3px 10px; white-space: nowrap; }

/* method cards — two-step verification, danger zone */
.acc-method { border: 1px solid var(--border); border-radius: var(--r); padding: 16px 18px; }
.acc-method + .acc-method { margin-top: 14px; }
.acc-method-h { display: flex; align-items: flex-start; gap: 13px; }
.acc-method-ico { width: 38px; height: 38px; border-radius: 9px; background: var(--surface-sunken); border: 1px solid var(--border); color: var(--ink-3); display: grid; place-items: center; flex: 0 0 auto; }
.acc-method-ico.danger { background: color-mix(in srgb, var(--danger) 12%, transparent); border-color: transparent; color: var(--danger); }
.acc-method-tt { flex: 1; min-width: 0; }
.acc-method-name { font-size: 14px; font-weight: 700; color: var(--ink); display: flex; align-items: center; gap: 9px; }
.acc-method-sub { margin-top: 4px; font-size: 12.5px; color: var(--ink-3); line-height: 1.5; max-width: 560px; }
.acc-badge { font-size: 10px; font-weight: 700; letter-spacing: .5px; text-transform: uppercase; padding: 3px 8px; border-radius: 999px; }
.acc-badge.on { color: var(--good); background: var(--good-bg); }
.acc-badge.off { color: var(--ink-4); background: var(--surface-sunken); border: 1px solid var(--border); }
.acc-method-act { display: flex; align-items: center; gap: 9px; margin-top: 15px; padding-top: 14px; border-top: 1px solid var(--border); flex-wrap: wrap; }
.acc-method-act .note { margin-left: auto; font-size: 12px; color: var(--ink-4); }
.acc-method-act .note b { color: var(--ink-2); font-weight: 600; }
.acc-method-act .inline-form { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.acc-method-act .inline-form input { max-width: 168px; }

/* grid tables — passkeys, access tokens, connected assistants, repos */
.acc-tbl { border: 1px solid var(--border); border-radius: var(--r); overflow: hidden; }
.acc-row { display: grid; align-items: center; gap: 16px; padding: 0 16px; min-height: 60px; border-bottom: 1px solid var(--border); }
.acc-row:last-child { border-bottom: 0; }
.acc-row.head { min-height: 38px; background: var(--surface-2); font-size: 10.5px; font-weight: 700; letter-spacing: .8px; text-transform: uppercase; color: var(--ink-4); }
.acc-c-name { display: flex; align-items: center; gap: 12px; min-width: 0; }
.acc-c-ico { width: 36px; height: 36px; border-radius: 8px; background: var(--surface-sunken); border: 1px solid var(--border); color: var(--ink-3); display: grid; place-items: center; flex: 0 0 auto; }
.acc-nm { font-size: 13.5px; font-weight: 600; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.acc-nsub { margin-top: 2px; font-size: 11.5px; color: var(--ink-4); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.acc-meta { font-size: 12px; color: var(--ink-3); white-space: nowrap; }
.acc-meta.mono { font-family: var(--mono); font-size: 11.5px; }
.acc-scope { display: inline-flex; align-items: center; gap: 7px; padding: 4px 10px; border-radius: 999px; font-size: 11.5px; font-weight: 600; background: var(--surface-sunken); border: 1px solid var(--border); color: var(--ink-2); justify-self: start; }
.acc-ok { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--good); font-weight: 600; }

.acc-tbl.tt-pat  .acc-row { grid-template-columns: 1.5fr 132px 118px 108px 40px; }
.acc-tbl.tt-asst .acc-row { grid-template-columns: 1.6fr 1fr 130px 40px; }
.acc-tbl.tt-repo .acc-row { grid-template-columns: 1.6fr 150px 130px 40px; }
.acc-tbl.tt-pass .acc-row { grid-template-columns: 1.6fr 130px 130px 40px; }

/* compact icon-only delete/disconnect button for table rows */
.acc-del { width: 30px; height: 30px; border-radius: 8px; border: 1px solid transparent; background: transparent; color: var(--ink-4); display: grid; place-items: center; cursor: pointer; justify-self: end; transition: background .12s, color .12s, border-color .12s; }
.acc-del:hover { background: color-mix(in srgb, var(--danger) 12%, transparent); color: var(--danger); border-color: color-mix(in srgb, var(--danger) 30%, var(--border)); }
