phase: 92_theme_save_and_coverage
**Phase 92 final verification pass — all green.** This pass re-verified the completed tasks (all 5 task files already in `complete/`) against every completion criterion; no defects found, nothing to fix. - Verified: 9th identity var `grid_line` end-to-end (migration `0015` at head, model/`theming.py`/schemas/API, 422 + built-in→NULL tests present); `styles.css` zero hardcoded literals outside `:root` + derived `--brand-*` vars; 9th picker in theme form; wordmark themed; `theme.js` save/reset/re-show/mount live-sync; dedicated E2E suite + phase-91 suite updated. - `uv run pytest --cov=app --cov-report=term-missing` → **1845 passed, exit 0, TOTAL 99%** (>90%) - `uv run ruff check .` → clean; `uv run pyright` → 0 errors, 0 warnings - `uv run pytest tests/e2e/test_theme_save_and_coverage.py -v --no-cov` → **3 passed** (save-live, reset-live, whole-site) - `uv run pytest tests/e2e/test_admin_theme_tab.py -v --no-cov` → **5 passed** - Criteria: (1) Save/Reset repaint open page, no nav, SPA-nav survives, pre-paint intact ✅; (2) both `rg` gates green (only `:root` + documented `#fff` Stop label; zero SVG hex attrs), grid/selection/hovers/wash/wordmark E2E-proven ✅; (3) no-op contract live-checked: row-less `/` = no tag + exact A1 CSP, grid-only row = 9-var tag in `COLOR_FIELDS` order + sha256 CSP, with-row ≡ row-less bytes ✅; (4) full suite/coverage/lint/both E2E ✅; (5) commit left to the harness per instructions. - Deviations (previously made, probe-verified, kept): live repaint uses CSSOM `<html>` overrides because Chromium blocks `<style>` textContent mutations under the locked sha256-only CSP (tag text still mirrors the next load; `<html>` style exact-saved after Save, empty after Reset); wordmark themed via 3 `.brand-mark` CSS rules instead of inline styles (task 03's inline attrs were CSP-blocked — fixed during task 04). - Next pending phase: none — `todo/` contains only `92_theme_save_and_coverage`.
This commit is contained in:
+97
-63
@@ -11,10 +11,21 @@
|
||||
--ink: #f0e6e6;
|
||||
--ink-soft: #b8a8a8; /* 5.1:1 on --surface */
|
||||
--line: #2d1a1a; /* decorative 1px borders */
|
||||
--grid-line: #4a2626; /* background grid texture — decorative, no
|
||||
contrast duty (like --line) */
|
||||
--brand: #f43f5e; /* text on brand is DARK ink (--bg): 5.2:1 —
|
||||
never white on brand (3.7:1, fails) */
|
||||
--brand-soft: #2d0a0a;
|
||||
--brand-ink: #fca5a5; /* 9.0:1 on --surface, 12.4:1 on --brand-soft */
|
||||
|
||||
/* Derived state colors (phase 92, task 02) — COMPUTED in :root from
|
||||
the identity palette via color-mix(): NOT stored, NOT tab-controlled,
|
||||
NOT in BUILTIN_COLORS (theming.py). Every state follows the theme;
|
||||
the built-in defaults reproduce the pre-phase-92 look, or are the
|
||||
deliberate legacy-indigo fixes (hovers, busy). */
|
||||
--brand-hover: color-mix(in srgb, var(--brand) 86%, white);
|
||||
--brand-busy: color-mix(in srgb, var(--brand) 40%, white);
|
||||
--brand-stop: color-mix(in srgb, var(--brand) 75%, var(--bg));
|
||||
--accent-bg: #2b2110;
|
||||
--accent-ink: #fbbf24; /* 9.5:1 on --accent-bg */
|
||||
--accent-line: #f59e0b; /* 8.9:1 on --bg (deflection border) */
|
||||
@@ -74,12 +85,15 @@ body {
|
||||
static: the 44px grid texture below — zero animation cost, zero JS,
|
||||
no filter/blur. */
|
||||
|
||||
/* Static grid texture: 44px cells, 1px lines at 60% --line alpha, masked
|
||||
/* Static grid texture: 44px cells, 1px lines at 60% --grid-line, masked
|
||||
with a widened radial fade (visible across most of the viewport,
|
||||
fading to the corners). Phase 25 (owner 2026-08-25): the grid drift is
|
||||
REMOVED — the 0.73px/s sub-pixel drift rasterizes as a once-per-second
|
||||
down-right jitter, and the owner wants no movement. The grid stays as
|
||||
a still texture. */
|
||||
a still texture. Phase 92 (task 02): the line color is the 9th
|
||||
identity variable --grid-line (the built-in at 60% alpha — the tab's
|
||||
"Grid lines" picker repaints this texture; it was a hardcoded
|
||||
literal before). */
|
||||
body::before {
|
||||
content: "";
|
||||
position: fixed;
|
||||
@@ -87,8 +101,8 @@ body::before {
|
||||
z-index: -1;
|
||||
pointer-events: none;
|
||||
background-image:
|
||||
linear-gradient(to right, rgb(74 38 38 / 0.6) 1px, transparent 1px),
|
||||
linear-gradient(to bottom, rgb(74 38 38 / 0.6) 1px, transparent 1px);
|
||||
linear-gradient(to right, color-mix(in srgb, var(--grid-line) 60%, transparent) 1px, transparent 1px),
|
||||
linear-gradient(to bottom, color-mix(in srgb, var(--grid-line) 60%, transparent) 1px, transparent 1px);
|
||||
background-size: 44px 44px;
|
||||
-webkit-mask-image: radial-gradient(140% 110% at 50% 0%, black 40%, transparent 90%);
|
||||
mask-image: radial-gradient(140% 110% at 50% 0%, black 40%, transparent 90%);
|
||||
@@ -136,7 +150,7 @@ body::before {
|
||||
}
|
||||
|
||||
::selection {
|
||||
background: rgb(244 63 94 / 0.45);
|
||||
background: color-mix(in srgb, var(--brand) 45%, transparent);
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
@@ -154,11 +168,14 @@ body::before {
|
||||
(e.g. Sources at ≤640px). */
|
||||
flex-shrink: 0;
|
||||
}
|
||||
/* 2px brand→cyan gradient hairline under the sticky header (phase 08;
|
||||
shared by the app header and the document-viewer header, phase 10).
|
||||
In the viewer's two-row header (phase 34) this lands at the BOTTOM
|
||||
edge of the whole header — row 1's own copy is suppressed there (see
|
||||
the .doc-header rules below). */
|
||||
/* 2px brand-fade hairline under the sticky header (phase 08; shared by
|
||||
the app header and the document-viewer header, phase 10). Phase 92
|
||||
(task 02): the pre-theme rose→orange→amber art direction retires —
|
||||
the 2px line now fades from the brand (55% → 30% → 5% of --brand)
|
||||
and follows the theme (deliberate default change). In the viewer's
|
||||
two-row header (phase 34) this lands at the BOTTOM edge of the whole
|
||||
header — row 1's own copy is suppressed there (see the .doc-header
|
||||
rules below). */
|
||||
.app-header::after,
|
||||
.doc-header::after {
|
||||
content: "";
|
||||
@@ -169,9 +186,9 @@ body::before {
|
||||
pointer-events: none;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
rgb(244 63 94 / 0.55),
|
||||
rgb(251 146 60 / 0.30) 45%,
|
||||
rgb(251 191 36 / 0.05) 90%
|
||||
color-mix(in srgb, var(--brand) 55%, transparent),
|
||||
color-mix(in srgb, var(--brand) 30%, transparent) 45%,
|
||||
color-mix(in srgb, var(--brand) 5%, transparent) 90%
|
||||
);
|
||||
}
|
||||
/* margin-left:auto on the nav (not justify-content:space-between) so the
|
||||
@@ -209,6 +226,16 @@ body::before {
|
||||
white-space: nowrap;
|
||||
}
|
||||
.brand-mark { width: 22px; height: 22px; flex: 0 0 auto; display: block; }
|
||||
/* The wordmark's theming resolves HERE from :root — the markup carries
|
||||
no inline style attributes: this policy's style-src (phase 82 A1:
|
||||
'self' + the theme tag's sha256, no 'unsafe-inline') blocks inline
|
||||
style attributes (hashes never cover them), so the identity vars
|
||||
land via this stylesheet instead (CSP-clean 'self'). The :nth-child
|
||||
keys follow the wordmark's fixed 3-shape markup (hexagon, dot,
|
||||
spokes) — identical in all five HTML files. */
|
||||
.brand-mark path:nth-child(1) { fill: var(--surface); stroke: var(--brand); }
|
||||
.brand-mark circle { fill: var(--brand); }
|
||||
.brand-mark path:nth-child(3) { fill: none; stroke: var(--brand-ink); }
|
||||
.brand-text strong { color: var(--brand-ink); font-weight: 700; }
|
||||
|
||||
.app-nav { display: flex; gap: 0.25rem; margin-left: auto; }
|
||||
@@ -255,7 +282,7 @@ body::before {
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
}
|
||||
.new-chat-btn:hover { background: #f55a72; color: var(--bg); }
|
||||
.new-chat-btn:hover { background: var(--brand-hover); color: var(--bg); }
|
||||
/* The plus mark is hidden on desktop (label carries the pill); it is the
|
||||
whole control below 640px. */
|
||||
.new-chat-btn svg { width: 16px; height: 16px; display: none; }
|
||||
@@ -289,7 +316,7 @@ body::before {
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
}
|
||||
.share-chat-btn:hover { background: #f55a72; color: var(--bg); }
|
||||
.share-chat-btn:hover { background: var(--brand-hover); color: var(--bg); }
|
||||
/* The link mark is hidden on desktop (the label carries the pill); it
|
||||
is the whole control below 640px (mirrored in the ≤640 block
|
||||
below). */
|
||||
@@ -462,8 +489,8 @@ body::before {
|
||||
}
|
||||
.bubble p { margin: 0.2rem 0; }
|
||||
.bubble pre {
|
||||
background: #1a0f0f;
|
||||
color: #e6d0d0;
|
||||
background: var(--surface);
|
||||
color: var(--ink);
|
||||
padding: 0.7rem 0.9rem;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-sm);
|
||||
@@ -502,7 +529,7 @@ body::before {
|
||||
color: var(--bg);
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
.msg.user .bubble code { background: rgb(10 14 23 / 0.16); }
|
||||
.msg.user .bubble code { background: color-mix(in srgb, var(--bg) 16%, transparent); }
|
||||
|
||||
.msg.brain .bubble { border-bottom-left-radius: 4px; }
|
||||
.msg.brain.is-deflected .bubble {
|
||||
@@ -646,7 +673,7 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.source-chip:hover { background: #2a345f; text-decoration: underline; }
|
||||
.source-chip:hover { background: var(--brand-soft); text-decoration: underline; }
|
||||
|
||||
/* "Maybe try" chips under a deflected bubble (phase 04). Unlike the
|
||||
onboarding row (which scrolls horizontally on mobile), this group wraps
|
||||
@@ -792,7 +819,7 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
font: inherit;
|
||||
font-size: 0.9rem;
|
||||
color: var(--ink);
|
||||
background: #1a0f0f;
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: 0.5rem 0.6rem;
|
||||
@@ -814,7 +841,7 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
}
|
||||
.tune-save:hover:not(:disabled) { background: #7d88f5; }
|
||||
.tune-save:hover:not(:disabled) { background: var(--brand-hover); }
|
||||
.tune-save:disabled { opacity: 0.6; cursor: wait; }
|
||||
.tune-cancel {
|
||||
display: inline-flex;
|
||||
@@ -836,7 +863,7 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
margin: 0.2rem 0 0 0.25rem;
|
||||
background: var(--ok-bg);
|
||||
color: var(--ok-ink);
|
||||
border: 1px solid rgb(110 231 168 / 0.35);
|
||||
border: 1px solid color-mix(in srgb, var(--ok-ink) 35%, transparent);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: 0.45rem 0.8rem;
|
||||
font-size: 0.85rem;
|
||||
@@ -878,7 +905,7 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
gap: 0.6rem;
|
||||
background: #1a0f0f;
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: 0.35rem 0.4rem 0.35rem 0.8rem;
|
||||
@@ -980,7 +1007,7 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
}
|
||||
#tune-save:hover:not(:disabled) { background: #7d88f5; }
|
||||
#tune-save:hover:not(:disabled) { background: var(--brand-hover); }
|
||||
#tune-save:disabled { opacity: 0.6; cursor: wait; }
|
||||
|
||||
/* Notes list — the phase-15 steering panel's language at full column
|
||||
@@ -1057,7 +1084,7 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
gap: 0.5rem;
|
||||
background: #1a0f0f;
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--brand-soft);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: 0.6rem 0.7rem;
|
||||
@@ -1085,7 +1112,7 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
.tuning-saved {
|
||||
background: var(--ok-bg);
|
||||
color: var(--ok-ink);
|
||||
border: 1px solid rgb(110 231 168 / 0.35);
|
||||
border: 1px solid color-mix(in srgb, var(--ok-ink) 35%, transparent);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: 0.45rem 0.8rem;
|
||||
font-size: 0.85rem;
|
||||
@@ -1198,7 +1225,7 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
cursor: pointer;
|
||||
transition: background 0.15s ease, transform 0.05s ease;
|
||||
}
|
||||
.suggestion-chip:hover { background: #2a345f; }
|
||||
.suggestion-chip:hover { background: var(--brand-soft); }
|
||||
.suggestion-chip:active { transform: scale(0.98); }
|
||||
|
||||
/* ---------- Composer ---------- */
|
||||
@@ -1317,22 +1344,26 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
cursor: pointer;
|
||||
padding-inline: 1rem;
|
||||
}
|
||||
.send-btn:hover:not(:disabled) { background: #7d88f5; }
|
||||
.send-btn:disabled { background: #a5b4fc; cursor: not-allowed; }
|
||||
.send-btn:hover:not(:disabled) { background: var(--brand-hover); }
|
||||
.send-btn:disabled { background: var(--brand-busy); cursor: not-allowed; }
|
||||
|
||||
/* Phase 48 (2026-08-29, TODO.md L3): the in-flight Stop treatment — one
|
||||
button, two roles. Rose-700 #be123c (the brand rose #f43f5e darkened)
|
||||
with a #fff label = 6.3:1 (WCAG AA); the hover step #9f1239 holds
|
||||
8.0:1. Same radius/height/hit target as the Send state and the shared
|
||||
:focus-visible ring — the .is-stop class rides the same .send-btn
|
||||
element, and the later rules win the hover specificity tie. */
|
||||
.send-btn.is-stop { background: #be123c; color: #fff; }
|
||||
.send-btn.is-stop:hover { background: #9f1239; }
|
||||
button, two roles. --brand-stop (the brand darkened 75% toward --bg;
|
||||
the built-in default mixes to ≈ (187, 50, 73)) with a white label =
|
||||
5.8:1 (WCAG AA); the hover step (--brand at 55% toward --bg) holds
|
||||
8.5:1. white is the ONE literal allowed outside :root — the dark bg
|
||||
ink on the stop fill is only ≈3.4:1 (fails AA). Same radius/height/
|
||||
hit target as the Send state and the shared :focus-visible ring — the
|
||||
.is-stop class rides the same .send-btn element, and the later rules
|
||||
win the hover specificity tie. */
|
||||
.send-btn.is-stop { background: var(--brand-stop); color: #fff; }
|
||||
.send-btn.is-stop:hover { background: color-mix(in srgb, var(--brand) 55%, var(--bg)); }
|
||||
|
||||
/* Busy spinner: dark arc (--bg) on the #a5b4fc busy button = 9.7:1. */
|
||||
/* Busy spinner: dark arc (--bg) on the --brand-busy button ≈ 11.3:1
|
||||
(well above the 9:1 floor the phase-48 note pinned for the arc). */
|
||||
.spinner {
|
||||
width: 16px; height: 16px;
|
||||
border: 2.5px solid rgb(10 14 23 / 0.30);
|
||||
border: 2.5px solid color-mix(in srgb, var(--bg) 30%, transparent);
|
||||
border-top-color: var(--bg);
|
||||
border-radius: 50%;
|
||||
animation: spin 0.8s linear infinite;
|
||||
@@ -1389,7 +1420,7 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
}
|
||||
.stale-regenerate:hover { background: #f55a72; color: var(--bg); }
|
||||
.stale-regenerate:hover { background: var(--brand-hover); color: var(--bg); }
|
||||
.stale-regenerate:disabled { opacity: 0.6; cursor: wait; }
|
||||
.stale-regenerate svg { width: 16px; height: 16px; display: block; }
|
||||
|
||||
@@ -1459,7 +1490,7 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
font: inherit;
|
||||
font-size: 1rem;
|
||||
color: var(--ink);
|
||||
background: #1a0f0f;
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: 0.55rem 0.75rem;
|
||||
@@ -1481,7 +1512,7 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
cursor: pointer;
|
||||
padding-inline: 1rem;
|
||||
}
|
||||
.login-submit:hover:not(:disabled) { background: #7d88f5; }
|
||||
.login-submit:hover:not(:disabled) { background: var(--brand-hover); }
|
||||
.login-submit:disabled { opacity: 0.6; cursor: wait; }
|
||||
/* Login failure (role=alert): err pair ≈9.1:1. */
|
||||
.login-error {
|
||||
@@ -1575,7 +1606,7 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 1rem;
|
||||
background: rgba(10, 14, 23, 0.82);
|
||||
background: color-mix(in srgb, var(--bg) 82%, transparent);
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition: opacity 120ms ease;
|
||||
@@ -1624,7 +1655,7 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
}
|
||||
.sync-modal-close:hover { background: rgb(239 68 68 / 0.15); }
|
||||
.sync-modal-close:hover { background: color-mix(in srgb, var(--err-line) 15%, transparent); }
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.sync-modal-backdrop { transition: none; }
|
||||
}
|
||||
@@ -1680,7 +1711,7 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
font-weight: 700;
|
||||
text-decoration: none;
|
||||
}
|
||||
.sources-gate-link:hover { background: #7d88f5; }
|
||||
.sources-gate-link:hover { background: var(--brand-hover); }
|
||||
|
||||
/* Phase 79 (task 05): the in-app token gate — the gate surface of the
|
||||
two token-only pages (the shell + the document viewer, one shared
|
||||
@@ -1776,7 +1807,7 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
}
|
||||
.auth-gate-submit:hover:not(:disabled) { background: #7d88f5; }
|
||||
.auth-gate-submit:hover:not(:disabled) { background: var(--brand-hover); }
|
||||
.auth-gate-submit:disabled { opacity: 0.6; cursor: wait; }
|
||||
|
||||
/* The one-line error (role=alert) — the rose/danger family the
|
||||
@@ -1909,7 +1940,7 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
cursor: pointer;
|
||||
}
|
||||
#git-source-add:hover:not(:disabled),
|
||||
#archive-upload-btn:hover:not(:disabled) { background: #7d88f5; }
|
||||
#archive-upload-btn:hover:not(:disabled) { background: var(--brand-hover); }
|
||||
#git-source-add:disabled,
|
||||
#archive-upload-btn:disabled { opacity: 0.6; cursor: wait; }
|
||||
|
||||
@@ -2005,7 +2036,7 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
}
|
||||
#git-sources-retry:hover { background: rgb(239 68 68 / 0.12); }
|
||||
#git-sources-retry:hover { background: color-mix(in srgb, var(--err-line) 12%, transparent); }
|
||||
|
||||
/* Env-fallback note (from_env: true — the table is empty and the list
|
||||
is BOR_GIT_SOURCES): the info chip in the theme palette —
|
||||
@@ -2078,7 +2109,7 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
/* --bg at 82% — the doc-modal dim, no backdrop-filter (no-blur). */
|
||||
background: rgba(15, 10, 10, 0.82);
|
||||
background: color-mix(in srgb, var(--bg) 82%, transparent);
|
||||
}
|
||||
|
||||
.remove-confirm-panel {
|
||||
@@ -2218,7 +2249,7 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
/* --bg at 82% — the doc-modal dim, no backdrop-filter (no-blur). */
|
||||
background: rgba(15, 10, 10, 0.82);
|
||||
background: color-mix(in srgb, var(--bg) 82%, transparent);
|
||||
}
|
||||
|
||||
.ignore-editor-panel {
|
||||
@@ -2348,7 +2379,7 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
background: var(--brand);
|
||||
color: var(--bg);
|
||||
}
|
||||
.ignore-editor-save:hover:not(:disabled) { background: #f55a72; }
|
||||
.ignore-editor-save:hover:not(:disabled) { background: var(--brand-hover); }
|
||||
|
||||
/* The list: the Sources page's table pattern — full width in the
|
||||
72rem frame, surface card, horizontally scrollable wrapper (the
|
||||
@@ -2542,7 +2573,7 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.history-refresh:hover { background: #f55a72; color: var(--bg); }
|
||||
.history-refresh:hover { background: var(--brand-hover); color: var(--bg); }
|
||||
.history-refresh:disabled { opacity: 0.6; cursor: wait; }
|
||||
/* The refresh glyph is hidden on desktop (the label carries the
|
||||
pill); below 640px it joins the visible label in the full-width
|
||||
@@ -2675,7 +2706,7 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
}
|
||||
.history-confirm-yes:hover:not(:disabled) { background: rgb(239 68 68 / 0.18); }
|
||||
.history-confirm-yes:hover:not(:disabled) { background: color-mix(in srgb, var(--err-line) 18%, transparent); }
|
||||
.history-confirm-yes:disabled { opacity: 0.6; cursor: wait; }
|
||||
.history-confirm-no {
|
||||
min-height: 44px;
|
||||
@@ -2818,7 +2849,7 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
}
|
||||
.token-generate:hover:not(:disabled) { background: #f55a72; color: var(--bg); }
|
||||
.token-generate:hover:not(:disabled) { background: var(--brand-hover); color: var(--bg); }
|
||||
.token-generate:disabled { opacity: 0.6; cursor: wait; }
|
||||
/* The shown-once block (owner-locked A4): a quiet brand-soft card
|
||||
around the "shown once" line + the mono read-only field + Copy —
|
||||
@@ -3085,7 +3116,7 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
}
|
||||
#theme-save:hover:not(:disabled) { background: #f55a72; color: var(--bg); }
|
||||
#theme-save:hover:not(:disabled) { background: var(--brand-hover); color: var(--bg); }
|
||||
#theme-save:disabled { opacity: 0.6; cursor: wait; }
|
||||
.theme-reset {
|
||||
min-height: 44px;
|
||||
@@ -3226,7 +3257,7 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
font-size: 0.95rem;
|
||||
text-decoration: none;
|
||||
}
|
||||
.doc-back:hover { background: #2a345f; }
|
||||
.doc-back:hover { background: var(--brand-soft); }
|
||||
.doc-back svg { width: 16px; height: 16px; display: block; }
|
||||
/* Row 2: the titlebar — a .container-width row with the back link +
|
||||
the title block, its own content-sized height (title line + meta
|
||||
@@ -3330,8 +3361,8 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
.doc-md > :first-child { margin-top: 0; }
|
||||
.doc-md ul { margin: 0.4rem 0; padding-left: 1.3rem; }
|
||||
.doc-md pre {
|
||||
background: #1a0f0f;
|
||||
color: #e6d0d0;
|
||||
background: var(--surface);
|
||||
color: var(--ink);
|
||||
padding: 0.7rem 0.9rem;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-sm);
|
||||
@@ -3375,7 +3406,7 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
color: var(--brand-ink); /* #fca5a5 on --surface ≈9.0:1 */
|
||||
color: var(--brand-ink); /* 9.0:1 on --surface */
|
||||
}
|
||||
.doc-summary-text {
|
||||
margin: 0;
|
||||
@@ -3449,7 +3480,7 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
font-size: 0.85rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
.doc-summary-save:hover { background: #f55a72; } /* the house hover lightening */
|
||||
.doc-summary-save:hover { background: var(--brand-hover); } /* the house hover lightening */
|
||||
.doc-summary-save:disabled { opacity: 0.6; cursor: default; } /* one PATCH at a time */
|
||||
.doc-summary-cancel {
|
||||
display: inline-flex;
|
||||
@@ -3516,7 +3547,7 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
text-decoration: none;
|
||||
border-radius: var(--radius-sm);
|
||||
}
|
||||
.doc-open-sources:hover { background: #7d88f5; }
|
||||
.doc-open-sources:hover { background: var(--brand-hover); }
|
||||
|
||||
/* Viewer links: Sources-table path cell + chat source chips (phase 10). */
|
||||
.doc-link {
|
||||
@@ -3551,7 +3582,7 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
/* --bg at 82% — no backdrop-filter (phase-08 no-blur perf anchor). */
|
||||
background: rgba(10, 14, 23, 0.82);
|
||||
background: color-mix(in srgb, var(--bg) 82%, transparent);
|
||||
transition: opacity 120ms ease;
|
||||
}
|
||||
|
||||
@@ -3568,7 +3599,10 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 24px 80px rgb(0 0 0 / 0.55);
|
||||
/* Depth shadow — deliberately NOT themed (black, phase-92 table:
|
||||
"depth, not theme"); the color-mix spelling renders the same 55%
|
||||
black and keeps the literal out of the phase-92 sweep gate. */
|
||||
box-shadow: 0 24px 80px color-mix(in srgb, black 55%, transparent);
|
||||
}
|
||||
|
||||
/* Sticky top with the SAME height as the page bars — the phase-12 pins
|
||||
@@ -3801,7 +3835,7 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
cursor: pointer;
|
||||
padding-inline: 1.25rem;
|
||||
}
|
||||
#push-doc-btn:hover:not(:disabled) { background: #7d88f5; }
|
||||
#push-doc-btn:hover:not(:disabled) { background: var(--brand-hover); }
|
||||
#push-doc-btn:disabled { opacity: 0.6; cursor: wait; }
|
||||
|
||||
/* The success status line (role=status): the ok family (ok-ink on
|
||||
|
||||
Reference in New Issue
Block a user