/* ── Admin redesign, stage 1 (docs/admin-ux-concept.md) ────────── Loaded last from admin.css, so it overrides the earlier sheets rather than rewriting them. Stage 1: the sidebar shell, the overview page, the site's typography and a calmer use of the accent. */ /* ── Tokens ────────────────────────────────────────────────── */ .admin-layout, .admin-listbox-popup { /* The site's own fonts (set on by the root layout from the preset). The fallbacks are what the admin used before. */ --admin-font: var( --font-sans, -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif ); --admin-font-label: var(--font-caption, ui-monospace, 'SF Mono', Menlo, monospace); --admin-bg: #0c0c0c; --admin-bg-raised: #141414; --admin-bg-elevated: #1b1b1b; --admin-bg-input: #101010; --admin-border: #242424; --admin-border-hover: #3a3a3a; --admin-sidebar-bg: #090909; --admin-radius: 4px; --admin-sidebar-width: 232px; /* The one outer content column every workspace screen shares. Pages, Overview and Diagnostics used to end at three different right edges (QA A-18). Up to a 1592px window every screen simply fills the workspace; wider, they all stop here instead of each at its own cap. Text inside keeps its own narrower measure (the 70ch details). Only the split editors (journal, content pages) break out of it. */ --admin-content-width: 1280px; --admin-workspace-pad-x: 2.5rem; font-family: var(--admin-font); } [data-theme='light'] .admin-layout, [data-theme='light'] .admin-listbox-popup { --admin-bg: #f6f6f5; --admin-bg-raised: #ffffff; --admin-bg-elevated: #efefee; --admin-bg-input: #ffffff; --admin-border: #e2e2e0; --admin-border-hover: #c8c8c5; --admin-sidebar-bg: #fbfbfa; } .admin-listbox-popup { font-family: var(--admin-font); } /* ── Shell: sidebar + workspace ────────────────────────────── */ .admin-app { display: grid; grid-template-columns: var(--admin-sidebar-width) minmax(0, 1fr); flex-direction: unset; min-height: 100vh; } .admin-sidebar { position: sticky; top: 0; height: 100vh; display: flex; flex-direction: column; gap: 1.25rem; padding: 1.25rem 0.75rem 1rem; background: var(--admin-sidebar-bg); border-right: 1px solid var(--admin-border); overflow-y: auto; z-index: 50; } .admin-brand { display: flex; align-items: center; gap: 0.7rem; padding: 0.25rem 0.6rem 0.75rem; color: var(--admin-text); text-decoration: none; } /* The square marker the site uses for kickers and the header dot. */ .admin-brand-mark { width: 10px; height: 10px; background: var(--admin-accent); flex-shrink: 0; } .admin-brand-text { display: flex; flex-direction: column; line-height: 1.15; } .admin-brand-name { font-size: 0.8rem; font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; } .admin-brand-sub { font-family: var(--admin-font-label); font-size: 0.65rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--admin-text-muted); } .admin-nav { display: flex; flex-direction: column; gap: 1rem; flex: 1; } .admin-nav-group { display: flex; flex-direction: column; gap: 1px; } .admin-nav-label { padding: 0 0.6rem 0.35rem; font-family: var(--admin-font-label); font-size: 0.62rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--admin-text-muted); } .admin-nav-item { position: relative; display: flex; align-items: center; gap: 0.65rem; padding: 0.5rem 0.6rem; border-radius: var(--admin-radius); color: var(--admin-text-secondary); font-size: 0.85rem; text-decoration: none; transition: color 0.15s ease, background 0.15s ease; } .admin-nav-item:hover { color: var(--admin-text); background: var(--admin-bg-raised); } .admin-nav-item.active { color: var(--admin-text); background: var(--admin-bg-elevated); } /* One of the accent's three jobs: where you are. */ .admin-nav-item.active::before { content: ''; position: absolute; left: -0.75rem; top: 50%; width: 3px; height: 18px; transform: translateY(-50%); background: var(--admin-accent); } .admin-nav-icon { display: inline-flex; color: var(--admin-text-muted); } .admin-nav-item.active .admin-nav-icon { color: var(--admin-text); } .admin-nav-text { flex: 1; } .admin-nav-count { min-width: 1.35rem; padding: 0.05rem 0.4rem; border-radius: 999px; background: var(--admin-accent); color: var(--admin-on-accent); font-family: var(--admin-font-label); font-size: 0.68rem; text-align: center; } .admin-nav-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--admin-error); } .admin-sidebar-foot { display: flex; flex-direction: column; gap: 0.5rem; padding-top: 0.75rem; border-top: 1px solid var(--admin-border); } .admin-sidebar .status-indicator-container { display: block; margin: 0; } .admin-sidebar .sidebar-status { width: 100%; justify-content: flex-start; } /* In the sidebar foot the dropdown opens upwards, as wide as the foot. The sidebar scrolls (overflow-y: auto), which clips sideways too: a fixed 280px panel lost its values past the 232px column. */ .admin-sidebar .status-dropdown { top: auto; bottom: 100%; left: 0; right: 0; margin: 0 0 0.5rem; width: auto; border-radius: var(--admin-radius); } .admin-sidebar .status-item { gap: 0.75rem; } .admin-sidebar .status-val { text-align: right; } /* The collapsed sidebar does not clip (overflow: visible below), so the panel keeps its width and opens out of the 64px column. */ .admin-app.is-collapsed .admin-sidebar .status-dropdown { right: auto; width: 280px; } .admin-sidebar-actions { display: flex; flex-direction: column; gap: 1px; } .admin-side-action { display: flex; align-items: center; gap: 0.6rem; width: 100%; padding: 0.45rem 0.6rem; border: none; border-radius: var(--admin-radius); background: none; color: var(--admin-text-muted); font: inherit; font-size: 0.8rem; text-align: left; text-decoration: none; cursor: pointer; } .admin-side-action:hover:not(:disabled) { color: var(--admin-text); background: var(--admin-bg-raised); } .admin-side-action:disabled { opacity: 0.5; cursor: wait; } .admin-workspace { max-width: calc(var(--admin-content-width) + 2 * var(--admin-workspace-pad-x)); padding: 2.25rem var(--admin-workspace-pad-x) 6rem; margin: 0; } /* The save bar centres on the workspace, not on the window. */ .admin-app ~ .floating-save-bar, .admin-app .floating-save-bar { left: calc(50% + var(--admin-sidebar-width) / 2); } @media (max-width: 860px) { .admin-app { grid-template-columns: 1fr; } .admin-sidebar { position: static; height: auto; border-right: none; border-bottom: 1px solid var(--admin-border); } .admin-nav { flex-direction: row; flex-wrap: wrap; gap: 0.25rem 1rem; } .admin-nav-item.active::before { display: none; } .admin-workspace { padding: 1.5rem 1rem 6rem; } .admin-app .floating-save-bar { left: 50%; } } /* ── Calmer accent ─────────────────────────────────────────── */ /* A switched-on card keeps a hairline; its switch carries the state. A thick accent frame on every active card turned Studio Modern's settings into a wall of red and took the colour's meaning with it. */ .admin-layout .admin-toggle-card.active { border-color: var(--admin-border-hover); box-shadow: none; } .admin-layout .admin-toggle-card, .admin-layout .settings-group, .admin-layout .analytics-panel, .admin-layout .metric-card, .admin-layout .messages-list { border-radius: var(--admin-radius); } /* Section and field labels in the site's caption voice. */ .admin-layout .admin-field > label, .admin-layout .settings-group-title { font-family: var(--admin-font-label); letter-spacing: 0.12em; } /* Panel headings are headings, not captions: the caption font made the analytics titles a mixed-case line of monospace (QA A-18). They read like the settings section headings; monospace stays with the paths. */ .admin-layout .settings-section-header h3, .admin-layout .analytics-header h2, .admin-layout .analytics-section-title h3 { font-family: var(--admin-font); font-weight: 500; letter-spacing: -0.01em; } /* Section icons stay neutral; the accent is not decoration. */ .admin-layout .settings-section-header h3 svg, .admin-layout .analytics-header h2 svg, .admin-layout .analytics-section-title h3 svg { color: var(--admin-text-muted); } /* ── Overview ──────────────────────────────────────────────── */ .admin-overview { display: flex; flex-direction: column; gap: 2.5rem; } .overview-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 1rem; flex-wrap: wrap; } .overview-kicker { display: flex; align-items: center; gap: 0.5rem; margin: 0 0 0.6rem; font-family: var(--admin-font-label); font-size: 0.7rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--admin-text-muted); } .overview-kicker::before { content: ''; width: 7px; height: 7px; background: var(--admin-accent); } .overview-title { margin: 0; font-size: clamp(1.8rem, 3vw, 2.4rem); font-weight: 500; letter-spacing: -0.02em; } .overview-sub { margin: 0.4rem 0 0; color: var(--admin-text-secondary); font-size: 0.9rem; } .overview-section-label { margin: 0 0 0.9rem; font-family: var(--admin-font-label); font-size: 0.68rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--admin-text-muted); } .overview-attention { display: flex; flex-direction: column; border: 1px solid var(--admin-border); border-radius: var(--admin-radius); background: var(--admin-bg-raised); } .overview-attention-item { display: flex; align-items: center; gap: 0.9rem; padding: 0.95rem 1.1rem; color: var(--admin-text); text-decoration: none; font-size: 0.9rem; } .overview-attention-item + .overview-attention-item { border-top: 1px solid var(--admin-border); } .overview-attention-item:hover { background: var(--admin-bg-elevated); } .overview-attention-marker { width: 8px; height: 8px; flex-shrink: 0; } .overview-attention-marker.accent { background: var(--admin-accent); } .overview-attention-marker.warn { background: var(--admin-warning); } .overview-attention-marker.error { background: var(--admin-error); } .overview-attention-text { flex: 1; } .overview-attention-detail { display: block; max-width: 70ch; margin-top: 0.15rem; color: var(--admin-text-muted); font-size: 0.8rem; } .overview-attention-go { font-family: var(--admin-font-label); font-size: 0.68rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--admin-text-muted); } .overview-calm { margin: 0; padding: 1rem 1.1rem; border: 1px dashed var(--admin-border); border-radius: var(--admin-radius); color: var(--admin-text-muted); font-size: 0.88rem; } .overview-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 1px; border: 1px solid var(--admin-border); border-radius: var(--admin-radius); background: var(--admin-border); overflow: hidden; } .overview-stat { display: flex; flex-direction: column; gap: 0.35rem; padding: 1.2rem 1.25rem 1.1rem; background: var(--admin-bg-raised); color: inherit; text-decoration: none; } .overview-stat:hover { background: var(--admin-bg-elevated); } .overview-stat-value { font-size: 2rem; font-weight: 500; letter-spacing: -0.02em; line-height: 1; } .overview-stat-label { font-family: var(--admin-font-label); font-size: 0.66rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--admin-text-muted); } .overview-stat-note { color: var(--admin-text-secondary); font-size: 0.78rem; } .overview-actions { display: flex; flex-wrap: wrap; gap: 0.6rem; } /* Same rule for the metadata master card: its switch says it is on. */ .admin-layout .metadata-card.active { border-color: var(--admin-border-hover); box-shadow: none; } /* A chosen option (preset, frame, layout…) is a place, so it keeps the accent, but as a hairline rather than a doubled frame. */ .admin-layout .preset-card.active, .admin-layout .preset-btn.active { box-shadow: none; } /* Page builder section icons: neutral, like the settings headers. */ .admin-layout .builder-section-header h2 svg { color: var(--admin-text-muted); } /* "Disabled" is a state, not an error. The badge sets its red inline, hence !important; stage 2 moves the colour into the stylesheet (after #711). */ .admin-layout .subpage-badge-protected[title='Page is disabled'] { background: rgba(0, 0, 0, 0.72) !important; color: var(--admin-text-secondary) !important; border: 1px solid var(--admin-border-hover); } /* Every screen starts at the same left edge (stage 2 adds the shared page header). */ .admin-layout .diag-page { margin-left: 0; } /* ── Page header (stage 2) ─────────────────────────────────── */ .page-header { display: flex; align-items: flex-end; justify-content: space-between; gap: 1rem 2rem; flex-wrap: wrap; margin: 0 0 2rem; padding-bottom: 1.25rem; border-bottom: 1px solid var(--admin-border); } .page-header-kicker { display: flex; align-items: center; gap: 0.5rem; margin: 0 0 0.55rem; font-family: var(--admin-font-label); font-size: 0.68rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--admin-text-muted); } .page-header-kicker::before { content: ''; width: 7px; height: 7px; background: var(--admin-accent); } .page-header-title { display: flex; align-items: center; gap: 0.6rem; margin: 0; font-size: clamp(1.5rem, 2.4vw, 1.9rem); font-weight: 500; letter-spacing: -0.02em; } .page-header-sub { margin: 0.35rem 0 0; max-width: 62ch; color: var(--admin-text-secondary); font-size: 0.88rem; line-height: 1.5; } .page-header-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; } /* The journal list is an ordinary screen and gets the workspace column; only the editor (split view) needs the full width journal-studio.css gives it. */ .admin-app .admin-main:has(> .journal-studio) { max-width: calc(var(--admin-content-width) + 2 * var(--admin-workspace-pad-x)); padding: 2.25rem var(--admin-workspace-pad-x) 6rem; } @media (max-width: 860px) { .admin-app .admin-main:has(> .journal-studio) { padding: 1.5rem 1rem 6rem; } } /* ── Confirm dialog (stage 3) ──────────────────────────────── */ .confirm-backdrop { position: fixed; inset: 0; z-index: 1200; display: grid; place-items: center; padding: 1rem; background: var(--admin-overlay); } .confirm-card { width: min(420px, 100%); padding: 1.4rem 1.5rem 1.2rem; border: 1px solid var(--admin-border-hover); border-radius: var(--admin-radius); background: var(--admin-bg-raised); color: var(--admin-text); font-family: var(--admin-font); box-shadow: 0 24px 60px rgba(0, 0, 0, 0.45); } .confirm-title { margin: 0; font-size: 1.1rem; font-weight: 500; } .confirm-message { margin: 0.5rem 0 0; color: var(--admin-text-secondary); font-size: 0.88rem; line-height: 1.5; } .confirm-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 0.5rem; margin-top: 1.4rem; } .admin-btn.confirm-danger { background: var(--admin-error); border-color: var(--admin-error); color: #fff; } /* A caption over a group of buttons or a self-labelled switch: looks like a field label, but is not a