Files
UmbraTrans/web/assets/styles.css
umbra audio 3e0568b9d1 Generate backend endpoints for language-project workflow
Add REST endpoints and frontend wiring for per-language project actions:
- POST /api/workspace/{project}/translation/{lang}/queue — queue translation
- POST /api/workspace/{project}/audio/{lang}/queue — queue audio generation
- GET/POST /api/workspace/{project}/format/{lang} — format metadata (EPUB/PDF)
- GET /api/workspace/{project}/review/{lang}/chapters/{chapter} — utterance review
- GET/POST /api/workspace/{project}/front-matter/{lang} — front matter editor
- GET /api/workspace/{project}/chapters/{lang} — chapter list
- GET /api/workspace/{project}/chapter-content/{lang}/{chapter} — chapter text

Frontend fixes:
- Review page shows per-language text (English source, Chinese translation, etc.)
- Non-translated languages show 'Queue translation' button only
- Speaker data from English source matched by paragraph ID
- UmbraAudio column layout: Speaker, Variation, Text, Actions
- Chapter tree in left sidebar: Front matter, Back matter, Body
- Audio Format label at top of sidebar
- Pandoc formatting toolbar for front matter text editing
2026-10-25 11:04:53 -07:00

681 lines
57 KiB
CSS

:root {
--admin-bg: #1a1a2e;
--admin-panel: #16213e;
--admin-stat: #0f3460;
--admin-border: #2c3550;
--admin-border-bright: #414a68;
--admin-text: #e0e0e0;
--admin-muted: #94a3b8;
--admin-purple: #7c3aed;
--admin-lilac: #a78bfa;
--admin-blue: #3b82f6;
--admin-green: #10b981;
--admin-amber: #f59e0b;
--admin-red: #ef4444;
--workspace-bg: #0b1220;
--workspace-panel: #111c2f;
--workspace-panel-raised: #16263d;
--workspace-border: #243650;
--workspace-text: #eef2ff;
--workspace-muted: #8fa3bf;
--workspace-teal: #2dd4bf;
--workspace-amber: #fbbf24;
--workspace-blue: #60a5fa;
--shadow: 0 18px 45px rgba(0, 0, 0, .22);
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}
* { box-sizing: border-box; }
/* Author `display` rules outrank the user-agent `[hidden]` rule, and many
components here set `display`, so hiding must be stated explicitly. */
[hidden] { display: none !important; }
html { scroll-behavior: smooth; }
body { margin: 0; }
a { color: inherit; }
button, input, select { font: inherit; }
button { cursor: pointer; }
button:focus-visible, a:focus-visible, input:focus-visible, select:focus-visible { outline: 3px solid rgba(45, 212, 191, .45); outline-offset: 2px; }
/* Shared brand and status language */
.brand-lockup { display: inline-flex; align-items: center; gap: .7rem; color: var(--admin-lilac); font-weight: 800; letter-spacing: -.02em; text-decoration: none; font-size: 1.1rem; }
/* The emblem is a book shape on a transparent field, not a filled rounded tile.
The radius therefore does nothing, and the glow is applied with `filter`
rather than `box-shadow`: a box-shadow follows the border box instead of the
artwork's alpha, so the strong drop the previous filled icon carried would
read as a glowing rectangle behind the book. */
.brand-image { display: block; width: 2.55rem; height: 2.55rem; object-fit: contain; filter: drop-shadow(0 6px 14px rgba(124, 58, 237, .38)); }
.brand-lockup--rail .brand-image { width: 2.35rem; height: 2.35rem; }
.eyebrow { margin: 0 0 .45rem; color: var(--admin-lilac); font-size: .72rem; font-weight: 800; letter-spacing: .13em; text-transform: uppercase; }
.eyebrow--teal { color: var(--workspace-teal); }
.status-pill { display: inline-flex; align-items: center; gap: .35rem; width: fit-content; border-radius: 999px; padding: .28rem .6rem; font-size: .7rem; font-weight: 750; white-space: nowrap; }
.status-pill--info { color: #bfdbfe; background: #1e3a5f; }
.status-pill--success { color: #a7f3d0; background: #065f46; }
.status-pill--warning { color: #fde68a; background: #78350f; }
.status-pill--muted { color: #cbd5e1; background: #334155; }
.status-dot { display: inline-block; width: .55rem; height: .55rem; border-radius: 50%; }
.status-dot--good { background: #34d399; box-shadow: 0 0 0 .25rem rgba(52, 211, 153, .12); }
.button { display: inline-flex; align-items: center; justify-content: center; gap: .45rem; min-height: 2.45rem; border: 1px solid transparent; border-radius: .55rem; padding: .55rem .9rem; font-size: .82rem; font-weight: 750; text-decoration: none; transition: transform .15s ease, background .15s ease, border-color .15s ease; }
.button:hover { transform: translateY(-1px); }
.button--primary { color: #fff; background: var(--admin-blue); }
.button--primary:hover { background: #2563eb; }
.button--secondary { color: var(--workspace-text); background: var(--workspace-panel-raised); border-color: var(--workspace-border); }
.button--secondary:hover { border-color: var(--workspace-teal); }
.button--teal { color: #062a28; background: var(--workspace-teal); }
.button--teal:hover { background: #5eead4; }
.button--ghost { color: var(--admin-muted); background: transparent; border-color: var(--admin-border); }
.button--ghost:hover { color: var(--admin-text); border-color: var(--admin-lilac); }
.button--wide { width: 100%; }
.text-button, .admin-text-button { border: 0; background: none; color: var(--admin-lilac); font-size: .75rem; font-weight: 750; }
.text-button:hover, .admin-text-button:hover { color: #fff; text-decoration: underline; }
.muted-label { color: var(--admin-muted); font-size: .75rem; }
/* Login */
.auth-page { min-height: 100vh; color: var(--admin-text); background: radial-gradient(circle at 10% 0%, #26204b 0, transparent 34rem), var(--admin-bg); }
.auth-shell { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(22rem, 30rem); gap: clamp(2rem, 7vw, 8rem); align-items: center; width: min(1120px, calc(100% - 3rem)); min-height: 100vh; margin: 0 auto; padding: 3rem 0; }
.auth-brand { align-self: stretch; display: flex; flex-direction: column; justify-content: space-between; min-height: 40rem; padding: 1rem 0; }
.brand-copy { max-width: 34rem; margin: auto 0; }
.brand-copy h1 { max-width: 12ch; margin: 0 0 1.3rem; color: #fff; font-size: clamp(2.7rem, 6vw, 5.4rem); line-height: .98; letter-spacing: -.065em; }
.lede { max-width: 30rem; margin: 0; color: var(--admin-muted); font-size: 1.05rem; line-height: 1.7; }
.brand-points { display: grid; gap: .7rem; margin: 2.5rem 0; color: #c4b5fd; font-size: .85rem; }
.brand-points > div { display: flex; align-items: center; gap: .65rem; }
.point-dot { width: .45rem; height: .45rem; border-radius: 50%; background: var(--workspace-teal); box-shadow: 0 0 0 .3rem rgba(45, 212, 191, .12); }
.prototype-note { margin: 0; color: #64748b; font-size: .72rem; letter-spacing: .04em; }
/* The read-only account facts on the settings page. A definition list rather
than a table, because these are terms and their values, not tabular data. */
.settings-list { margin: 0 0 .4rem; padding: .1rem 0; }
.settings-list > div { display: flex; justify-content: space-between; gap: 1rem; padding: .6rem 0; border-bottom: 1px solid var(--admin-border); }
.settings-list > div:last-child { border-bottom: 0; }
.settings-list dt { color: var(--admin-muted); font-size: .78rem; }
.settings-list dd { margin: 0; color: #e2e8f0; font-size: .82rem; font-weight: 700; text-align: right; overflow-wrap: anywhere; }
/* Standing deployment notices. Never dismissible: each one describes a state
in which an action about to be taken will not work. */
.admin-banners { display: grid; gap: .6rem; margin: 0 0 1.4rem; }
.admin-banner { margin: 0; padding: .85rem 1rem; border-radius: .6rem; font-size: .8rem; line-height: 1.55; border: 1px solid; }
.admin-banner--warning { color: #fde68a; background: rgba(120, 53, 15, .45); border-color: rgba(253, 230, 138, .35); }
.admin-banner--danger { color: #fecaca; background: rgba(127, 29, 29, .45); border-color: rgba(254, 202, 202, .32); }
.admin-banner[hidden] { display: none; }
.auth-card { padding: 2rem; background: rgba(22, 33, 62, .88); border: 1px solid var(--admin-border); border-radius: 1rem; box-shadow: var(--shadow); backdrop-filter: blur(14px); }
.auth-card-heading h2 { margin: .75rem 0 .55rem; color: #fff; font-size: 1.6rem; letter-spacing: -.03em; }
.auth-card-heading p { margin: 0 0 1.7rem; color: var(--admin-muted); font-size: .86rem; line-height: 1.6; }
.stack-form { display: grid; gap: .55rem; }
.stack-form label { margin-top: .45rem; color: #c4b5fd; font-size: .74rem; font-weight: 750; }
.stack-form input, .stack-form select { width: 100%; min-height: 2.8rem; padding: .65rem .8rem; color: var(--admin-text); background: #0f172a; border: 1px solid var(--admin-border-bright); border-radius: .5rem; }
.stack-form input::placeholder { color: #64748b; }
.stack-form input:focus, .stack-form select:focus { border-color: var(--admin-purple); outline: none; box-shadow: 0 0 0 3px rgba(124, 58, 237, .18); }
.form-message { min-height: 1.2rem; margin: .35rem 0 .2rem; color: var(--admin-muted); font-size: .75rem; }
.form-message--error { color: #fca5a5; }
.form-message--success { color: #6ee7b7; }
/* Shown only once the password has already been proven correct, so it can say
why sign-in stopped without revealing whether an address has an account. */
.verify-panel { margin: 1.1rem 0 .2rem; padding: 1rem; background: rgba(30, 58, 95, .38); border: 1px solid rgba(147, 197, 253, .28); border-radius: .7rem; }
.verify-panel h3 { margin: 0 0 .4rem; color: #dbeafe; font-size: .88rem; }
.verify-panel p { margin: 0 0 .8rem; color: var(--admin-muted); font-size: .78rem; line-height: 1.6; }
.verify-panel .button { width: 100%; }
.verify-panel .form-message { margin-bottom: 0; }
.auth-divider { display: flex; align-items: center; gap: .8rem; margin: 1.6rem 0 1rem; color: #64748b; font-size: .7rem; }
.auth-divider::before, .auth-divider::after { content: ""; height: 1px; flex: 1; background: var(--admin-border); }
.admin-link { display: flex; justify-content: space-between; padding: .8rem .9rem; color: var(--admin-lilac); background: rgba(124, 58, 237, .08); border: 1px solid rgba(167, 139, 250, .3); border-radius: .55rem; font-size: .8rem; font-weight: 750; text-decoration: none; }
.admin-link:hover { background: rgba(124, 58, 237, .18); }
.auth-footnote { margin: 1.3rem 0 0; color: #64748b; font-size: .7rem; line-height: 1.5; }
/* Admin / control surface */
.admin-page { min-height: 100vh; color: var(--admin-text); background: var(--admin-bg); }
.admin-shell { min-height: 100vh; }
.admin-topbar { display: flex; align-items: center; gap: 1.5rem; min-height: 4.5rem; padding: .8rem clamp(1rem, 3vw, 3rem); background: rgba(15, 23, 42, .5); border-bottom: 1px solid var(--admin-border); }
.admin-context { display: flex; align-items: center; gap: .7rem; padding-left: 1.5rem; border-left: 1px solid var(--admin-border); }
.admin-context-name { color: var(--admin-muted); font-size: .78rem; }
.admin-top-actions { display: flex; align-items: center; gap: 1rem; margin-left: auto; }
.admin-user { display: inline-flex; align-items: center; gap: .5rem; color: #cbd5e1; font-size: .78rem; }
.admin-exit { color: var(--admin-lilac); font-size: .75rem; font-weight: 750; text-decoration: none; }
.admin-layout { display: grid; grid-template-columns: 15rem minmax(0, 1fr); min-height: calc(100vh - 4.5rem); }
.admin-sidebar { display: flex; flex-direction: column; padding: 1.5rem 1rem; background: #141c33; border-right: 1px solid var(--admin-border); }
.admin-nav-label { padding: 0 .7rem .55rem; color: #64748b; font-size: .64rem; font-weight: 800; letter-spacing: .14em; text-transform: uppercase; }
.admin-nav-label--spaced { margin-top: 1.7rem; }
.admin-nav-link { display: flex; align-items: center; gap: .7rem; margin: .15rem 0; padding: .65rem .7rem; color: var(--admin-muted); border-radius: .45rem; font-size: .8rem; font-weight: 700; text-decoration: none; }
.admin-nav-link span { width: 1rem; color: #64748b; text-align: center; }
.admin-nav-link:hover { color: #fff; background: rgba(124, 58, 237, .1); }
.admin-nav-link--active { color: #fff; background: rgba(124, 58, 237, .2); box-shadow: inset 2px 0 var(--admin-purple); }
.admin-nav-link--active span { color: var(--admin-lilac); }
.admin-sidebar-footer { margin-top: auto; padding: .8rem .7rem 0; color: #94a3b8; font-size: .68rem; line-height: 1.7; border-top: 1px solid var(--admin-border); }
.admin-sidebar-footer small { color: #64748b; }
.admin-main { width: min(1440px, 100%); margin: 0 auto; padding: clamp(1.2rem, 3vw, 2.5rem); }
.admin-banner { display: flex; align-items: center; gap: .7rem; margin-bottom: 1.6rem; padding: .7rem .9rem; color: #c4b5fd; background: rgba(124, 58, 237, .1); border: 1px solid rgba(167, 139, 250, .25); border-radius: .5rem; font-size: .73rem; }
.admin-banner strong { color: #fff; white-space: nowrap; }
.admin-heading { display: flex; align-items: end; justify-content: space-between; gap: 1.5rem; margin-bottom: 1.6rem; }
.admin-heading h1 { margin: 0 0 .35rem; color: #fff; font-size: clamp(1.9rem, 3vw, 2.7rem); letter-spacing: -.05em; }
.admin-heading p:not(.eyebrow) { margin: 0; color: var(--admin-muted); font-size: .86rem; }
.admin-stat-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1rem; margin-bottom: 1rem; }
.admin-stat, .admin-card { background: var(--admin-panel); border: 1px solid var(--admin-border); border-radius: .7rem; }
.admin-stat { padding: 1.1rem; }
.admin-stat-label { display: block; margin-bottom: .5rem; color: var(--admin-muted); font-size: .72rem; }
.admin-stat strong { display: block; color: var(--admin-purple); font-size: 2rem; letter-spacing: -.05em; }
.admin-stat small { display: block; margin-top: .35rem; color: #64748b; font-size: .68rem; }
.trend-up { color: #6ee7b7; }
.health-value { display: flex !important; align-items: center; gap: .5rem; color: #a7f3d0 !important; font-size: 1.35rem !important; }
.admin-columns { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(20rem, .9fr); gap: 1rem; margin-bottom: 1rem; }
.admin-columns--lower { grid-template-columns: minmax(0, 1.1fr) minmax(20rem, .9fr); }
.admin-card { min-width: 0; padding: 1.2rem; }
.admin-card-heading { display: flex; align-items: start; justify-content: space-between; gap: 1rem; margin-bottom: 1rem; }
.admin-card-heading h2 { margin: 0; color: #fff; font-size: 1.05rem; letter-spacing: -.02em; }
.admin-table-wrap { overflow-x: auto; }
.admin-table { width: 100%; border-collapse: collapse; font-size: .74rem; }
.admin-table th { padding: .55rem .5rem; color: var(--admin-lilac); font-size: .66rem; text-align: left; text-transform: uppercase; letter-spacing: .08em; }
.admin-table td { padding: .7rem .5rem; color: #cbd5e1; border-top: 1px solid #26334f; white-space: nowrap; }
.admin-table tbody tr:hover { background: #1e293b; }
.table-user { display: flex; align-items: center; gap: .55rem; }
.table-user > span:last-child { display: grid; gap: .12rem; }
.table-user strong { color: #f8fafc; }
.table-user small { color: #64748b; font-size: .66rem; }
.avatar { display: inline-grid; place-items: center; flex: 0 0 auto; width: 2rem; height: 2rem; color: #fff; background: #334155; border-radius: .6rem; font-size: .65rem; font-weight: 800; }
.avatar--admin { background: var(--admin-purple); }
.avatar--small { width: 1.85rem; height: 1.85rem; border-radius: .5rem; }
.avatar--teal { background: #0f766e; }
.avatar--violet { background: #7c3aed; }.avatar--blue { background: #2563eb; }.avatar--amber { background: #b45309; }.avatar--rose { background: #be185d; }
.admin-project-list { display: grid; gap: .55rem; }
.admin-project-row { display: flex; align-items: center; gap: .65rem; padding: .7rem; background: #101a30; border: 1px solid #26334f; border-radius: .5rem; }
.admin-project-row > div { display: grid; flex: 1; gap: .18rem; min-width: 0; }
.admin-project-row strong { color: #f8fafc; font-size: .78rem; }
.admin-project-row small { color: #64748b; font-size: .67rem; }
.project-mark { display: grid; place-items: center; width: 2rem; height: 2rem; border-radius: .5rem; font-size: .65rem; font-weight: 800; }
.project-mark--purple { color: #ddd6fe; background: #4c1d95; }.project-mark--blue { color: #bfdbfe; background: #1e3a8a; }.project-mark--teal { color: #99f6e4; background: #115e59; }
.admin-card--maintenance { margin-bottom: 1rem; }
.maintenance-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: .7rem; }
.maintenance-item { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: .6rem; padding: .75rem; background: #101a30; border: 1px solid #26334f; border-radius: .5rem; }
.maintenance-item > div { display: grid; gap: .2rem; min-width: 0; }
.maintenance-item strong { color: #e2e8f0; font-size: .74rem; }.maintenance-item small { color: #64748b; font-size: .65rem; white-space: nowrap; }
.maintenance-icon { display: grid; place-items: center; width: 1.8rem; height: 1.8rem; border-radius: .5rem; font-weight: 800; }
.maintenance-icon--green { color: #a7f3d0; background: #065f46; }.maintenance-icon--purple { color: #ddd6fe; background: #4c1d95; }.maintenance-icon--blue { color: #bfdbfe; background: #1e3a5f; }.maintenance-icon--amber { color: #fde68a; background: #78350f; }
.admin-chart-placeholder { padding: .7rem 0 0; }
.chart-bars { display: flex; align-items: end; gap: .45rem; height: 9rem; padding: 0 .3rem; border-bottom: 1px solid #334155; }
.chart-bars i { display: block; flex: 1; min-width: .4rem; background: linear-gradient(180deg, var(--admin-lilac), #4c1d95); border-radius: .25rem .25rem 0 0; opacity: .85; }
.chart-axis { display: flex; justify-content: space-between; padding-top: .5rem; color: #64748b; font-size: .62rem; }
.audit-list { display: grid; gap: .85rem; }
.audit-list > div { display: flex; align-items: start; gap: .6rem; }
.audit-list p { display: grid; gap: .18rem; margin: 0; }.audit-list strong { color: #e2e8f0; font-size: .75rem; }.audit-list small { color: #64748b; font-size: .66rem; }
.audit-dot { width: .55rem; height: .55rem; margin-top: .35rem; border-radius: 50%; }.audit-dot--purple { background: var(--admin-lilac); }.audit-dot--blue { background: #60a5fa; }.audit-dot--amber { background: var(--admin-amber); }
/* Workspace surface */
.workspace-page { min-height: 100vh; color: var(--workspace-text); background: var(--workspace-bg); }
.workspace-shell { display: grid; grid-template-columns: 15rem minmax(0, 1fr); min-height: 100vh; }
.workspace-rail { display: flex; flex-direction: column; padding: 1.3rem 1rem; background: #0d1728; border-right: 1px solid var(--workspace-border); }
.brand-lockup--rail { color: #c4b5fd; }
.rail-section-label { margin: 2.3rem .7rem .55rem; color: #64748b; font-size: .62rem; font-weight: 800; letter-spacing: .14em; text-transform: uppercase; }
.rail-section-label--spaced { margin-top: 1.7rem; }
.rail-nav { display: grid; gap: .2rem; }
.rail-link { display: flex; align-items: center; gap: .7rem; padding: .68rem .7rem; color: var(--workspace-muted); border-radius: .5rem; font-size: .78rem; font-weight: 700; text-decoration: none; }
.rail-link:hover { color: #fff; background: #16263d; }.rail-link--active { color: #fff; background: #1b2f4a; box-shadow: inset 2px 0 var(--workspace-teal); }
.rail-icon { width: 1.1rem; color: #5eead4; text-align: center; font-size: .95rem; }
.rail-footer { margin-top: auto; padding: .9rem .7rem 0; border-top: 1px solid var(--workspace-border); }
.rail-user { display: flex; align-items: center; gap: .55rem; margin-bottom: .8rem; }.rail-user > span:last-child { display: grid; gap: .12rem; }.rail-user strong { color: #e2e8f0; font-size: .73rem; }.rail-user small { color: #64748b; font-size: .63rem; }
.workspace-main { min-width: 0; width: min(1440px, 100%); margin: 0 auto; padding: 0 clamp(1.1rem, 3vw, 2.8rem) 3rem; }
.workspace-topbar { display: flex; align-items: center; justify-content: space-between; min-height: 4.5rem; gap: 1rem; border-bottom: 1px solid var(--workspace-border); }
.breadcrumb { display: flex; align-items: center; gap: .55rem; color: #64748b; font-size: .74rem; }.breadcrumb strong { color: #cbd5e1; }.topbar-actions { display: flex; align-items: center; gap: .8rem; }.icon-button { display: grid; place-items: center; width: 2rem; height: 2rem; color: #93c5fd; background: #16263d; border: 1px solid #2b4363; border-radius: .5rem; }.topbar-admin-link { color: #5eead4; font-size: .72rem; font-weight: 750; text-decoration: none; }
.workspace-hero { display: flex; align-items: end; justify-content: space-between; gap: 1.5rem; padding: 2.6rem 0 2rem; }.workspace-hero h1 { margin: 0 0 .45rem; font-size: clamp(2.2rem, 5vw, 4rem); letter-spacing: -.06em; }.hero-subtitle { max-width: 38rem; margin: 0; color: var(--workspace-muted); font-size: .9rem; line-height: 1.6; }.hero-actions { display: flex; gap: .6rem; flex-wrap: wrap; }
.pipeline-card, .workspace-panel { padding: 1.2rem; background: var(--workspace-panel); border: 1px solid var(--workspace-border); border-radius: .8rem; }.pipeline-card { margin-bottom: 1rem; }.section-heading { display: flex; align-items: start; justify-content: space-between; gap: 1rem; }.section-heading h2 { margin: 0; font-size: 1.05rem; letter-spacing: -.02em; }.section-heading .text-button { color: var(--workspace-teal); }
.pipeline-track { display: flex; align-items: center; margin-top: 1.5rem; overflow-x: auto; padding: .25rem 0 .4rem; }.pipeline-step { display: grid; justify-items: center; gap: .2rem; min-width: 5.5rem; text-align: center; }.pipeline-number { display: grid; place-items: center; width: 2rem; height: 2rem; color: #64748b; background: #1b2a40; border: 2px solid #3b4d69; border-radius: 50%; font-size: .72rem; font-weight: 800; }.pipeline-step strong { color: #cbd5e1; font-size: .72rem; }.pipeline-step small { color: #64748b; font-size: .62rem; }.pipeline-step--done .pipeline-number { color: #99f6e4; background: #115e59; border-color: #2dd4bf; }.pipeline-step--active .pipeline-number { color: #062a28; background: var(--workspace-teal); border-color: var(--workspace-teal); }.pipeline-step--active strong { color: #fff; }.pipeline-line { flex: 1; min-width: 1.2rem; height: 2px; margin: 0 .4rem 1.6rem; background: #2b3c58; }.pipeline-line--done { background: #2dd4bf; }
/* Project list on the member dashboard. The card is the unit of a project as
everybody in the organization sees it: visible to all, worked on by some. The
"assigned to you" marker is therefore a fact about the caller, not a filter on
the row - which is why it sits inside the row rather than replacing it. */
.project-list { display: grid; gap: .55rem; margin-top: .8rem; }
.list-summary { margin: .7rem 0 0; color: var(--workspace-muted); font-size: .7rem; }
.list-summary--error { color: #fca5a5; }
.project-card { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: .8rem; padding: .8rem .9rem; background: var(--workspace-panel-raised); border: 1px solid var(--workspace-border); border-left: 3px solid var(--workspace-border); border-radius: .6rem; }
.project-card--active { border-left-color: var(--workspace-teal); }
.project-card--on_hold { border-left-color: #fcd34d; }
.project-card--released { border-left-color: #93c5fd; }
.project-card--archived { border-left-color: #475569; opacity: .72; }
.project-card__main { display: grid; gap: .3rem; min-width: 0; }
.project-card__name { overflow: hidden; color: #e2e8f0; font-size: .85rem; font-weight: 750; text-overflow: ellipsis; white-space: nowrap; }
.project-card__meta { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; color: #64748b; font-size: .65rem; }
.project-card__slug { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.project-card__side { display: flex; align-items: center; gap: .45rem; }
.marker--mine { color: #99f6e4; background: #115e59; }
.marker--unclaimed { color: #fcd34d; background: #78350f; }
.chip { padding: .3rem .6rem; color: var(--workspace-muted); background: transparent; border: 1px solid var(--workspace-border); border-radius: 999px; font: inherit; font-size: .68rem; cursor: pointer; }
.chip:hover { color: var(--workspace-text); border-color: #3b5273; }
.chip--active { color: #0b1120; background: var(--workspace-teal); border-color: var(--workspace-teal); font-weight: 750; }
.chip:focus-visible { outline: 2px solid var(--workspace-teal); outline-offset: 2px; }
.metric-card strong[data-empty="true"] { color: #475569; }
.metric-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: .8rem; margin-bottom: 1rem; }.metric-card { display: grid; gap: .3rem; padding: 1rem; background: var(--workspace-panel-raised); border: 1px solid var(--workspace-border); border-radius: .7rem; }.metric-label { color: var(--workspace-muted); font-size: .68rem; }.metric-card strong { font-size: 1.8rem; letter-spacing: -.05em; }.metric-note { color: #64748b; font-size: .65rem; }.metric-note--good { color: #6ee7b7; }.metric-note--warn { color: #fcd34d; }
.workspace-columns { display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(18rem, .75fr); gap: 1rem; margin-bottom: 1rem; }.workspace-panel { min-width: 0; }.language-list { display: grid; gap: .2rem; margin-top: 1rem; }.language-row { display: grid; grid-template-columns: 2.2rem minmax(8rem, 1fr) minmax(5rem, .8fr) 2.5rem auto; align-items: center; gap: .7rem; padding: .65rem .2rem; border-top: 1px solid #1e2f48; }.language-code { display: grid; place-items: center; width: 2rem; height: 2rem; color: #bfdbfe; background: #1e3a5f; border-radius: .5rem; font-size: .62rem; font-weight: 800; }.language-code--source { color: #99f6e4; background: #115e59; }.language-name { display: grid; gap: .15rem; }.language-name strong { font-size: .76rem; }.language-name small { color: #64748b; font-size: .63rem; }.progress-track { height: .35rem; overflow: hidden; background: #243650; border-radius: 999px; }.progress-track span { display: block; height: 100%; background: linear-gradient(90deg, #14b8a6, #5eead4); border-radius: inherit; }.language-percent { color: #cbd5e1; font-size: .7rem; text-align: right; }
.cast-summary { display: flex; align-items: center; gap: 1rem; margin: 1.1rem 0 1.2rem; }.cast-summary p { margin: .35rem 0 0; color: #64748b; font-size: .68rem; line-height: 1.5; }.cast-ring { display: grid; place-items: center; width: 4.6rem; height: 4.6rem; border: 5px solid #1f4152; border-top-color: var(--workspace-teal); border-right-color: var(--workspace-teal); border-radius: 50%; }.cast-ring strong { font-size: .8rem; }.cast-ring span { color: #64748b; font-size: .55rem; }.cast-avatars { display: flex; padding-left: .3rem; }.cast-avatar { display: grid; place-items: center; width: 2rem; height: 2rem; margin-left: -.3rem; color: #e0e7ff; border: 2px solid var(--workspace-panel); border-radius: 50%; font-size: .58rem; font-weight: 800; }.cast-avatar--one { background: #7c3aed; }.cast-avatar--two { background: #2563eb; }.cast-avatar--three { background: #b45309; }.cast-avatar--four { background: #be185d; }.cast-avatar--more { color: #94a3b8; background: #243650; }
.activity-list { display: grid; gap: .2rem; margin-top: 1rem; }.activity-row { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: .7rem; padding: .7rem .2rem; border-top: 1px solid #1e2f48; }.activity-row > div { display: grid; gap: .15rem; }.activity-row strong { font-size: .76rem; }.activity-row small { color: #64748b; font-size: .63rem; }.activity-icon { display: grid; place-items: center; width: 1.8rem; height: 1.8rem; border-radius: .5rem; font-weight: 800; }.activity-icon--teal { color: #99f6e4; background: #115e59; }.activity-icon--amber { color: #fde68a; background: #78350f; }.activity-icon--blue { color: #bfdbfe; background: #1e3a5f; }
/* Modal and toast */
.modal-backdrop { position: fixed; inset: 0; z-index: 20; display: grid; place-items: center; padding: 1rem; background: rgba(2, 6, 23, .78); backdrop-filter: blur(7px); }.modal-backdrop[hidden] { display: none; }.modal { width: min(100%, 32rem); max-height: calc(100vh - 2rem); overflow: auto; padding: 1.3rem; background: var(--admin-panel); border: 1px solid var(--admin-border-bright); border-radius: .8rem; box-shadow: var(--shadow); }.modal-heading { display: flex; justify-content: space-between; gap: 1rem; }.modal-heading h2 { margin: 0; color: #fff; }.modal-close { width: 2rem; height: 2rem; color: #94a3b8; background: transparent; border: 1px solid var(--admin-border); border-radius: .5rem; font-size: 1.2rem; }.modal-notice { margin: 1rem 0; padding: .75rem; color: #c4b5fd; background: rgba(124, 58, 237, .1); border: 1px solid rgba(167, 139, 250, .25); border-radius: .5rem; font-size: .72rem; line-height: 1.55; }.modal-notice strong { color: #fff; }.checkbox-row { display: flex !important; align-items: center; gap: .5rem; margin-top: .8rem; color: #cbd5e1 !important; font-weight: 500 !important; }.checkbox-row input { width: auto; min-height: auto; }.modal-actions { display: flex; justify-content: end; gap: .6rem; margin-top: 1.2rem; }.toast { position: fixed; right: 1.2rem; bottom: 1.2rem; z-index: 30; max-width: min(26rem, calc(100% - 2rem)); padding: .8rem 1rem; color: #e0e7ff; background: #1e293b; border: 1px solid #475569; border-radius: .6rem; box-shadow: var(--shadow); font-size: .75rem; opacity: 0; transform: translateY(.6rem); pointer-events: none; transition: opacity .2s ease, transform .2s ease; }.toast--visible { opacity: 1; transform: translateY(0); }
/* ========================================================================
Real application components.
Everything above this line is the original prototype design system. The
rules below extend it for API-driven pages: view panels, filter toolbars,
tables with row actions, pagination, empty and loading states, the
one-time-password reveal panel, and the form controls the new dialogs use.
No `@import`, no remote font, no inline style: the page ships a single
stylesheet that the Content-Security-Policy allows.
======================================================================== */
/* Focus is always visible for every interactive surface, including the ones
added with the API-driven pages. */
textarea:focus-visible, [tabindex]:focus-visible, .password-toggle:focus-visible,
.modal-close:focus-visible, .icon-button:focus-visible, .admin-nav-link:focus-visible,
.rail-link:focus-visible, summary:focus-visible, .otp-value:focus-visible {
outline: 3px solid rgba(45, 212, 191, .55);
outline-offset: 2px;
}
html.modal-open { overflow: hidden; }
.visually-hidden { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
/* View panels: the console is one document with four switchable sections. */
.admin-view[hidden] { display: none; }
.admin-nav { display: grid; gap: .2rem; }
.admin-service-line { display: flex; align-items: center; gap: .5rem; margin: 0 0 .3rem; color: #cbd5e1; }
.admin-user-detail { display: grid; gap: .1rem; }
.admin-user-detail strong { color: #e2e8f0; font-size: .76rem; }
.admin-user-detail small { color: #64748b; font-size: .66rem; }
.status-dot--warning { background: var(--admin-amber); box-shadow: 0 0 0 .25rem rgba(245, 158, 11, .14); }
.admin-card + .admin-card { margin-top: 1rem; }
.admin-view > .admin-card { margin-bottom: 1rem; }
.loading-note { margin: 0; padding: .6rem 0; color: var(--admin-muted); font-size: .74rem; }
[aria-busy="true"] { opacity: .7; }
/* Filter and toolbar rows */
.toolbar { display: flex; flex-wrap: wrap; align-items: end; gap: .7rem; margin-bottom: 1.1rem; padding-bottom: 1.1rem; border-bottom: 1px solid var(--admin-border); }
.filter-field { display: grid; gap: .3rem; min-width: 9rem; }
.filter-field label { color: var(--admin-muted); font-size: .66rem; font-weight: 750; letter-spacing: .04em; text-transform: uppercase; }
.filter-field select { min-height: 2.35rem; padding: .4rem .6rem; color: var(--admin-text); background: #0f172a; border: 1px solid var(--admin-border-bright); border-radius: .45rem; font-size: .76rem; }
.filter-field select:focus { border-color: var(--admin-purple); outline: none; box-shadow: 0 0 0 3px rgba(124, 58, 237, .18); }
.toolbar-actions { display: flex; gap: .5rem; margin-left: auto; }
.toolbar-actions .button { min-height: 2.35rem; }
/* Tables */
.admin-table--wide { min-width: 60rem; }
.admin-table--audit { min-width: 78rem; }
.admin-table td { vertical-align: middle; }
.admin-table th[scope="col"] { white-space: nowrap; }
.table-row--state:hover { background: transparent; }
.table-state { padding: 1.4rem .6rem !important; text-align: center; white-space: normal; }
.table-state .empty-state { border: 0; background: none; padding: 0; }
.count { color: #f8fafc; font-size: .84rem; }
.cell-stack { display: grid; gap: .28rem; justify-items: start; }
.cell-email { font-size: .76rem; overflow-wrap: anywhere; }
/* A status pill that is also a control. It must not look like the inert pills
beside it, and it must not look like a plain button either, so it keeps the
pill and adds the affordance: pointer, underline on hover, and a focus ring
that survives the rounded shape. */
.status-pill--action { cursor: pointer; border: 1px solid rgba(253, 230, 138, .45); font: inherit; text-align: left; }
.status-pill--action:hover:not(:disabled) { background: #92400e; }
.status-pill--action:focus-visible { outline: 2px solid #fde68a; outline-offset: 2px; }
.status-pill--action:disabled { cursor: progress; opacity: .65; }
.cell-note { color: #64748b; font-size: .66rem; white-space: normal; }
.slug, .action-code, .id-code { color: #c4b5fd; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: .68rem; }
.id-code { color: #7dd3fc; }
.row-actions { display: flex; flex-wrap: wrap; gap: .3rem; }
.row-actions .button { min-height: 1.85rem; padding: .25rem .5rem; font-size: .66rem; }
.button[disabled] { cursor: not-allowed; opacity: .45; }
.button[disabled]:hover { transform: none; }
/* Pagination */
.pagination { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .7rem; margin-top: .9rem; padding-top: .9rem; border-top: 1px solid var(--admin-border); }
.pagination__info { color: var(--admin-muted); font-size: .72rem; }
.pagination__buttons { display: flex; gap: .45rem; }
.pagination__buttons .button { min-height: 2.1rem; padding: .35rem .7rem; font-size: .7rem; }
/* Empty states, used by tables and by the whole workspace page */
/* Assigning an account to a project. The assigned state is marked on the row as
well as in the button label, so the list reads as "who is on this" at a glance
rather than requiring each button to be read. */
.member-list { display: grid; gap: .3rem; max-height: 22rem; overflow-y: auto; margin: .8rem 0; }
.member-row { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: .7rem; padding: .5rem .6rem; border: 1px solid #1e2f48; border-radius: .5rem; }
.member-row--assigned { border-color: #115e59; background: rgba(15, 118, 110, .14); }
.member-row__name { display: grid; gap: .1rem; min-width: 0; }
.member-row__name strong { overflow: hidden; font-size: .78rem; text-overflow: ellipsis; white-space: nowrap; }
.member-row__name small { overflow: hidden; color: #64748b; font-size: .63rem; text-overflow: ellipsis; white-space: nowrap; }
.empty-state { display: grid; justify-items: start; gap: .4rem; margin-top: .9rem; padding: 1.1rem; background: #101a30; border: 1px dashed #2c3c5c; border-radius: .6rem; }
.empty-state__icon { display: grid; place-items: center; width: 2rem; height: 2rem; color: #5eead4; background: #0f2a35; border-radius: .5rem; font-size: .9rem; }
.empty-state__title { margin: 0; color: #e2e8f0; font-size: .8rem; font-weight: 750; }
.empty-state__body { max-width: 46rem; margin: 0; color: #7c8db0; font-size: .73rem; line-height: 1.6; }
.empty-state .button { margin-top: .4rem; }
#summary-grid .empty-state { grid-column: 1 / -1; }
/* Audit: recent list on the dashboard, sanitized detail on the full table */
.audit-list-item { display: flex; align-items: start; gap: .6rem; padding: .5rem 0; border-top: 1px solid #26334f; }
.audit-list-item:first-child { border-top: 0; padding-top: 0; }
.audit-list-body { display: grid; gap: .18rem; min-width: 0; }
.audit-list-title { display: flex; align-items: center; flex-wrap: wrap; gap: .5rem; margin: 0; }
.audit-list-title strong { color: #e2e8f0; font-size: .76rem; }
.audit-list-body small { color: #64748b; font-size: .66rem; }
.detail-list { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: .2rem .55rem; margin: 0; max-width: 26rem; }
.detail-list dt { color: #7c8db0; font-size: .66rem; white-space: nowrap; }
.detail-list dd { margin: 0; color: #cbd5e1; font-size: .68rem; overflow-wrap: anywhere; }
/* One-time password reveal */
.otp-warning { margin: 1rem 0 0; padding: .8rem .9rem; color: #fde68a; background: rgba(120, 53, 15, .3); border: 1px solid rgba(245, 158, 11, .45); border-radius: .5rem; font-size: .73rem; line-height: 1.6; }
.otp-warning strong { color: #fff; }
.otp-panel { margin: .9rem 0; padding: 1rem; background: #0b1226; border: 1px solid var(--admin-purple); border-radius: .6rem; box-shadow: 0 0 0 3px rgba(124, 58, 237, .12); }
.otp-panel-head { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: .6rem; margin-bottom: .7rem; }
.otp-panel-target { color: var(--admin-muted); font-size: .74rem; }
.otp-panel-target strong { color: #fff; }
.otp-value-row { display: flex; align-items: stretch; flex-wrap: wrap; gap: .6rem; }
.otp-value { flex: 1 1 12rem; min-width: 0; padding: .75rem .8rem; color: #fff; background: #020617; border: 1px solid var(--admin-border-bright); border-radius: .5rem; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: .98rem; letter-spacing: .05em; overflow-wrap: anywhere; user-select: all; }
.otp-hint { min-height: 1.05rem; margin: .55rem 0 0; color: #6ee7b7; font-size: .7rem; line-height: 1.5; }
.otp-notice { margin: 0; color: #64748b; font-size: .7rem; line-height: 1.55; }
.modal--wide { width: min(100%, 40rem); }
/* Form controls shared by the dialogs */
.form-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .7rem; }
.form-field { display: grid; gap: .32rem; align-content: start; }
.form-field > label:first-child { margin-top: .35rem; }
.field-hint { margin: 0; color: #64748b; font-size: .67rem; line-height: 1.5; }
.field-label { margin-top: .35rem; color: #c4b5fd; font-size: .74rem; font-weight: 750; }
.field-optional { color: #64748b; font-weight: 500; text-transform: none; letter-spacing: 0; }
.readonly-value { margin: 0; padding: .55rem .7rem; color: #e2e8f0; background: #0f172a; border: 1px solid var(--admin-border); border-radius: .5rem; font-size: .78rem; overflow-wrap: anywhere; }
.enrollment-fieldset { display: grid; gap: .5rem; margin: .6rem 0 0; padding: .85rem; border: 1px solid var(--admin-border); border-radius: .5rem; }
.enrollment-fieldset legend { padding: 0 .35rem; color: #c4b5fd; font-size: .72rem; font-weight: 800; }
.radio-row { display: flex !important; align-items: start; gap: .6rem; margin-top: 0 !important; padding: .55rem .6rem; color: #cbd5e1 !important; background: #101a30; border: 1px solid #26334f; border-radius: .45rem; font-weight: 500 !important; cursor: pointer; }
.radio-row:hover { border-color: var(--admin-purple); }
.radio-row input { width: auto; min-height: auto; margin-top: .15rem; }
.radio-row span { display: grid; gap: .15rem; }
.radio-row strong { color: #f1f5f9; font-size: .76rem; }
.radio-row small { color: #7c8db0; font-size: .67rem; line-height: 1.5; }
.permission-note { margin: 0 0 1rem; padding: .8rem .9rem; color: #c4b5fd; background: rgba(124, 58, 237, .1); border: 1px solid rgba(167, 139, 250, .28); border-radius: .5rem; font-size: .73rem; line-height: 1.6; }
.permission-note strong { color: #fff; }
/* Sign-in: password reveal control and the policy reminder */
.password-field { display: flex; align-items: stretch; gap: .4rem; }
.stack-form .password-field input { flex: 1; min-width: 0; }
.password-toggle { flex: 0 0 auto; padding: 0 .7rem; color: var(--admin-muted); background: #0f172a; border: 1px solid var(--admin-border-bright); border-radius: .5rem; font-size: .7rem; font-weight: 750; }
.password-toggle:hover { color: var(--admin-text); border-color: var(--admin-purple); }
.password-toggle[aria-pressed="true"] { color: #fff; background: rgba(124, 58, 237, .22); border-color: var(--admin-purple); }
.policy-list { margin: 0 0 1.2rem; padding: .85rem .95rem; background: #0f172a; border: 1px solid var(--admin-border); border-radius: .5rem; }
.policy-title { margin: 0 0 .45rem; color: #c4b5fd; font-size: .68rem; font-weight: 800; letter-spacing: .11em; text-transform: uppercase; }
.policy-list ul { margin: 0; padding-left: 1.15rem; color: var(--admin-muted); font-size: .73rem; line-height: 1.75; }
.prototype-note--live { color: #94a3b8; }
.topbar-signout { color: var(--workspace-teal); }
@media (max-width: 1000px) {
.auth-shell { grid-template-columns: 1fr; gap: 1.5rem; width: min(38rem, calc(100% - 2rem)); padding: 2rem 0; }.auth-brand { min-height: 0; gap: 3rem; }.brand-copy { margin: 2rem 0; }.brand-copy h1 { max-width: 15ch; font-size: 3.4rem; }.brand-points { margin: 1.5rem 0; }
.admin-stat-grid, .maintenance-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }.admin-columns, .admin-columns--lower, .workspace-columns { grid-template-columns: 1fr; }
.workspace-rail { width: 13rem; }.workspace-shell { grid-template-columns: 13rem minmax(0, 1fr); }
.toolbar-actions { margin-left: 0; }
}
@media (max-width: 720px) {
.admin-layout, .workspace-shell { display: block; }.admin-sidebar, .workspace-rail { min-height: auto; border-right: 0; border-bottom: 1px solid var(--admin-border); }.workspace-rail { padding: .8rem 1rem; }.rail-section-label, .rail-section-label--spaced, .rail-footer { display: none; }.rail-nav { display: flex; gap: .25rem; overflow-x: auto; }.rail-link { white-space: nowrap; }.rail-link:not(.rail-link--active) { display: flex; }.workspace-rail .brand-lockup { margin-bottom: .6rem; }.workspace-topbar { min-height: 3.7rem; }.status-pill { display: none; }.workspace-hero { display: block; padding: 1.8rem 0 1.2rem; }.hero-actions { margin-top: 1rem; }.metric-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }.language-row { grid-template-columns: 2.2rem minmax(0, 1fr) auto; }.language-row .progress-track, .language-row .language-percent { display: none; }.admin-topbar { flex-wrap: wrap; gap: .7rem; }.admin-context { padding-left: 0; border-left: 0; }.admin-top-actions { width: 100%; margin-left: 0; justify-content: space-between; }.admin-heading { display: block; }.admin-heading .button { margin-top: 1rem; }.admin-stat strong { font-size: 1.6rem; }
/* --- navigation on a narrow screen ---------------------------------------
The old breakpoint hid navigation rather than relocating it:
`.admin-sidebar { display: none }`, `.rail-link:not(.rail-link--active)
{ display: none }` and `.topbar-admin-link { display: none }`. On a phone that
left the console showing the page you were on and no way to reach any other, and
there was no hamburger because nothing had been built for a narrow screen.
The rule now: at any width, every navigation link is reachable. Above the
breakpoint the rail and sidebar are on screen as before and the toggle is hidden.
Below it the toggle appears and `.nav-open` on the body reveals the nav as a drawer
over the content.
The drawer is positioned rather than shown inline, because an inline nav pushes the
page down by its own height every time it opens - so on a short viewport the page
the operator asked for ends up below the fold. */
[data-nav-toggle] {
display: inline-flex; align-items: center; justify-content: center;
width: 2.4rem; height: 2.4rem; margin-right: .5rem; padding: 0;
color: var(--workspace-teal, #5eead4); background: transparent;
border: 1px solid var(--admin-border, #1e293b); border-radius: .45rem;
font-size: 1.05rem; line-height: 1; cursor: pointer;
/* nodes.html carries its navigation inline in <main>, not in a sidebar, so there is
nothing to put in a drawer and a hamburger there would toggle nothing. Its nav was a
single horizontal scroll strip instead, which hides links off the right edge with no
indication that there are more - so it wraps instead. Every link visible, no control
needed. */
.admin-main .admin-nav { flex-wrap: wrap; overflow-x: visible; gap: .35rem; }
.admin-main .admin-nav-link { flex: 1 1 8rem; justify-content: center; }
}
[data-nav-toggle]:focus-visible { outline: 2px solid #5eead4; outline-offset: 2px; }
[data-nav-toggle][hidden] { display: none; }
/* `display: none` rather than `visibility: hidden` so a closed drawer leaves the tab
order as well as the screen. A screen reader should not walk a menu nobody can open,
and a phone with a screen reader is the case that matters. */
.admin-sidebar { display: none; }
body.nav-open .admin-sidebar,
body.nav-open .workspace-rail {
display: block; position: fixed; inset: 3.7rem 0 0 0; z-index: 40;
overflow-y: auto; border-bottom: 0; background: #0d172a; padding: 1rem;
}
body.nav-open .admin-sidebar .admin-nav-link,
body.nav-open .workspace-rail .rail-link { padding: .8rem .7rem; }
body.nav-open .workspace-rail .rail-link:not(.rail-link--active) { display: flex; }
.rail-nav { display: grid; gap: .2rem; }
.rail-link { white-space: normal; }
.topbar-admin-link { display: inline-flex; }
.form-row { grid-template-columns: 1fr; }.filter-field { min-width: 7rem; flex: 1 1 7rem; }.toolbar-actions { width: 100%; margin-left: 0; }.toolbar-actions .button { flex: 1; }
.admin-table--wide, .admin-table--audit { min-width: 46rem; }.otp-value-row .button { width: 100%; }
.pagination { justify-content: stretch; }.pagination__info { width: 100%; }.pagination__buttons .button { flex: 1; }
}
/* The sudo prerequisites beside the "expect to run as root" checkbox. Two steps, and
the second cannot be run until the first is true, so they are numbered rather than
left as a paragraph. Deliberately plain: this is read on the machine it describes. */
.root-access-steps {
margin: .55rem 0 0;
padding-left: 1.15rem;
color: var(--admin-muted);
font-size: .67rem;
line-height: 1.6;
}
.root-access-steps li { margin-bottom: .5rem; }
.root-access-steps strong { color: #e2e8f0; font-weight: 700; }
.root-access-steps code {
color: var(--admin-lilac);
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
font-size: .95em;
word-break: break-all;
}
/* === Umbra Tools New Shell === */
:root {
--shell-bg: #0b1020;
--shell-panel: #0f1529;
--shell-border: #1f2937;
--shell-text: #e5e7eb;
--shell-muted: #94a3b8;
--shell-accent: #22d3ee;
--shell-accent-2: #38bdf8;
}
[data-theme="light"] {
--shell-bg: #f8fafc;
--shell-panel: #ffffff;
--shell-border: #e5e7eb;
--shell-text: #0f172a;
--shell-muted: #475569;
--shell-accent: #06b6d4;
--shell-accent-2: #2563eb;
}
.umbra-shell { display: grid; grid-template-rows: 4rem 1fr; grid-template-columns: 280px 1fr; grid-template-areas: "topbar topbar" "sidebar main"; min-height: 100vh; background: var(--shell-bg); color: var(--shell-text); }
.umbra-topbar { grid-area: topbar; display: grid; grid-template-columns: 280px 1fr auto; align-items: center; gap: 1rem; padding: 0 1rem; background: linear-gradient(180deg, rgba(30,41,59,.9), rgba(15,23,42,.9)); border-bottom: 1px solid var(--shell-border); }
.umbra-topbar__left { display: flex; align-items: center; gap: .75rem; }
.umbra-topbar__logo { width: 28px; height: 28px; border-radius: 6px; }
.umbra-topbar__brand { font-weight: 800; letter-spacing: .02em; }
.umbra-topbar__mode { background: var(--shell-panel); color: var(--shell-text); border: 1px solid var(--shell-border); border-radius: .5rem; padding: .4rem .6rem; }
.umbra-topbar__middle { color: var(--shell-muted); font-weight: 600; }
.umbra-topbar__right { display: flex; align-items: center; gap: .6rem; }
.umbra-user { display: flex; align-items: center; gap: .5rem; }
.umbra-user__meta { display: flex; flex-direction: column; line-height: 1.1; }
.umbra-user__name { font-size: .9rem; }
.umbra-user__role { font-size: .72rem; color: var(--shell-muted); }
.umbra-dropdown { background: var(--shell-panel); color: var(--shell-text); border: 1px solid var(--shell-border); border-radius: .5rem; padding: .35rem .5rem; }
.umbra-sidebar { grid-area: sidebar; background: var(--shell-panel); border-right: 1px solid var(--shell-border); padding: .8rem; overflow-y: auto; }
.umbra-sidebar__section { margin-bottom: 1rem; }
.umbra-sidebar__title { color: var(--shell-muted); text-transform: uppercase; font-size: .7rem; letter-spacing: .12em; margin: .4rem 0 .6rem; }
.umbra-nav__item { display: flex; align-items: center; gap: .5rem; width: 100%; text-align: left; background: transparent; color: var(--shell-text); border: 0; padding: .5rem .6rem; border-radius: .5rem; cursor: pointer; text-decoration: none; }
.umbra-nav__item:hover { background: rgba(56,189,248,.12); }
.umbra-nav__item--active { background: linear-gradient(90deg, rgba(34,211,238,.18), transparent); border-left: 2px solid var(--shell-accent); }
.umbra-main { grid-area: main; padding: 1.2rem 1.6rem; overflow-y: auto; }
.project-row { display: grid; grid-template-columns: 1.2fr 1fr auto; gap: 1rem; align-items: center; padding: .8rem 1rem; background: var(--shell-panel); border: 1px solid var(--shell-border); border-radius: .7rem; margin-bottom: .6rem; }
.project-row__lang { font-weight: 700; }
.project-row__status { color: var(--shell-muted); }
.project-row__actions { display: flex; gap: .4rem; flex-wrap: wrap; }
.btn { background: linear-gradient(180deg, rgba(56,189,248,.9), rgba(14,165,233,.9)); color: white; border: 0; border-radius: .5rem; padding: .4rem .7rem; cursor: pointer; }
.btn--ghost { background: transparent; color: var(--shell-text); border: 1px solid var(--shell-border); }
.btn--subtle { background: rgba(148,163,184,.18); color: var(--shell-text); border: 1px solid var(--shell-border); }
.format-tabs { display: flex; gap: .4rem; margin-bottom: 1rem; }
.format-tab { padding: .4rem .7rem; border-radius: .5rem; border: 1px solid var(--shell-border); background: var(--shell-panel); color: var(--shell-text); cursor: pointer; }
.format-tab--active { background: rgba(34,211,238,.18); border-color: rgba(34,211,238,.6); }
.form-grid { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: .8rem; }
.form-grid__full { grid-column: 1 / -1; }
.input { width: 100%; background: var(--shell-panel); color: var(--shell-text); border: 1px solid var(--shell-border); border-radius: .5rem; padding: .5rem .6rem; }
.binder { display: grid; grid-template-columns: 260px 1fr; gap: 1rem; }
.binder__tree { background: var(--shell-panel); border: 1px solid var(--shell-border); border-radius: .7rem; padding: .6rem; }
.binder__editor { background: var(--shell-panel); border: 1px solid var(--shell-border); border-radius: .7rem; padding: 1rem; min-height: 70vh; }
.tree__item { padding: .35rem .5rem; border-radius: .4rem; cursor: pointer; }
.tree__item:hover { background: rgba(56,189,248,.12); }
.versions { display: flex; gap: .4rem; flex-wrap: wrap; }
.version-pill { padding: .3rem .5rem; border-radius: .4rem; border: 1px solid var(--shell-border); background: var(--shell-panel); color: var(--shell-text); cursor: pointer; }
.audio-layout { display: grid; grid-template-columns: 260px 1fr; gap: 1rem; }
.audio-sidebar { background: var(--shell-panel); border: 1px solid var(--shell-border); border-radius: .7rem; padding: .6rem; }
.audio-main { background: var(--shell-panel); border: 1px solid var(--shell-border); border-radius: .7rem; padding: 1rem; }
/* === Umbra Tools shell: additions === */
.umbra-topbar__brandlink { display: flex; align-items: center; gap: .6rem; color: inherit; text-decoration: none; }
.umbra-main--framed { padding: 0; }
.umbra-frame { display: block; width: 100%; height: 100%; min-height: calc(100vh - 4rem); border: 0; background: var(--shell-bg); }
.umbra-heading { margin-bottom: 1.2rem; }
.umbra-heading--row { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
.umbra-heading h1 { margin: .1rem 0 .3rem; font-size: 1.5rem; }
.umbra-heading .lede { margin: 0; color: var(--shell-muted); max-width: 60ch; }
.umbra-heading .eyebrow { margin: 0; color: var(--shell-accent); text-transform: uppercase; letter-spacing: .12em; font-size: .7rem; font-weight: 700; }
.umbra-inline-actions { display: flex; gap: .5rem; flex-wrap: wrap; margin-top: 1rem; }
.project-row__sub { display: block; color: var(--shell-muted); font-size: .72rem; font-weight: 500; margin-top: .1rem; }
.versions__label { color: var(--shell-muted); font-size: .78rem; margin-right: .2rem; }
/* Disabled controls must be legibly disabled, not just inert. */
.btn[disabled], .umbra-nav__item[disabled] { opacity: .5; cursor: not-allowed; }
.btn:disabled { cursor: not-allowed; }
/* === Umbra Tools shell: embedded admin views === */
.audit-row { display: grid; grid-template-columns: 12rem 1fr auto; gap: .8rem; align-items: center; padding: .5rem .2rem; border-bottom: 1px solid var(--shell-border); }
.audit-row__when { color: var(--shell-muted); font-size: .78rem; }
.audit-row__action { font-weight: 600; }
.admin-table td .empty-state { padding: 1rem 0; }
.umbra-main .admin-card { background: var(--shell-panel); border: 1px solid var(--shell-border); border-radius: .7rem; }
/* === Program / language selector visibility === */
.umbra-topbar__mode--hidden { display: none !important; }
/* Project rows list (program detail) */
.project-rows { display: flex; flex-direction: column; gap: .4rem; margin-top: 1rem; }
/* Language row (program detail view) */
.language-row { display: grid; grid-template-columns: 1fr auto; gap: 1rem; align-items: center; padding: .75rem 1rem; background: var(--shell-panel); border: 1px solid var(--shell-border); border-radius: .7rem; margin-bottom: .6rem; cursor: pointer; }
.language-row:hover { background: rgba(56,189,248,.06); }
.language-row--selected { border-color: rgba(34,211,238,.6); background: rgba(34,211,238,.08); }
.language-row__label { display: flex; flex-direction: column; gap: .15rem; }
.language-row__label strong { font-weight: 700; }
.language-row__role { font-size: .7rem; color: var(--shell-muted); }
.language-row__actions { display: flex; gap: .35rem; flex-wrap: wrap; }
/* Binder tree groups */
.tree__group { color: var(--shell-muted); text-transform: uppercase; font-size: .7rem; letter-spacing: .12em; margin: .5rem 0 .3rem; padding: 0 .5rem; }
/* Control panel: no topbar name when no program */
#topbar-language-name { color: var(--shell-text); font-weight: 700; }
/* Language detail panel */
.language-detail { margin-top: 1.5rem; }
.language-detail .umbra-heading { margin-bottom: 1rem; }
.language-detail table { margin-top: 0.5rem; }
/* Language row compact actions */
.language-row__actions .btn { font-size: 0.8rem; padding: 0.3rem 0.5rem; }
.language-row__actions a.btn--ghost { font-size: 0.8rem; padding: 0.3rem 0.5rem; }
/* Ensure program selector fits in topbar */
.umbra-topbar__middle { display: flex; align-items: center; gap: 0.5rem; }
#program-select { min-width: 200px; }
/* Audio layout */
.audio-layout { display: grid; grid-template-columns: 260px 1fr; gap: 1rem; }
.audio-sidebar { background: var(--shell-panel); border: 1px solid var(--shell-border); border-radius: .7rem; padding: .6rem; }
.audio-main { background: var(--shell-panel); border: 1px solid var(--shell-border); border-radius: .7rem; padding: 1rem; }
.audio-section-list { list-style: none; padding: 0; margin: 1rem 0 0 0; }
.audio-section-list li { padding: .4rem .6rem; border-radius: .4rem; cursor: pointer; }
.audio-section-list li:hover { background: rgba(56,189,248,.12); }
/* Chapter review placeholder */
.chapter-review-placeholder { margin-top: 1rem; }
/* Language detail panel spacing */
.language-detail { margin-top: 1.5rem; }
.language-detail .umbra-heading { margin-bottom: 1rem; }
.language-detail table { margin-top: 0.5rem; }
/* Program selector width */
#program-select { min-width: 220px; }
/* Language row compact actions */
.language-row__actions .btn { font-size: 0.8rem; padding: 0.3rem 0.5rem; }
.language-row__actions a.btn--ghost { font-size: 0.8rem; padding: 0.3rem 0.5rem; }
/* Ensure program selector fits in topbar */
.umbra-topbar__middle { display: flex; align-items: center; gap: 0.5rem; }
/* Utterance review */
.utterance-list { margin-top: 1rem; border: 1px solid var(--shell-border); border-radius: .6rem; background: var(--shell-panel); }
.utterance-row { display: grid; grid-template-columns: 130px 90px 1fr 140px; gap: .5rem; padding: .5rem .75rem; border-bottom: 1px solid var(--shell-border); font-size: .85rem; }
.utterance-row:last-child { border-bottom: none; }
.utterance__id { font-family: monospace; color: var(--shell-muted); }
.utterance__text { color: var(--shell-text); }
.utterance__speaker { display: flex; align-items: center; }
/* Front matter panel */
.front-matter-panel { margin-top: 1.5rem; border: 1px solid var(--shell-border); border-radius: .6rem; background: var(--shell-panel); padding: 1rem; }
.front-matter-panel h3 { margin: 0 0 .75rem 0; font-size: .9rem; color: var(--shell-muted); }
.fm-item { display: grid; grid-template-columns: 160px 1fr 120px 120px; gap: .5rem; align-items: center; margin-bottom: .5rem; }
.fm-item label { font-size: .85rem; color: var(--shell-text); }
.fm-item input, .fm-item select { font-size: .85rem; }
/* Utterance review panel */
.utterance-review-panel { margin-top: 1rem; border: 1px solid var(--shell-border); border-radius: .6rem; background: var(--shell-panel); padding: 1rem; }
.utterance-header { display: grid; grid-template-columns: 140px 1fr 180px; gap: .5rem; padding: .5rem .75rem; border-bottom: 2px solid var(--shell-border); font-size: .85rem; font-weight: bold; color: var(--shell-muted); }
.chapter-select { width: 160px; margin-bottom: 0.75rem; }
/* Chapter items in edit sidebar */
.tree__item--chapter { padding: 0.4rem 0.6rem; cursor: pointer; border-radius: 0.3rem; font-size: 0.85rem; }
.tree__item--chapter:hover { background: rgba(56,189,248,0.12); }
.tree__item--chapter.tree__item--active { background: #38bdf8; color: #0b1220; }
/* Format toolbar */
.format-toolbar { margin: 0.75rem 0; padding: 0.5rem; background: var(--shell-panel); border: 1px solid var(--shell-border); border-radius: 0.5rem; display: flex; gap: 0.4rem; }
.format-toolbar .btn { font-size: 0.8rem; padding: 0.3rem 0.6rem; }
/* Edit main content layout */
.edit-main-content { margin-top: 1rem; }
/* Utterance row speaker select */
.utterance-row select { font-size: 0.8rem; }