Compare commits

...
6 Commits
Author SHA1 Message Date
bvandeusen 875f6a7b5e Queue clear — shared ACL on lists, semantic q, full telemetry ledger, --color-* retired (#103)
CI & Build / Python lint (push) Successful in 4s
CI & Build / Plugin hooks (push) Successful in 8s
CI & Build / integration (push) Successful in 16s
CI & Build / TypeScript typecheck (push) Successful in 32s
CI & Build / Python tests (push) Successful in 49s
CI & Build / Build & push image (push) Successful in 18s
2026-08-08 22:45:26 -04:00
bvandeusen 4ba544e2af refactor(theme): retire the --color-* shim — the sweep it promised, run
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 7s
CI & Build / integration (push) Successful in 17s
CI & Build / TypeScript typecheck (push) Successful in 34s
CI & Build / Python tests (push) Successful in 48s
CI & Build / Build & push image (push) Successful in 37s
#2533. theme.css claimed "removing this block is a rename sweep across the
components, tracked separately" — written in 67a529a, never filed, which made
the comment itself an instance of the survey's presence-without-reference
pattern. This is that sweep.

73 alias declarations deleted; 69 files rewritten; every --color-*-style name
now references its --fs-* token directly. Mechanical by construction: the map
IS the alias block, applied longest-name-first with a boundary guard so
--color-text never matched inside --color-text-muted. Zero survivors outside
theme.css, verified by grep rather than assumed.

One deliberate survivor: --color-shadow stays DECLARED, because it was never
an alias — it is a literal value the design system has no token for. Marked
in place as a recorded gap: promote it to an --fs-* token when a second app
needs it, don't copy the line.

Nothing is lost mode-wise: the aliases' resolve-at-use-time trick (which
absorbed 48 dark-mode overrides) lives one layer down in the --fs-* tokens'
own derivations, which is why the sweep is a pure rename. Both CSS checkers
green.

Why now rather than never: check_snippets_against_design_system reports every
--color-* reference as "unknown — renders as NOTHING", and nine recipe
snippets recorded from components.css carried the deprecated names, making
them prior art pointing the wrong way. With the sweep in, the checker's
report over re-recorded snippets should be EMPTY — the acceptance test that
proves the checker was right all along (#2517's correction).

Refs #2533
2026-08-08 22:42:37 -04:00
bvandeusen 2d1e26f38f feat(telemetry): ambient surfacings count, apart — enter_project and the skill sync emit
CI & Build / Python lint (push) Successful in 5s
CI & Build / Plugin hooks (push) Successful in 8s
CI & Build / integration (push) Successful in 16s
CI & Build / TypeScript typecheck (push) Successful in 32s
CI & Build / Python tests (push) Successful in 47s
CI & Build / Build & push image (push) Successful in 25s
#2477, option (a) as decided, with the readout changed in the same commit.

## The two silent surfaces

enter_project returns open tasks + recent notes on every project entry —
probably the largest surfacing by volume — and emitted nothing, so the pulls
it caused floated unattributed and the surfaced:pulled ratio ran against a
denominator missing its biggest contributor. Now source "enter_project".

build_process_manifest installs every reachable Process as an auto-surfacing
skill on the operator's machine — its own docstring calls it the most
consequential passive surface Scribe has — and emitted nothing, so a Process
matched on every relevant turn and never opened was indistinguishable from
one never installed. Now source "process_skill_sync": the honest event is
"installed", which is a surfacing in effect since the description sits in
front of the model each session.

## The readout, same commit — the condition option (a) carried

Both surfaces are AMBIENT: top-N-by-recency and install-everything are not
ranked choices. Pooling them into surfaced_count would make a note's number
dominated by "recently updated in a project you opened", and dead-weight
detection would read that as popularity — the wrong number read confidently,
which is the corrupts-data tier the survey ranked above everything else.

So usage_for_notes splits: surfaced_count stays RANKED-ONLY (every existing
consumer's reading — "surfaced often, never pulled → dead weight" — keeps
meaning what it meant), and ambient_count is new. Classified in SQL via a
CASE on AMBIENT_SOURCES so the group count stays three rows per note, not one
per distinct source. Pulls stay pooled: "did anyone ever open this?" does not
depend on how it was found.

#1038 and #2085 read agent pulls and ranked surfacings; both are unaffected
by ambient volume, which is the point.

Refs #2477
2026-08-08 22:39:13 -04:00
bvandeusen 9b3874b657 test: the auto-inject path now logs two retrievals, and that is the point
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 9s
CI & Build / integration (push) Successful in 12s
CI & Build / TypeScript typecheck (push) Successful in 22s
CI & Build / Python tests (push) Successful in 48s
CI & Build / Build & push image (push) Successful in 28s
45ba4aa made the reuse slot log its query (source: reuse_slot). The margin-gate
test pinned record_retrieval to exactly one call, which was asserting the very
asymmetry #2463 fixed — the displaced hit logged, the displacing query not.
Assert both sources in order instead.

Refs #2463
2026-08-08 22:32:58 -04:00
bvandeusen 45ba4aab25 fix(telemetry): the two invisible retrievals log, and /api/search takes scope
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 9s
CI & Build / Python tests (push) Failing after 28s
CI & Build / Build & push image (push) Skipped
CI & Build / integration (push) Successful in 18s
CI & Build / TypeScript typecheck (push) Successful in 22s
#2463, the remaining findings (finding 3 landed with f11a547).

## The reuse slot logs (source: reuse_slot)

A real semantic query competing for an auto-inject menu slot, and the ledger
was asymmetric: the scored hit it DISPLACED was in retrieval_logs, the query
that displaced it was not — so the slot could never be evaluated against what
it replaced. #1038 and #2085 are gated on this ledger being complete.

## Browse search logs (source: browse_search)

The human's main search surface, and it logged nothing — so retrieval_logs
claimed the web's search was /api/search. Measured while fixing: /api/search
has ZERO frontend consumers; the web UI searches through /api/knowledge
exclusively. The table wasn't just under-describing the UI, it was describing
a surface the UI never touches.

The task's check — does folding human queries into the corpus skew the
precision signal thresholds are tuned against? — is answered by the source
column: distinct values (browse_search, reuse_slot beside the existing four)
mean tuning includes or excludes human traffic deliberately rather than by
accident. Same resolution as the mcp_/rest_ split in note_usage_events.

## /api/search takes project_id (and logs it)

The route logged project_id=None unconditionally while the MCP tool insists
the agent pass the active project. Now optional, default global: with no
frontend consumer, this route serves API callers, and an API caller states
its scope explicitly — the default-scope UI decision the task flagged is moot
until a UI actually consumes the route, which is recorded rather than guessed.

Refs #2463
2026-08-08 20:00:22 -04:00
bvandeusen f11a547cd2 fix(lists): shared-project records appear, and a list's q means what search means
CI & Build / Python lint (push) Successful in 4s
CI & Build / Plugin hooks (push) Successful in 8s
CI & Build / TypeScript typecheck (push) Successful in 12s
CI & Build / integration (push) Successful in 18s
CI & Build / Python tests (push) Successful in 48s
CI & Build / Build & push image (push) Successful in 28s
#2462, both decided halves.

## The ACL defect

list_notes filtered on Note.user_id == user_id with no scope parameter at all
— never a per-call decision, the capability was absent. query_knowledge beside
it was deliberately browse-scoped with a comment saying why. So a task in a
shared project was invisible in list_tasks, enter_project's open-task list,
the SessionStart todo count and the web UI's task views, while the same
project's notes and snippets appeared.

Now the shared clause: notes_visibility_clause(user_id, "browse"). Browse and
not read, per decision #2094 — an ambient list must never surface a record
someone shared one-to-one; those stay search-only. This is the remaining half
of a fix made twice before (#2159 widened fetch, #2092 widened meaning), and
the guard below is what stops a fourth half appearing.

Guarded by source inspection in test_retrieval_scopes: every list-shaped
service references a shared visibility clause AND carries no bare
Note.user_id comparison that would quietly re-narrow it. An owner-only list
returns correct-looking rows and simply omits the shared ones — the shape no
behavioural test catches.

## q is semantic (operator: "make it match")

The UI's note list keyword-matched while the UI's Browse search
semantic-matched, over the same records, with nothing saying so. Now one
meaning: q joins the embedding index and orders by cosine distance at the
interactive floor, with every lifecycle filter still applied in the same
indexed query. Relevance ordering wins over `sort` when q is present — a query
is a relevance claim, and sorting its results by date would shuffle the
answer. ILIKE survives only as the embedder-down fallback: degraded, never
empty.

Stated position: superseded records are NOT demoted in list-q. The penalty
reorders a top-k; reordering a paginated, counted list would make page
boundaries lie. The search surfaces carry the demotion.

## The interactive floor becomes one constant

INTERACTIVE_SEARCH_THRESHOLD = 0.3 in embeddings.py, consumed by
routes/search.py (was a commented constant), knowledge.py (was a bare
literal), and the new list-q. This closes #2463's finding 3 early — the same
number lived in two files with the reasoning attached to only one.

## Deferred, deliberately

The return-shape unification (ORM objects vs dicts) stays undone. It is a
14-caller refactor whose motivation — callers being unable to swap paths —
shrinks now that both paths share the clause and the meaning of q. If swap
pressure recurs it deserves its own change, not a rider on an ACL fix.

Refs #2462, #2463
2026-08-08 19:58:01 -04:00
81 changed files with 2030 additions and 1920 deletions
+16 -16
View File
@@ -254,7 +254,7 @@ onUnmounted(() => {
left: 0.5rem;
z-index: 9999;
padding: 0.4rem 0.75rem;
background: var(--color-primary);
background: var(--fs-accent);
color: var(--fs-text-on-action);
border-radius: 0 0 4px 4px;
font-size: 0.875rem;
@@ -290,7 +290,7 @@ onUnmounted(() => {
text-align: center;
padding: 0.2rem 0;
font-size: 0.68rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
opacity: 0.45;
user-select: none;
letter-spacing: 0.03em;
@@ -300,16 +300,16 @@ onUnmounted(() => {
.shortcuts-overlay {
position: fixed;
inset: 0;
background: var(--color-overlay);
background: var(--fs-overlay);
z-index: 9000;
display: flex;
align-items: center;
justify-content: center;
}
.shortcuts-panel {
background: var(--color-bg-card);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-lg);
box-shadow: 0 8px 32px var(--color-shadow);
width: min(420px, 92vw);
overflow: hidden;
@@ -319,25 +319,25 @@ onUnmounted(() => {
align-items: center;
justify-content: space-between;
padding: 0.85rem 1rem 0.75rem;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
}
.shortcuts-header h3 {
margin: 0;
font-size: 1rem;
font-weight: 600;
color: var(--color-text);
color: var(--fs-text-primary);
}
.shortcuts-close {
background: none;
border: none;
font-size: 1.4rem;
line-height: 1;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
cursor: pointer;
padding: 0 0.25rem;
}
.shortcuts-close:hover {
color: var(--color-text);
color: var(--fs-text-primary);
}
.shortcuts-body {
padding: 0.75rem 1rem 1rem;
@@ -350,7 +350,7 @@ onUnmounted(() => {
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
margin-bottom: 0.4rem;
}
.shortcut-row {
@@ -365,23 +365,23 @@ onUnmounted(() => {
justify-content: center;
min-width: 1.8rem;
padding: 0.15rem 0.4rem;
background: var(--color-bg-secondary);
border: 1px solid var(--color-border);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-bottom-width: 2px;
border-radius: 4px;
font-size: 0.78rem;
font-family: ui-monospace, monospace;
color: var(--color-text);
color: var(--fs-text-primary);
white-space: nowrap;
user-select: none;
}
.shortcut-key-sep {
font-size: 0.78rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.shortcut-desc {
font-size: 0.875rem;
color: var(--color-text);
color: var(--fs-text-primary);
margin-left: 0.25rem;
}
+13 -13
View File
@@ -89,19 +89,19 @@
* are universal across the family so a Save button looks identical in every
* app — the accent is identity, not action. */
.btn-primary {
background: var(--color-action-primary);
background: var(--fs-action-primary);
color: var(--fs-text-on-action);
}
.btn-primary:not(:disabled):hover {
background: var(--color-action-primary-hover);
background: var(--fs-action-primary-hover);
}
.btn-secondary {
background: var(--color-action-secondary);
background: var(--fs-action-secondary);
color: var(--fs-text-on-action);
}
.btn-secondary:not(:disabled):hover {
background: var(--color-action-secondary-hover);
background: var(--fs-action-secondary-hover);
}
/* Ghost is an OUTLINE, which is why its border and the tertiary action colour
@@ -112,21 +112,21 @@
.btn-ghost {
background: none;
border: var(--fs-border);
color: var(--color-text);
color: var(--fs-text-primary);
}
.btn-ghost:not(:disabled):hover {
border: var(--fs-border-hover);
background: var(--color-hover);
background: var(--fs-surface-hover);
}
/* Destructive is NOT the error colour: an error is a failure that happened, a
* destructive action is one about to happen. Pair with an icon. */
.btn-danger {
background: var(--color-action-destructive);
background: var(--fs-action-destructive);
color: var(--fs-text-on-action);
}
.btn-danger:not(:disabled):hover {
background: var(--color-action-destructive-hover);
background: var(--fs-action-destructive-hover);
}
/* A bare text button: no fill, no border. The most common shape in the dense
@@ -136,7 +136,7 @@
.btn-text {
background: none;
border: none;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
padding: var(--fs-space-1) var(--fs-space-2);
font-family: var(--fs-font-body);
font-size: var(--fs-size-tiny);
@@ -144,7 +144,7 @@
cursor: pointer;
transition: color var(--fs-dur-fast) var(--fs-ease);
}
.btn-text:not(:disabled):hover { color: var(--color-text); }
.btn-text:not(:disabled):hover { color: var(--fs-text-primary); }
.btn-text:disabled { opacity: var(--fs-disabled-opacity); cursor: not-allowed; }
.btn-text:focus-visible { outline: none; box-shadow: var(--fs-focus-ring); }
@@ -153,11 +153,11 @@
* a one-off: it is what a delete looks like when it must not shout. */
.btn-danger-outline {
background: none;
border: 1px solid var(--color-action-destructive);
color: var(--color-action-destructive);
border: 1px solid var(--fs-action-destructive);
color: var(--fs-action-destructive);
}
.btn-danger-outline:not(:disabled):hover {
background: var(--color-action-destructive);
background: var(--fs-action-destructive);
color: var(--fs-text-on-action);
}
+86 -86
View File
@@ -13,7 +13,7 @@
flex-direction: column;
gap: 0.75rem;
padding: 1rem 1.5rem 0.5rem;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
}
.editor-body {
flex: 1;
@@ -41,36 +41,36 @@
with a Trash icon at the call site to reinforce intent. */
.title-input:focus {
outline: none;
border-bottom-color: var(--color-primary);
border-bottom-color: var(--fs-accent);
}
.title-input::placeholder {
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
font-weight: 400;
}
.editor-tabs {
display: flex;
gap: 0;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
}
.tab {
padding: 0.45rem 1rem;
border: none;
background: none;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
cursor: pointer;
font-size: 0.9rem;
border-bottom: 2px solid transparent;
}
.tab.active {
color: var(--color-primary);
border-bottom-color: var(--color-primary);
color: var(--fs-accent);
border-bottom-color: var(--fs-accent);
}
.preview-pane {
padding: 0.75rem;
border: 1px solid var(--color-input-border);
border-radius: var(--radius-sm);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
min-height: 200px;
background: var(--color-bg-card);
background: var(--fs-surface-raised);
}
/* ── Tag suggestions ── */
@@ -85,21 +85,21 @@
align-items: center;
gap: 0.2rem;
padding: 0.2rem 0.55rem;
border: 1px solid var(--color-primary);
border: 1px solid var(--fs-accent);
border-radius: 999px;
background: transparent;
color: var(--color-primary);
color: var(--fs-accent);
font-size: 0.8rem;
cursor: pointer;
transition: background 0.15s, color 0.15s;
}
.tag-pill:hover:not(:disabled) {
background: var(--color-primary);
background: var(--fs-accent);
color: var(--fs-text-on-action);
}
.tag-pill.applied {
background: var(--color-success);
border-color: var(--color-success);
background: var(--fs-success);
border-color: var(--fs-success);
color: var(--fs-text-on-action);
cursor: default;
}
@@ -111,8 +111,8 @@
.assist-panel {
width: 320px;
flex-shrink: 0;
border-left: 1px solid var(--color-border);
background: var(--color-bg-secondary);
border-left: 1px solid var(--fs-border-color);
background: var(--fs-surface-raised);
display: flex;
flex-direction: column;
overflow: hidden;
@@ -123,13 +123,13 @@
align-items: center;
gap: 0.5rem;
padding: 0.65rem 0.9rem;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
}
.assist-panel-title {
flex: 1;
font-size: 0.8rem;
font-weight: 500;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
text-transform: uppercase;
letter-spacing: 0.05em;
}
@@ -149,13 +149,13 @@
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.04em;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
margin-bottom: 0.2rem;
}
.assist-sections {
border: 1px solid var(--color-input-border);
border-radius: var(--radius-sm);
background: var(--color-bg);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
background: var(--fs-surface-page);
max-height: 200px;
overflow-y: auto;
flex-shrink: 0;
@@ -165,46 +165,46 @@
cursor: pointer;
font-size: 0.82rem;
border-left: 3px solid transparent;
color: var(--color-text);
color: var(--fs-text-primary);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.assist-section-item:hover {
background: var(--color-bg-secondary);
background: var(--fs-surface-raised);
}
.assist-section-item.selected {
border-left-color: var(--color-primary);
background: var(--color-bg-secondary);
border-left-color: var(--fs-accent);
background: var(--fs-surface-raised);
font-weight: 500;
}
.assist-empty,
.assist-hint {
padding: 0.6rem 0.7rem;
font-size: 0.82rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.assist-target-preview {
font-size: 0.8rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.assist-target-preview em {
font-style: normal;
color: var(--color-text);
color: var(--fs-text-primary);
}
.assist-instruction {
width: 100%;
padding: 0.5rem 0.65rem;
border: 1px solid var(--color-input-border);
border-radius: var(--radius-sm);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
font-size: 0.88rem;
font-family: inherit;
resize: vertical;
background: var(--color-bg);
color: var(--color-text);
background: var(--fs-surface-page);
color: var(--fs-text-primary);
box-sizing: border-box;
min-height: 3.5rem;
}
@@ -216,22 +216,22 @@
/* Streaming */
.assist-streaming-label {
font-size: 0.8rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.assist-preview-box {
padding: 0.65rem;
border: 1px solid var(--color-input-border);
border-radius: var(--radius-sm);
background: var(--color-bg);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
background: var(--fs-surface-page);
font-size: 0.9rem;
max-height: 300px;
overflow-y: auto;
}
.typing-indicator {
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
font-size: 0.75rem;
letter-spacing: 0.15em;
animation: blink 1s step-end infinite;
@@ -244,18 +244,18 @@
.assist-active-hint {
padding: 0.5rem 0.75rem;
font-size: 0.8rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
text-align: center;
}
/* Error */
.assist-error {
padding: 0.5rem 0.75rem;
background: color-mix(in srgb, var(--color-danger) 10%, transparent);
border: 1px solid var(--color-danger);
border-radius: var(--radius-sm);
background: color-mix(in srgb, var(--fs-error) 10%, transparent);
border: 1px solid var(--fs-error);
border-radius: var(--fs-radius-sm);
font-size: 0.85rem;
color: var(--color-danger);
color: var(--fs-error);
}
/* Review / diff */
@@ -265,12 +265,12 @@
justify-content: space-between;
font-size: 0.8rem;
font-weight: 500;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
}
.diff-view {
border: 1px solid var(--color-input-border);
border-radius: var(--radius-sm);
background: var(--color-bg);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
background: var(--fs-surface-page);
font-size: 0.82rem;
font-family: monospace;
max-height: 340px;
@@ -284,15 +284,15 @@
line-height: 1.5;
}
.diff-delete {
background: color-mix(in srgb, var(--color-danger) 12%, transparent);
color: var(--color-danger);
background: color-mix(in srgb, var(--fs-error) 12%, transparent);
color: var(--fs-error);
}
.diff-insert {
background: color-mix(in srgb, var(--color-success) 12%, transparent);
color: var(--color-success);
background: color-mix(in srgb, var(--fs-success) 12%, transparent);
color: var(--fs-success);
}
.diff-equal {
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.diff-marker {
flex-shrink: 0;
@@ -308,7 +308,7 @@
}
.diff-empty {
padding: 0.5rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
font-size: 0.82rem;
}
.assist-actions {
@@ -320,15 +320,15 @@
.modal-overlay {
position: fixed;
inset: 0;
background: var(--color-overlay);
background: var(--fs-overlay);
display: flex;
align-items: center;
justify-content: center;
z-index: 200;
}
.modal-card {
background: var(--color-bg-card);
border-radius: var(--radius-md);
background: var(--fs-surface-raised);
border-radius: var(--fs-radius-lg);
padding: 1.5rem;
max-width: 400px;
width: 90%;
@@ -340,7 +340,7 @@
}
.modal-message {
margin: 0 0 1.25rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
font-size: 0.95rem;
}
.modal-actions {
@@ -350,17 +350,17 @@
}
.modal-btn {
padding: 0.45rem 1rem;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
background: var(--color-bg-card);
color: var(--color-text);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
background: var(--fs-surface-raised);
color: var(--fs-text-primary);
cursor: pointer;
font-size: 0.9rem;
}
.modal-btn-danger {
background: var(--color-danger);
background: var(--fs-error);
color: var(--fs-text-on-action);
border-color: var(--color-danger);
border-color: var(--fs-error);
}
/* ── Floating inline assist button (teleported to body) ── */
@@ -369,10 +369,10 @@
z-index: 100;
transform: translateX(-50%);
padding: 0.3rem 0.75rem;
background: var(--color-action-primary);
background: var(--fs-action-primary);
color: var(--fs-text-on-action);
border: none;
border-radius: var(--radius-sm);
border-radius: var(--fs-radius-sm);
cursor: pointer;
font-size: 0.8rem;
box-shadow: 0 2px 8px var(--color-shadow);
@@ -384,12 +384,12 @@
display: none;
width: 100%;
padding: 0.6rem 1rem;
background: var(--color-bg-secondary);
background: var(--fs-surface-raised);
border: none;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
font-size: 0.85rem;
font-weight: 500;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
cursor: pointer;
text-align: left;
font-family: inherit;
@@ -408,7 +408,7 @@
.sb-label {
font-size: 0.78rem;
font-weight: 500;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
text-transform: uppercase;
letter-spacing: 0.04em;
}
@@ -416,10 +416,10 @@
.sb-input {
width: 100%;
padding: 0.35rem 0.5rem;
border: 1px solid var(--color-input-border);
border-radius: var(--radius-sm);
background: var(--color-bg-card);
color: var(--color-text);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
background: var(--fs-surface-raised);
color: var(--fs-text-primary);
font-size: 0.875rem;
font-family: inherit;
box-sizing: border-box;
@@ -427,11 +427,11 @@
.sb-select:focus,
.sb-input:focus {
outline: none;
border-color: var(--color-primary);
border-color: var(--fs-accent);
}
.sb-divider {
height: 1px;
background: var(--color-border);
background: var(--fs-border-color);
margin: 0.15rem 0;
}
@media (max-width: 720px) {
@@ -452,8 +452,8 @@
width: auto;
flex: 0 0 45%;
border-left: none;
border-top: 1px solid var(--color-border);
border-radius: var(--radius-md) var(--radius-md) 0 0;
border-top: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-lg) var(--fs-radius-lg) 0 0;
}
.editor-header {
padding: 0.75rem 1rem 0.5rem;
@@ -480,14 +480,14 @@
.btn-accept,
.btn-generate,
.btn-save {
background: var(--color-action-primary);
background: var(--fs-action-primary);
color: var(--fs-text-on-action);
border: none;
}
.btn-accept:not(:disabled):hover,
.btn-generate:not(:disabled):hover,
.btn-save:not(:disabled):hover {
background: var(--color-action-primary-hover);
background: var(--fs-action-primary-hover);
}
.btn-back,
@@ -497,7 +497,7 @@
.btn-suggest-tags {
background: none;
border: var(--fs-border);
color: var(--color-text);
color: var(--fs-text-primary);
}
.btn-back:not(:disabled):hover,
.btn-clear:not(:disabled):hover,
@@ -505,16 +505,16 @@
.btn-proofread:not(:disabled):hover,
.btn-suggest-tags:not(:disabled):hover {
border: var(--fs-border-hover);
background: var(--color-hover);
background: var(--fs-surface-hover);
}
.btn-delete {
background: var(--color-action-destructive);
background: var(--fs-action-destructive);
color: var(--fs-text-on-action);
border: none;
}
.btn-delete:not(:disabled):hover {
background: var(--color-action-destructive-hover);
background: var(--fs-action-destructive-hover);
}
/* Shared geometry for every alias above. */
@@ -541,12 +541,12 @@
.btn-dismiss-tags {
background: none;
border: none;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
padding: 2px var(--fs-space-1);
font-size: var(--fs-size-tiny);
line-height: 1;
}
.btn-dismiss-tags:hover { color: var(--color-text); }
.btn-dismiss-tags:hover { color: var(--fs-text-primary); }
.btn-accept:disabled, .btn-generate:disabled, .btn-save:disabled,
.btn-back:disabled, .btn-clear:disabled, .btn-reject:disabled,
+24 -24
View File
@@ -41,8 +41,8 @@
}
.prose pre {
background: var(--color-code-bg);
border: 1px solid var(--color-border);
background: var(--fs-surface-code);
border: 1px solid var(--fs-border-color);
border-radius: 6px;
padding: 0.75rem;
overflow-x: auto;
@@ -57,7 +57,7 @@
}
.prose code {
background: var(--color-code-inline-bg);
background: var(--fs-surface-code-inline);
border-radius: 3px;
padding: 0.15rem 0.35rem;
font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
@@ -73,25 +73,25 @@
.prose th,
.prose td {
border: 1px solid var(--color-border);
border: 1px solid var(--fs-border-color);
padding: 0.4rem 0.6rem;
text-align: left;
}
.prose thead th {
background: var(--color-bg-secondary);
background: var(--fs-surface-raised);
font-weight: 600;
}
.prose tbody tr:nth-child(even) {
background: var(--color-table-stripe);
background: var(--fs-table-stripe);
}
.prose blockquote {
border-left: 3px solid var(--color-border);
border-left: 3px solid var(--fs-border-color);
margin: 0 0 0.6rem;
padding: 0.25rem 0 0.25rem 0.75rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
}
.prose blockquote p:last-child {
@@ -100,7 +100,7 @@
.prose hr {
border: none;
border-top: 1px solid var(--color-border);
border-top: 1px solid var(--fs-border-color);
margin: 1rem 0;
}
@@ -110,7 +110,7 @@
}
.prose a {
color: var(--color-primary);
color: var(--fs-accent);
text-decoration: none;
}
@@ -119,8 +119,8 @@
}
.prose .inline-tag {
color: var(--color-tag-text);
background: var(--color-tag-bg);
color: var(--fs-accent);
background: var(--fs-accent-soft);
padding: 0.1rem 0.35rem;
border-radius: 4px;
text-decoration: none;
@@ -133,8 +133,8 @@
}
.prose .wikilink {
color: var(--color-wikilink);
background: var(--color-wikilink-bg);
color: var(--fs-wikilink);
background: var(--fs-accent-soft);
padding: 0.1rem 0.35rem;
border-radius: 4px;
text-decoration: none;
@@ -168,7 +168,7 @@
.prose ul[data-type="taskList"] li > label input[type="checkbox"] {
cursor: pointer;
accent-color: var(--color-primary);
accent-color: var(--fs-accent);
width: 0.95em;
height: 0.95em;
margin: 0;
@@ -180,7 +180,7 @@
.prose ul[data-type="taskList"] li[data-checked="true"] > div {
text-decoration: line-through;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
/* Interactive checkboxes — marked output in the list-note viewer */
@@ -196,7 +196,7 @@
}
.prose--checklist li input[type="checkbox"] {
flex-shrink: 0;
accent-color: var(--color-primary);
accent-color: var(--fs-accent);
cursor: pointer;
width: 0.95em;
height: 0.95em;
@@ -205,7 +205,7 @@
.prose--checklist li:has(input[type="checkbox"]:checked) > p,
.prose--checklist li:has(input[type="checkbox"]:checked) {
text-decoration: line-through;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.prose--checklist li:has(input[type="checkbox"]:checked) input[type="checkbox"] {
text-decoration: none; /* don't strike through the checkbox itself */
@@ -219,7 +219,7 @@
}
.tiptap-editor .ProseMirror p.is-editor-empty:first-child::before {
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
content: attr(data-placeholder);
float: left;
height: 0;
@@ -227,12 +227,12 @@
}
.tiptap-wrapper {
border: 1px solid var(--color-input-border);
border-radius: var(--radius-sm);
background: var(--color-bg-card);
color: var(--color-text);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
background: var(--fs-surface-raised);
color: var(--fs-text-primary);
}
.tiptap-wrapper:focus-within {
box-shadow: var(--focus-ring);
box-shadow: var(--fs-focus-ring);
}
+11 -116
View File
@@ -188,126 +188,21 @@
*/
/* ==========================================================================
COMPATIBILITY ALIASES — the app's historical names, pointing at the system.
These exist so ~55 components keep working while they migrate to --fs-*
one at a time. Every one is a plain var() reference, which is what lets this
block be declared ONCE: when [data-theme="light"] moves --fs-surface-page,
--color-bg follows, because the alias resolves at use time.
That is why this file lost 48 of its 60 dark-mode overrides — they were all
restating relationships the aliases now express directly.
Removing this block is a rename sweep across the components, tracked
separately. Nothing new should reference a --color-* name.
The compatibility-alias block that lived here is GONE (#2533). It let ~55
components keep their historical --color-* names while theme.css was
repointed at the design system; the rename sweep it promised ran on
2026-08-08 and every component now references --fs-* directly. Do not
reintroduce app-local alias names — the design system's tokens are the
vocabulary, and check_snippets_against_design_system can only see through
names the system actually declares.
========================================================================== */
:root {
/* surfaces */
--color-bg: var(--fs-surface-page);
--color-bg-secondary: var(--fs-surface-raised);
--color-bg-card: var(--fs-surface-raised);
--color-surface: var(--fs-surface-hover);
--color-code-bg: var(--fs-surface-code);
--color-code-inline-bg: var(--fs-surface-code-inline);
--color-table-stripe: var(--fs-table-stripe);
--color-overlay: var(--fs-overlay);
/* text */
--color-text: var(--fs-text-primary);
--color-text-secondary: var(--fs-text-secondary);
--color-text-muted: var(--fs-text-tertiary);
/* lines */
--color-border: var(--fs-border-color);
--color-input-border: var(--fs-border-color);
--focus-ring: var(--fs-focus-ring);
/* brand */
--color-primary: var(--fs-accent);
--color-primary-solid: var(--fs-accent);
--color-primary-deep: var(--fs-accent-deep);
--color-primary-faint: var(--fs-accent-faint);
--color-primary-tint: var(--fs-accent-soft);
--color-primary-wash: var(--fs-accent-wash);
--color-tag-bg: var(--fs-accent-soft);
--color-tag-text: var(--fs-accent);
--color-wikilink: var(--fs-wikilink);
--color-wikilink-bg: var(--fs-accent-soft);
--gradient-cta: var(--fs-gradient-cta);
--glow-cta: var(--fs-glow-cta);
--glow-cta-hover: var(--fs-glow-cta-hover);
/* actions */
--color-action-primary: var(--fs-action-primary);
--color-action-primary-hover: var(--fs-action-primary-hover);
--color-action-secondary: var(--fs-action-secondary);
--color-action-secondary-hover: var(--fs-action-secondary-hover);
--color-action-destructive: var(--fs-action-destructive);
--color-action-destructive-hover: var(--fs-action-destructive-hover);
/* semantic */
--color-success: var(--fs-success);
--color-warning: var(--fs-warning);
--color-danger: var(--fs-error);
--color-overdue: var(--fs-overdue);
--color-toast-success: var(--fs-success);
--color-toast-error: var(--fs-error);
/* A VALUE, not an alias — the one survivor of the alias block. The design
system has no shadow-colour token yet, so this is a recorded gap: when a
second app needs it, promote it to an --fs-* token in the system and
regenerate, rather than copying this line. */
--color-shadow: rgba(0, 0, 0, 0.4);
/* task status + priority */
--color-status-todo: var(--fs-status-todo);
--color-status-todo-bg: var(--fs-status-todo-bg);
--color-status-in-progress: var(--fs-status-in-progress);
--color-status-in-progress-bg: var(--fs-status-in-progress-bg);
--color-status-done: var(--fs-status-done);
--color-status-done-bg: var(--fs-status-done-bg);
--color-priority-low: var(--fs-priority-low);
--color-priority-low-bg: var(--fs-priority-low-bg);
--color-priority-medium: var(--fs-priority-medium);
--color-priority-medium-bg: var(--fs-priority-medium-bg);
--color-priority-high: var(--fs-priority-high);
--color-priority-high-bg: var(--fs-priority-high-bg);
/* geometry */
--radius-sm: var(--fs-radius-sm);
--radius-md: var(--fs-radius-lg); /* NB: the app's "md" is the system's LARGE */
--radius-lg: var(--fs-radius-xl); /* and the app's "lg" is the system's XL */
--page-max-width: var(--fs-layout-page-max);
--page-padding-x: var(--fs-layout-page-pad);
--sidebar-width: var(--fs-layout-sidebar);
--header-height: var(--fs-layout-header);
/* ------------------------------------------------------------------
Names components reference that were NEVER declared anywhere.
Each of these was reached for with a hardcoded fallback, so the page
rendered — but the fallback was what rendered, always, and several were
off-palette: --color-primary-bg fell back to an indigo, --color-destructive
to a brick that is not the oxblood, --color-status-cancelled to a grey from
no palette in this system.
Wiring them to real tokens is the whole point of the exercise. Expect small
visual shifts exactly where a fallback had drifted; that shift IS the fix.
------------------------------------------------------------------ */
--color-accent: var(--fs-accent);
/* Foreground ON the accent, so it follows the accent's mode-independence,
not the page text's. Pointing this at --fs-text-primary made it invert to
obsidian on light — over a mid-tone accent, well under the AA floor. */
--color-accent-fg: var(--fs-text-on-action);
--color-hover: var(--fs-surface-hover);
--color-bg-hover: var(--fs-surface-hover);
--color-bg-tertiary: var(--fs-surface-hover);
--color-surface-2: var(--fs-surface-hover);
--color-surface-alt: var(--fs-surface-hover);
--color-surface-raised: var(--fs-surface-raised);
--color-input-bg: var(--fs-surface-page);
--color-muted: var(--fs-text-tertiary);
--color-destructive: var(--fs-destructive);
--color-primary-bg: var(--fs-accent-soft);
--color-status-cancelled: var(--fs-status-cancelled);
--font-display: var(--fs-font-display);
--font-mono: var(--fs-font-mono);
}
/* ==========================================================================
+12 -12
View File
@@ -15,27 +15,27 @@
white-space: nowrap;
}
.ctx-crumb-parent {
color: var(--color-text-muted);
background: var(--color-bg-secondary);
border: 1px solid var(--color-border);
color: var(--fs-text-tertiary);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
text-decoration: none;
}
.ctx-crumb-parent:hover {
color: var(--color-primary);
border-color: var(--color-primary);
color: var(--fs-accent);
border-color: var(--fs-accent);
}
.ctx-crumb-project {
color: var(--color-primary);
background: color-mix(in srgb, var(--color-primary) 10%, transparent);
border: 1px solid color-mix(in srgb, var(--color-primary) 30%, transparent);
color: var(--fs-accent);
background: color-mix(in srgb, var(--fs-accent) 10%, transparent);
border: 1px solid color-mix(in srgb, var(--fs-accent) 30%, transparent);
text-decoration: none;
font-weight: 500;
}
.ctx-crumb-project:hover {
background: color-mix(in srgb, var(--color-primary) 18%, transparent);
background: color-mix(in srgb, var(--fs-accent) 18%, transparent);
}
.ctx-crumb-milestone {
color: var(--color-text-secondary);
background: var(--color-bg-secondary);
border: 1px solid var(--color-border);
color: var(--fs-text-secondary);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
}
+33 -33
View File
@@ -124,8 +124,8 @@ router.afterEach(() => {
<style scoped>
.app-header {
background: linear-gradient(180deg, var(--color-surface), var(--color-bg));
border-bottom: 1px solid color-mix(in srgb, var(--color-primary) 18%, transparent);
background: linear-gradient(180deg, var(--fs-surface-hover), var(--fs-surface-page));
border-bottom: 1px solid color-mix(in srgb, var(--fs-accent) 18%, transparent);
position: relative;
}
/* Three tracks, not a flex row with an absolutely-centred overlay.
@@ -178,7 +178,7 @@ router.afterEach(() => {
display: flex;
align-items: center;
gap: 2px;
background: var(--color-primary-faint);
background: var(--fs-accent-faint);
border-radius: 10px;
padding: 3px;
}
@@ -194,7 +194,7 @@ router.afterEach(() => {
}
.nav-link {
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
text-decoration: none;
font-size: 0.82rem;
padding: 0.3rem 0.75rem;
@@ -202,14 +202,14 @@ router.afterEach(() => {
transition: background 0.15s, color 0.15s;
}
.nav-link:hover {
color: var(--color-text);
background: var(--color-primary-tint);
color: var(--fs-text-primary);
background: var(--fs-accent-soft);
}
.nav-link.router-link-active {
color: var(--color-primary-solid);
color: var(--fs-accent);
font-weight: 500;
background: color-mix(in srgb, var(--color-primary) 25%, transparent);
box-shadow: 0 0 16px color-mix(in srgb, var(--color-primary) 30%, transparent);
background: color-mix(in srgb, var(--fs-accent) 25%, transparent);
box-shadow: 0 0 16px color-mix(in srgb, var(--fs-accent) 30%, transparent);
}
/* Status indicator */
@@ -229,7 +229,7 @@ router.afterEach(() => {
.status-text {
font-size: 0.75rem;
font-weight: 500;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
/* Status dots are indicator lights, not semantic-palette buttons —
they want to read as vital (Moss/Warning/Error are too muted for
@@ -239,7 +239,7 @@ router.afterEach(() => {
.status-yellow .status-dot { background: #facc15; animation: pulse-dot 2s infinite; }
.status-orange .status-dot { background: #f97316; }
.status-red .status-dot { background: #ef4444; }
.status-gray .status-dot { background: var(--color-text-muted); animation: pulse-dot 2s infinite; }
.status-gray .status-dot { background: var(--fs-text-tertiary); animation: pulse-dot 2s infinite; }
@keyframes pulse-dot {
0%, 100% { opacity: 1; }
50% { opacity: 0.3; }
@@ -252,12 +252,12 @@ router.afterEach(() => {
/* Icon buttons (?, theme, gear) */
.btn-icon {
background: none;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
padding: 0.25rem 0.45rem;
cursor: pointer;
font-size: 0.95rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
line-height: 1;
display: flex;
align-items: center;
@@ -265,9 +265,9 @@ router.afterEach(() => {
}
.btn-icon:hover,
.btn-icon.active {
background: var(--color-bg-card);
color: var(--color-text);
border-color: var(--color-primary);
background: var(--fs-surface-raised);
color: var(--fs-text-primary);
border-color: var(--fs-accent);
}
/* User info */
@@ -277,11 +277,11 @@ router.afterEach(() => {
gap: 0.4rem;
margin-left: 0.25rem;
padding-left: 0.5rem;
border-left: 1px solid var(--color-border);
border-left: 1px solid var(--fs-border-color);
}
.username {
font-size: 0.85rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
font-weight: 500;
/* The widest thing on the right and the only one that can give: a long
username shouldn't be what decides where the nav bar sits. */
@@ -295,24 +295,24 @@ router.afterEach(() => {
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--color-primary);
background: color-mix(in srgb, var(--color-primary) 15%, transparent);
color: var(--fs-accent);
background: color-mix(in srgb, var(--fs-accent) 15%, transparent);
padding: 0.1rem 0.35rem;
border-radius: var(--radius-sm);
border-radius: var(--fs-radius-sm);
}
.btn-logout {
background: none;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
padding: 0.2rem 0.5rem;
cursor: pointer;
font-size: 0.8rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
font-family: inherit;
}
.btn-logout:hover {
color: var(--color-danger);
border-color: var(--color-danger);
color: var(--fs-error);
border-color: var(--fs-error);
}
/* Hamburger — mobile only */
@@ -330,7 +330,7 @@ router.afterEach(() => {
display: block;
width: 20px;
height: 2px;
background: var(--color-text);
background: var(--fs-text-primary);
border-radius: 1px;
}
@@ -339,13 +339,13 @@ router.afterEach(() => {
display: flex;
flex-direction: column;
padding: 0.5rem 1rem 0.75rem;
border-top: 1px solid var(--color-border);
background: var(--color-bg-secondary);
border-top: 1px solid var(--fs-border-color);
background: var(--fs-surface-raised);
gap: 0.1rem;
}
.mobile-divider {
height: 1px;
background: var(--color-border);
background: var(--fs-border-color);
margin: 0.4rem 0;
}
.mobile-actions {
@@ -359,7 +359,7 @@ router.afterEach(() => {
align-items: center;
gap: 0.5rem;
padding-top: 0.4rem;
border-top: 1px solid var(--color-border);
border-top: 1px solid var(--fs-border-color);
margin-top: 0.25rem;
}
@@ -398,7 +398,7 @@ router.afterEach(() => {
border-radius: 8px;
}
.mobile-menu .nav-link.router-link-active {
background: var(--color-primary-wash);
background: var(--fs-accent-wash);
box-shadow: none;
}
.mobile-user .btn-logout {
+5 -5
View File
@@ -13,8 +13,8 @@ defineProps<{ size?: number }>();
>
<defs>
<linearGradient id="logo-gradient" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="var(--color-primary-solid)" />
<stop offset="100%" stop-color="var(--color-primary-deep)" />
<stop offset="0%" stop-color="var(--fs-accent)" />
<stop offset="100%" stop-color="var(--fs-accent-deep)" />
</linearGradient>
</defs>
<!-- Book body -->
@@ -44,12 +44,12 @@ defineProps<{ size?: number }>();
<style scoped>
.logo-book {
fill: url(#logo-gradient);
stroke: color-mix(in srgb, var(--color-primary) 70%, transparent);
stroke: color-mix(in srgb, var(--fs-accent) 70%, transparent);
}
.logo-spine {
stroke: var(--color-text-secondary);
stroke: var(--fs-text-secondary);
}
.logo-lines {
stroke: var(--color-text-muted);
stroke: var(--fs-text-tertiary);
}
</style>
+16 -16
View File
@@ -90,9 +90,9 @@ function markerFor(type: DiffLine['type']): string {
flex-direction: column;
flex: 1;
min-height: 0;
border: 1px solid var(--color-input-border);
border-radius: var(--radius-sm);
background: var(--color-bg);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
background: var(--fs-surface-page);
overflow: hidden;
}
@@ -103,15 +103,15 @@ function markerFor(type: DiffLine['type']): string {
display: flex;
gap: 1rem;
padding: 0.4rem 0.75rem;
background: var(--color-bg-secondary);
border-bottom: 1px solid var(--color-border);
background: var(--fs-surface-raised);
border-bottom: 1px solid var(--fs-border-color);
font-size: 0.78rem;
font-family: monospace;
font-weight: 600;
}
.diff-summary-ins { color: var(--color-success); }
.diff-summary-del { color: var(--color-danger); }
.diff-summary-ins { color: var(--fs-success); }
.diff-summary-del { color: var(--fs-error); }
.diff-scroll {
flex: 1;
@@ -123,7 +123,7 @@ function markerFor(type: DiffLine['type']): string {
.diff-empty {
padding: 0.75rem;
font-size: 0.85rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.diff-line {
@@ -136,24 +136,24 @@ function markerFor(type: DiffLine['type']): string {
}
.diff-delete {
background: color-mix(in srgb, var(--color-danger) 12%, transparent);
color: var(--color-danger);
background: color-mix(in srgb, var(--fs-error) 12%, transparent);
color: var(--fs-error);
}
.diff-insert {
background: color-mix(in srgb, var(--color-success) 12%, transparent);
color: var(--color-success);
background: color-mix(in srgb, var(--fs-success) 12%, transparent);
color: var(--fs-success);
}
.diff-equal {
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.diff-collapse {
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
opacity: 0.6;
border-top: 1px dashed var(--color-border);
border-bottom: 1px dashed var(--color-border);
border-top: 1px dashed var(--fs-border-color);
border-bottom: 1px dashed var(--fs-border-color);
padding-top: 0.2rem;
padding-bottom: 0.2rem;
}
+26 -26
View File
@@ -309,7 +309,7 @@ onMounted(loadVersions);
align-items: center;
justify-content: space-between;
padding: 0.9rem 1.25rem;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
}
.history-title {
@@ -322,11 +322,11 @@ onMounted(loadVersions);
border: none;
font-size: 1.25rem;
cursor: pointer;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
line-height: 1;
padding: 0.1rem 0.3rem;
}
.history-close:hover { color: var(--color-text); }
.history-close:hover { color: var(--fs-text-primary); }
.history-body {
flex: 1;
@@ -338,7 +338,7 @@ onMounted(loadVersions);
.history-list {
width: 220px;
flex-shrink: 0;
border-right: 1px solid var(--color-border);
border-right: 1px solid var(--fs-border-color);
overflow-y: auto;
}
@@ -346,18 +346,18 @@ onMounted(loadVersions);
padding: 0.6rem 0.9rem;
cursor: pointer;
border-left: 3px solid transparent;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
}
.history-item:hover { background: var(--color-bg-secondary); }
.history-item:hover { background: var(--fs-surface-raised); }
.history-item.selected {
border-left-color: var(--color-primary);
background: var(--color-bg-secondary);
border-left-color: var(--fs-accent);
background: var(--fs-surface-raised);
}
.history-item-title {
font-size: 0.85rem;
font-weight: 500;
color: var(--color-text);
color: var(--fs-text-primary);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
@@ -365,7 +365,7 @@ onMounted(loadVersions);
.history-item-date {
font-size: 0.75rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
margin-top: 0.15rem;
}
@@ -381,7 +381,7 @@ onMounted(loadVersions);
.history-empty {
padding: 1rem;
font-size: 0.85rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.history-footer {
@@ -390,7 +390,7 @@ onMounted(loadVersions);
gap: 0.5rem;
justify-content: flex-end;
padding: 0.75rem 1.25rem;
border-top: 1px solid var(--color-border);
border-top: 1px solid var(--fs-border-color);
}
@@ -403,12 +403,12 @@ onMounted(loadVersions);
font-size: 0.85em;
line-height: 1;
}
.pin-badge-manual { color: var(--color-primary); }
.pin-badge-auto { color: var(--color-text-muted); }
.pin-badge-manual { color: var(--fs-accent); }
.pin-badge-auto { color: var(--fs-text-tertiary); }
.history-item-label {
font-size: 0.72rem;
color: var(--color-primary);
color: var(--fs-accent);
font-style: italic;
margin-top: 0.15rem;
overflow: hidden;
@@ -419,7 +419,7 @@ onMounted(loadVersions);
/* ── Pin controls above the diff ────────────────────────────────────────── */
.version-pin-controls {
padding: 0.4rem 0.5rem 0.5rem;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
font-size: 0.82rem;
}
.pin-actions {
@@ -430,7 +430,7 @@ onMounted(loadVersions);
}
.pin-state {
font-style: italic;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
flex: 1;
min-width: 0;
overflow: hidden;
@@ -442,13 +442,13 @@ onMounted(loadVersions);
font-size: 0.78rem;
background: transparent;
color: inherit;
border: 1px solid var(--color-border);
border: 1px solid var(--fs-border-color);
border-radius: 999px;
cursor: pointer;
}
.btn-pin:hover:not(:disabled), .btn-pin-edit:hover:not(:disabled) {
background: rgba(99, 102, 241, 0.12);
border-color: var(--color-primary);
border-color: var(--fs-accent);
}
.btn-unpin:hover:not(:disabled) {
background: rgba(239, 68, 68, 0.10);
@@ -463,27 +463,27 @@ onMounted(loadVersions);
flex: 1;
padding: 0.3rem 0.5rem;
font-size: 0.85rem;
background: var(--color-input-bg);
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
background: var(--fs-surface-page);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
color: inherit;
}
.pin-label-input:focus {
outline: none;
border-color: var(--color-primary);
border-color: var(--fs-accent);
}
.btn-pin-save, .btn-pin-cancel {
padding: 0.3rem 0.7rem;
font-size: 0.78rem;
background: transparent;
color: inherit;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
cursor: pointer;
}
.btn-pin-save:hover:not(:disabled) {
background: rgba(99, 102, 241, 0.12);
border-color: var(--color-primary);
border-color: var(--fs-accent);
}
.btn-pin-save:disabled, .btn-pin-cancel:disabled,
.btn-pin:disabled, .btn-pin-edit:disabled, .btn-unpin:disabled {
+34 -34
View File
@@ -74,11 +74,11 @@ const markers: Record<DiffLine["type"], string> = {
<style scoped>
.iap {
border-radius: var(--radius-sm);
border-radius: var(--fs-radius-sm);
margin-bottom: 0.75rem;
overflow: hidden;
border: 1px solid var(--color-border);
background: var(--color-bg);
border: 1px solid var(--fs-border-color);
background: var(--fs-surface-page);
}
/* ── Header ── */
@@ -88,16 +88,16 @@ const markers: Record<DiffLine["type"], string> = {
gap: 0.5rem;
padding: 0.45rem 0.75rem;
font-size: 0.85rem;
border-bottom: 1px solid var(--color-border);
background: var(--color-bg-secondary);
border-bottom: 1px solid var(--fs-border-color);
background: var(--fs-surface-raised);
}
/* ── Streaming ── */
.iap-streaming {
border-color: var(--color-primary);
border-color: var(--fs-accent);
}
.iap-streaming .iap-header {
background: color-mix(in srgb, var(--color-primary) 8%, var(--color-bg-secondary));
background: color-mix(in srgb, var(--fs-accent) 8%, var(--fs-surface-raised));
}
.iap-pulse {
@@ -105,7 +105,7 @@ const markers: Record<DiffLine["type"], string> = {
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--color-primary);
background: var(--fs-accent);
flex-shrink: 0;
animation: iap-pulse 1.2s ease-in-out infinite;
}
@@ -117,7 +117,7 @@ const markers: Record<DiffLine["type"], string> = {
.iap-label {
flex: 1;
font-weight: 500;
color: var(--color-text);
color: var(--fs-text-primary);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
@@ -125,9 +125,9 @@ const markers: Record<DiffLine["type"], string> = {
.iap-btn-cancel {
background: none;
border: 1px solid var(--color-border);
color: var(--color-text-secondary);
border-radius: var(--radius-sm);
border: 1px solid var(--fs-border-color);
color: var(--fs-text-secondary);
border-radius: var(--fs-radius-sm);
padding: 0.15rem 0.5rem;
cursor: pointer;
font-size: 0.8rem;
@@ -135,8 +135,8 @@ const markers: Record<DiffLine["type"], string> = {
flex-shrink: 0;
}
.iap-btn-cancel:hover {
border-color: var(--color-danger);
color: var(--color-danger);
border-color: var(--fs-error);
color: var(--fs-error);
}
.iap-stream-preview {
@@ -150,29 +150,29 @@ const markers: Record<DiffLine["type"], string> = {
.iap-waiting {
padding: 0.75rem;
font-size: 0.85rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
/* ── Review ── */
.iap-review-title {
flex: 1;
font-weight: 600;
color: var(--color-text);
color: var(--fs-text-primary);
}
.iap-btn-toggle {
background: none;
border: 1px solid var(--color-border);
color: var(--color-text-secondary);
border-radius: var(--radius-sm);
border: 1px solid var(--fs-border-color);
color: var(--fs-text-secondary);
border-radius: var(--fs-radius-sm);
padding: 0.15rem 0.5rem;
cursor: pointer;
font-size: 0.78rem;
font-family: inherit;
}
.iap-btn-toggle:hover {
border-color: var(--color-primary);
color: var(--color-primary);
border-color: var(--fs-accent);
color: var(--fs-accent);
}
.iap-actions {
@@ -183,7 +183,7 @@ const markers: Record<DiffLine["type"], string> = {
.iap-btn-accept,
.iap-btn-reject {
border: none;
border-radius: var(--radius-sm);
border-radius: var(--fs-radius-sm);
padding: 0.2rem 0.65rem;
cursor: pointer;
font-size: 0.8rem;
@@ -191,19 +191,19 @@ const markers: Record<DiffLine["type"], string> = {
font-weight: var(--fs-weight-medium);
}
.iap-btn-accept {
background: var(--color-success);
background: var(--fs-success);
color: var(--fs-text-on-action);
}
.iap-btn-accept:hover { opacity: 0.85; }
.iap-btn-reject {
background: var(--color-bg-card);
color: var(--color-text-secondary);
border: 1px solid var(--color-border);
background: var(--fs-surface-raised);
color: var(--fs-text-secondary);
border: 1px solid var(--fs-border-color);
}
.iap-btn-reject:hover {
border-color: var(--color-danger);
color: var(--color-danger);
border-color: var(--fs-error);
color: var(--fs-error);
}
/* ── Diff ── */
@@ -224,14 +224,14 @@ const markers: Record<DiffLine["type"], string> = {
word-break: break-word;
}
.iap-diff-equal { color: var(--color-text-muted); }
.iap-diff-equal { color: var(--fs-text-tertiary); }
.iap-diff-delete {
background: color-mix(in srgb, var(--color-danger) 10%, transparent);
color: var(--color-danger);
background: color-mix(in srgb, var(--fs-error) 10%, transparent);
color: var(--fs-error);
}
.iap-diff-insert {
background: color-mix(in srgb, var(--color-success) 10%, transparent);
color: var(--color-success);
background: color-mix(in srgb, var(--fs-success) 10%, transparent);
color: var(--fs-success);
}
.iap-diff-marker {
@@ -243,7 +243,7 @@ const markers: Record<DiffLine["type"], string> = {
.iap-diff-empty {
padding: 0.75rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
font-size: 0.85rem;
font-family: inherit;
}
+11 -11
View File
@@ -111,9 +111,9 @@ const groups = [
align-items: center;
gap: 2px;
flex-wrap: wrap;
background: var(--color-bg-secondary);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-lg);
padding: 3px 4px;
}
@@ -127,7 +127,7 @@ const groups = [
display: block;
width: 1px;
height: 18px;
background: var(--color-border);
background: var(--fs-border-color);
flex-shrink: 0;
margin: 0 3px;
}
@@ -141,7 +141,7 @@ const groups = [
border: none;
border-radius: 5px;
background: transparent;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
cursor: pointer;
padding: 0;
transition: background 0.12s, color 0.12s, box-shadow 0.12s;
@@ -149,19 +149,19 @@ const groups = [
}
.md-btn:hover {
background: var(--color-bg-card);
color: var(--color-text);
background: var(--fs-surface-raised);
color: var(--fs-text-primary);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.md-btn.active {
background: color-mix(in srgb, var(--color-primary) 14%, transparent);
color: var(--color-primary);
box-shadow: 0 0 0 1px color-mix(in srgb, var(--color-primary) 35%, transparent);
background: color-mix(in srgb, var(--fs-accent) 14%, transparent);
color: var(--fs-accent);
box-shadow: 0 0 0 1px color-mix(in srgb, var(--fs-accent) 35%, transparent);
}
.md-btn.active:hover {
background: color-mix(in srgb, var(--color-primary) 22%, transparent);
background: color-mix(in srgb, var(--fs-accent) 22%, transparent);
}
.btn-icon {
@@ -66,10 +66,10 @@ function onChange(e: Event) {
<style scoped>
.milestone-select {
padding: 0.4rem 0.6rem;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
background: var(--color-bg);
color: var(--color-text);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
background: var(--fs-surface-page);
color: var(--fs-text-primary);
font-size: 0.875rem;
font-family: inherit;
box-sizing: border-box;
@@ -77,7 +77,7 @@ function onChange(e: Event) {
}
.milestone-select:focus {
outline: none;
border-color: var(--color-primary);
border-color: var(--fs-accent);
}
.milestone-select:disabled {
opacity: 0.5;
+17 -17
View File
@@ -60,15 +60,15 @@ function goEdit() {
.note-card {
display: block;
padding: 1rem;
border-radius: var(--radius-md);
border-radius: var(--fs-radius-lg);
text-decoration: none;
color: inherit;
background: var(--color-bg-card);
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06), 0 0 0 1px color-mix(in srgb, var(--color-primary) 6%, transparent);
background: var(--fs-surface-raised);
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06), 0 0 0 1px color-mix(in srgb, var(--fs-accent) 6%, transparent);
transition: box-shadow 0.2s, transform 0.18s ease;
}
.note-card:hover {
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.10), 0 0 0 1px color-mix(in srgb, var(--color-primary) 14.0%, transparent);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.10), 0 0 0 1px color-mix(in srgb, var(--fs-accent) 14.0%, transparent);
transform: translateY(-2px);
}
@@ -78,18 +78,18 @@ function goEdit() {
align-items: center;
gap: 0.6rem;
padding: 0.45rem 0.75rem;
background: var(--color-bg-card);
background: var(--fs-surface-raised);
box-shadow: none;
border-radius: 0;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
transform: none !important;
}
.note-card.compact:first-child {
border-top: 1px solid var(--color-border);
border-top: 1px solid var(--fs-border-color);
}
.note-card.compact:hover {
box-shadow: none;
background: color-mix(in srgb, var(--color-primary) 4%, transparent);
background: color-mix(in srgb, var(--fs-accent) 4%, transparent);
transform: none;
}
.note-title-compact {
@@ -108,7 +108,7 @@ function goEdit() {
}
.timestamp-compact {
font-size: 0.72rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
flex-shrink: 0;
white-space: nowrap;
}
@@ -133,20 +133,20 @@ function goEdit() {
flex-shrink: 0;
padding: 0.25rem 0.6rem;
font-size: 0.8rem;
background: var(--color-bg-card);
color: var(--color-text-secondary);
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
background: var(--fs-surface-raised);
color: var(--fs-text-secondary);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
cursor: pointer;
transition: color 0.15s, border-color 0.15s;
}
.btn-edit:hover {
color: var(--color-primary);
border-color: var(--color-primary);
color: var(--fs-accent);
border-color: var(--fs-accent);
}
.note-preview {
margin: 0 0 0.5rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
font-size: 0.9rem;
max-height: 7.5em;
overflow: hidden;
@@ -163,6 +163,6 @@ function goEdit() {
.timestamp {
margin-left: auto;
font-size: 0.75rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
</style>
+7 -7
View File
@@ -60,11 +60,11 @@ onUnmounted(() => {
.btn-bell {
background: none;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
padding: 0.25rem 0.45rem;
cursor: pointer;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
display: flex;
align-items: center;
justify-content: center;
@@ -72,16 +72,16 @@ onUnmounted(() => {
}
.btn-bell:hover,
.btn-bell.active {
background: var(--color-bg-card);
color: var(--color-text);
border-color: var(--color-primary);
background: var(--fs-surface-raised);
color: var(--fs-text-primary);
border-color: var(--fs-accent);
}
.bell-badge {
position: absolute;
top: -5px;
right: -5px;
background: var(--color-danger);
background: var(--fs-error);
color: var(--fs-text-on-action);
font-size: 0.6rem;
font-weight: 700;
@@ -85,9 +85,9 @@ onMounted(() => store.fetchAll())
width: 340px;
max-height: 400px;
overflow-y: auto;
background: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: var(--radius-lg);
background: var(--fs-surface-hover);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-xl);
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.18);
z-index: 500;
}
@@ -97,10 +97,10 @@ onMounted(() => store.fetchAll())
align-items: center;
justify-content: space-between;
padding: 0.75rem 1rem;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
position: sticky;
top: 0;
background: var(--color-surface);
background: var(--fs-surface-hover);
}
.notif-panel-title {
@@ -114,12 +114,12 @@ onMounted(() => store.fetchAll())
align-items: flex-start;
gap: 0.6rem;
padding: 0.75rem 1rem;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
cursor: pointer;
transition: background 0.1s;
}
.notif-item:last-child { border-bottom: none; }
.notif-item:hover { background: var(--color-hover); }
.notif-item:hover { background: var(--fs-surface-hover); }
.notif-icon { font-size: 1.2rem; flex-shrink: 0; margin-top: 0.1rem; }
@@ -127,10 +127,10 @@ onMounted(() => store.fetchAll())
.notif-msg {
margin: 0 0 0.2rem;
font-size: 0.85rem;
color: var(--color-text);
color: var(--fs-text-primary);
line-height: 1.4;
word-break: break-word;
}
.notif-time { font-size: 0.75rem; color: var(--color-muted); }
.notif-time { font-size: 0.75rem; color: var(--fs-text-tertiary); }
</style>
+8 -8
View File
@@ -74,27 +74,27 @@ function goToPage(page: number) {
}
.page-btn {
padding: 0.35rem 0.7rem;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
background: var(--color-bg-card);
color: var(--color-text);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
background: var(--fs-surface-raised);
color: var(--fs-text-primary);
cursor: pointer;
font-size: 0.85rem;
}
.page-btn:hover:not(:disabled) {
background: var(--color-bg-secondary);
background: var(--fs-surface-raised);
}
.page-btn:disabled {
opacity: 0.4;
cursor: default;
}
.page-btn.active {
background: var(--color-primary);
background: var(--fs-accent);
color: var(--fs-text-on-action);
border-color: var(--color-primary);
border-color: var(--fs-accent);
}
.ellipsis {
padding: 0 0.25rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
</style>
+6 -6
View File
@@ -33,15 +33,15 @@ const labels: Record<TaskPriority, string> = {
letter-spacing: 0.025em;
}
.priority-low {
background: var(--color-priority-low-bg);
color: var(--color-priority-low);
background: var(--fs-priority-low-bg);
color: var(--fs-priority-low);
}
.priority-medium {
background: var(--color-priority-medium-bg);
color: var(--color-priority-medium);
background: var(--fs-priority-medium-bg);
color: var(--fs-priority-medium);
}
.priority-high {
background: var(--color-priority-high-bg);
color: var(--color-priority-high);
background: var(--fs-priority-high-bg);
color: var(--fs-priority-high);
}
</style>
+17 -17
View File
@@ -128,16 +128,16 @@ watch(() => [props.projectId, props.designSystemId], run);
}
.pdt-note {
background: var(--color-surface);
border: 1px solid var(--color-border);
border-left: 3px solid var(--color-warning);
background: var(--fs-surface-hover);
border: 1px solid var(--fs-border-color);
border-left: 3px solid var(--fs-warning);
border-radius: var(--fs-radius-sm);
padding: var(--fs-space-3) var(--fs-space-4);
}
.pdt-note p {
margin: var(--fs-space-2) 0 0;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
font-size: var(--fs-size-body-sm);
line-height: var(--fs-leading-body);
max-width: 70ch;
@@ -146,18 +146,18 @@ watch(() => [props.projectId, props.designSystemId], run);
.pdt-muted,
.pdt-clean,
.pdt-summary {
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
font-size: var(--fs-size-body-sm);
margin: 0 0 var(--fs-space-3);
max-width: 70ch;
}
.pdt-clean {
color: var(--color-status-done);
color: var(--fs-status-done);
}
.pdt-summary {
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
}
.pdt-list {
@@ -170,7 +170,7 @@ watch(() => [props.projectId, props.designSystemId], run);
}
.pdt-finding {
border: 1px solid var(--color-border);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-md);
padding: var(--fs-space-3);
min-width: 0;
@@ -179,11 +179,11 @@ watch(() => [props.projectId, props.designSystemId], run);
.pdt-title {
display: block;
font-weight: var(--fs-weight-medium);
color: var(--color-text);
color: var(--fs-text-primary);
text-decoration: none;
margin-bottom: var(--fs-space-2);
}
.pdt-title:hover { color: var(--color-primary-solid); }
.pdt-title:hover { color: var(--fs-accent); }
.pdt-row {
display: flex;
@@ -205,18 +205,18 @@ watch(() => [props.projectId, props.designSystemId], run);
}
.pdt-tag.unknown {
background: var(--color-priority-high-bg);
color: var(--color-priority-high);
background: var(--fs-priority-high-bg);
color: var(--fs-priority-high);
}
.pdt-tag.local {
background: var(--color-priority-medium-bg);
color: var(--color-priority-medium);
background: var(--fs-priority-medium-bg);
color: var(--fs-priority-medium);
}
.pdt-tag.superseded {
background: var(--color-surface);
color: var(--color-text-muted);
background: var(--fs-surface-hover);
color: var(--fs-text-tertiary);
}
.pdt-detail {
@@ -224,7 +224,7 @@ watch(() => [props.projectId, props.designSystemId], run);
flex-wrap: wrap;
gap: var(--fs-space-2);
font-size: var(--fs-size-code);
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
min-width: 0;
}
+5 -5
View File
@@ -51,10 +51,10 @@ function onChange(e: Event) {
<style scoped>
.project-selector {
padding: 0.4rem 0.5rem;
border: 1px solid var(--color-input-border);
border-radius: var(--radius-sm);
background: var(--color-bg-card);
color: var(--color-text);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
background: var(--fs-surface-raised);
color: var(--fs-text-primary);
font-size: 0.9rem;
font-family: inherit;
width: 100%;
@@ -62,6 +62,6 @@ function onChange(e: Event) {
}
.project-selector:focus {
outline: none;
border-color: var(--color-primary);
border-color: var(--fs-accent);
}
</style>
+6 -6
View File
@@ -153,19 +153,19 @@ const calendarDayMax = computed(() =>
}
.rec-label {
font-size: 0.78rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
min-width: 2.5rem;
}
.rec-num-input {
width: 4rem;
padding: 0.25rem 0.4rem;
border: 1px solid var(--color-input-border);
border-radius: var(--radius-sm);
background: var(--color-bg);
color: var(--color-text);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
background: var(--fs-surface-page);
color: var(--fs-text-primary);
font-size: 0.85rem;
font-family: inherit;
}
.rec-num-input:focus { outline: none; border-color: var(--color-primary); }
.rec-num-input:focus { outline: none; border-color: var(--fs-accent); }
.rec-unit { min-width: 6rem; }
</style>
+5 -5
View File
@@ -28,14 +28,14 @@ defineExpose({ focus: () => inputRef.value?.focus() });
.search-input {
width: 100%;
padding: 0.5rem 0.75rem;
border: 1px solid var(--color-input-border);
border-radius: var(--radius-sm);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
font-size: 1rem;
box-sizing: border-box;
background: var(--color-bg-card);
color: var(--color-text);
background: var(--fs-surface-raised);
color: var(--fs-text-primary);
}
.search-input::placeholder {
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
</style>
+26 -26
View File
@@ -206,9 +206,9 @@ onMounted(async () => {
}
.share-dialog {
background: var(--color-bg-card);
border: 1px solid var(--color-border);
border-radius: var(--radius-lg);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-xl);
width: 480px;
max-width: 95vw;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
@@ -220,7 +220,7 @@ onMounted(async () => {
align-items: center;
justify-content: space-between;
padding: 1.25rem 1.5rem;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
}
.share-title {
@@ -228,7 +228,7 @@ onMounted(async () => {
font-size: 1.1rem;
font-weight: 700;
margin: 0;
color: var(--color-text);
color: var(--fs-text-primary);
}
@@ -240,17 +240,17 @@ onMounted(async () => {
.share-tab {
background: none;
border: 1px solid var(--color-border);
border: 1px solid var(--fs-border-color);
border-radius: 6px;
padding: 0.3rem 0.8rem;
font-size: 0.82rem;
cursor: pointer;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
transition: all 0.15s;
}
.share-tab.active {
background: var(--color-primary);
border-color: var(--color-primary);
background: var(--fs-accent);
border-color: var(--fs-accent);
color: var(--fs-text-on-action);
}
@@ -269,23 +269,23 @@ onMounted(async () => {
.share-input {
width: 100%;
padding: 0.45rem 0.7rem;
border: 1px solid var(--color-border);
border: 1px solid var(--fs-border-color);
border-radius: 6px;
background: var(--color-bg-card);
color: var(--color-text);
background: var(--fs-surface-raised);
color: var(--fs-text-primary);
font-size: 0.9rem;
outline: none;
transition: border-color 0.15s;
}
.share-input:focus { border-color: var(--color-primary); }
.share-input:focus { border-color: var(--fs-accent); }
.user-results {
position: absolute;
top: 100%;
left: 0;
right: 0;
background: var(--color-bg-card);
border: 1px solid var(--color-border);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: 6px;
margin-top: 2px;
list-style: none;
@@ -304,24 +304,24 @@ onMounted(async () => {
cursor: pointer;
transition: background 0.1s;
}
.user-result-item:hover { background: var(--color-bg-secondary); }
.user-result-item:hover { background: var(--fs-surface-raised); }
.user-result-name { font-weight: 600; font-size: 0.88rem; }
.user-result-email { color: var(--color-text-muted); font-size: 0.8rem; }
.user-result-email { color: var(--fs-text-tertiary); font-size: 0.8rem; }
.perm-select {
padding: 0.45rem 0.5rem;
border: 1px solid var(--color-border);
border: 1px solid var(--fs-border-color);
border-radius: 6px;
background: var(--color-bg-card);
color: var(--color-text);
background: var(--fs-surface-raised);
color: var(--fs-text-primary);
font-size: 0.85rem;
cursor: pointer;
}
.btn-add-share {
padding: 0.45rem 1rem;
background: var(--gradient-cta);
background: var(--fs-gradient-cta);
color: var(--fs-text-on-action);
border: none;
border-radius: 6px;
@@ -342,7 +342,7 @@ onMounted(async () => {
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
margin: 0 0 0.5rem;
}
@@ -361,7 +361,7 @@ onMounted(async () => {
gap: 0.5rem;
padding: 0.5rem 0.75rem;
border-radius: 8px;
background: var(--color-bg-secondary);
background: var(--fs-surface-raised);
}
.share-target-icon { font-size: 1rem; flex-shrink: 0; }
@@ -369,10 +369,10 @@ onMounted(async () => {
.perm-select-inline {
padding: 0.25rem 0.4rem;
border: 1px solid var(--color-border);
border: 1px solid var(--fs-border-color);
border-radius: 4px;
background: var(--color-bg-card);
color: var(--color-text);
background: var(--fs-surface-raised);
color: var(--fs-text-primary);
font-size: 0.8rem;
cursor: pointer;
}
@@ -127,7 +127,7 @@ const totalTokens = () =>
.srp-legend {
font-size: var(--fs-size-label);
font-weight: var(--fs-weight-medium);
color: var(--color-text);
color: var(--fs-text-primary);
padding: 0 var(--fs-space-2);
}
@@ -135,7 +135,7 @@ const totalTokens = () =>
.srp-note {
margin: 0 0 var(--fs-space-3);
font-size: var(--fs-size-body-sm);
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
line-height: var(--fs-leading-body);
max-width: 62ch;
}
@@ -160,16 +160,16 @@ const totalTokens = () =>
cursor: pointer;
min-width: 0;
}
.srp-item:hover { background: var(--color-hover); }
.srp-item:hover { background: var(--fs-surface-hover); }
.srp-name {
font-size: var(--fs-size-body-sm);
color: var(--color-text);
color: var(--fs-text-primary);
}
.srp-count {
font-size: var(--fs-size-tiny);
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
font-variant-numeric: tabular-nums;
}
@@ -178,7 +178,7 @@ const totalTokens = () =>
.srp-desc {
grid-column: 1 / -1;
font-size: var(--fs-size-tiny);
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
line-height: var(--fs-leading-body);
}
@@ -196,7 +196,7 @@ const totalTokens = () =>
align-items: center;
gap: var(--fs-space-2);
font-size: var(--fs-size-body-sm);
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
}
.srp-prefix-input {
@@ -207,6 +207,6 @@ const totalTokens = () =>
.srp-total {
font-size: var(--fs-size-tiny);
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
</style>
+8 -8
View File
@@ -38,20 +38,20 @@ const labels: Record<TaskStatus, string> = {
letter-spacing: 0.025em;
}
.status-todo {
background: color-mix(in srgb, var(--color-status-todo-bg) 78%, var(--color-status-todo) 22%);
color: color-mix(in srgb, var(--color-status-todo) 85%, #000 15%);
background: color-mix(in srgb, var(--fs-status-todo-bg) 78%, var(--fs-status-todo) 22%);
color: color-mix(in srgb, var(--fs-status-todo) 85%, #000 15%);
}
.status-in_progress {
background: color-mix(in srgb, var(--color-status-in-progress-bg) 78%, var(--color-status-in-progress) 22%);
color: color-mix(in srgb, var(--color-status-in-progress) 85%, #000 15%);
background: color-mix(in srgb, var(--fs-status-in-progress-bg) 78%, var(--fs-status-in-progress) 22%);
color: color-mix(in srgb, var(--fs-status-in-progress) 85%, #000 15%);
}
.status-done {
background: color-mix(in srgb, var(--color-status-done-bg) 78%, var(--color-status-done) 22%);
color: color-mix(in srgb, var(--color-status-done) 85%, #000 15%);
background: color-mix(in srgb, var(--fs-status-done-bg) 78%, var(--fs-status-done) 22%);
color: color-mix(in srgb, var(--fs-status-done) 85%, #000 15%);
}
.status-cancelled {
background: color-mix(in srgb, var(--color-bg-secondary) 78%, var(--color-text-muted) 22%);
color: var(--color-text-muted);
background: color-mix(in srgb, var(--fs-surface-raised) 78%, var(--fs-text-tertiary) 22%);
color: var(--fs-text-tertiary);
}
.clickable {
cursor: pointer;
@@ -70,9 +70,9 @@ defineExpose({ onKeyDown });
list-style: none;
margin: 0;
padding: 0;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
background: var(--color-bg-card);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
background: var(--fs-surface-raised);
box-shadow: 0 4px 12px var(--color-shadow);
max-height: 200px;
overflow-y: auto;
@@ -85,6 +85,6 @@ defineExpose({ onKeyDown });
}
.ac-item:hover,
.ac-item.active {
background: var(--color-bg-secondary);
background: var(--fs-surface-raised);
}
</style>
+58 -58
View File
@@ -253,7 +253,7 @@ async function confirmDelete() {
<template v-else>
<span
class="system-swatch"
:style="{ background: system.color || 'var(--color-text-muted)' }"
:style="{ background: system.color || 'var(--fs-text-tertiary)' }"
aria-hidden="true"
></span>
<div class="system-body">
@@ -325,41 +325,41 @@ async function confirmDelete() {
/* ── Open issues ──────────────────────────────────────────────── */
.open-issues { display: flex; flex-direction: column; gap: 0.35rem; }
.open-issues-label { font-size: 0.72rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--color-text-muted); }
.open-issues-label { font-size: 0.72rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--fs-text-tertiary); }
.issue-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.2rem; }
.issue-link { display: flex; align-items: center; gap: 0.5rem; padding: 0.35rem 0.5rem; border-radius: var(--radius-sm); text-decoration: none; color: var(--color-text); font-size: 0.85rem; }
.issue-link:hover { background: var(--color-bg-secondary); }
.issue-mark { color: var(--color-text-muted); flex-shrink: 0; }
.issue-mark.imk-in_progress { color: var(--color-primary); }
.issue-link { display: flex; align-items: center; gap: 0.5rem; padding: 0.35rem 0.5rem; border-radius: var(--fs-radius-sm); text-decoration: none; color: var(--fs-text-primary); font-size: 0.85rem; }
.issue-link:hover { background: var(--fs-surface-raised); }
.issue-mark { color: var(--fs-text-tertiary); flex-shrink: 0; }
.issue-mark.imk-in_progress { color: var(--fs-accent); }
.issue-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.issue-systems { display: flex; gap: 0.25rem; flex-shrink: 0; flex-wrap: wrap; }
.issue-sys-chip { font-size: 0.66rem; color: var(--color-text-secondary); background: var(--color-bg-secondary); border-radius: 999px; padding: 0.05rem 0.4rem; }
.issue-sys-chip { font-size: 0.66rem; color: var(--fs-text-secondary); background: var(--fs-surface-raised); border-radius: 999px; padding: 0.05rem 0.4rem; }
/* ── Toolbar ──────────────────────────────────────────────────── */
.systems-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; }
.btn-add-system {
background: none;
border: 1px dashed var(--color-border);
color: var(--color-text-secondary);
border: 1px dashed var(--fs-border-color);
color: var(--fs-text-secondary);
padding: 0.28rem 0.65rem;
border-radius: var(--radius-sm);
border-radius: var(--fs-radius-sm);
cursor: pointer;
font-size: 0.78rem;
font-family: inherit;
}
.btn-add-system:hover { border-color: var(--color-primary); color: var(--color-primary); }
.btn-add-system:focus-visible { outline: none; border-color: var(--color-primary); color: var(--color-primary); }
.btn-add-system:hover { border-color: var(--fs-accent); color: var(--fs-accent); }
.btn-add-system:focus-visible { outline: none; border-color: var(--fs-accent); color: var(--fs-accent); }
.archived-toggle {
display: inline-flex;
align-items: center;
gap: 0.4rem;
font-size: 0.78rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
cursor: pointer;
user-select: none;
}
.archived-checkbox { accent-color: var(--color-primary); cursor: pointer; }
.archived-checkbox { accent-color: var(--fs-accent); cursor: pointer; }
/* ── Create / edit form ───────────────────────────────────────── */
.system-form {
@@ -367,23 +367,23 @@ async function confirmDelete() {
flex-direction: column;
gap: 0.5rem;
padding: 0.75rem;
background: var(--color-bg-card);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-lg);
}
.system-form--inline { padding: 0; background: none; border: none; flex: 1; }
.system-input, .system-textarea {
padding: 0.4rem 0.6rem;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
background: var(--color-bg);
color: var(--color-text);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
background: var(--fs-surface-page);
color: var(--fs-text-primary);
font-size: 0.875rem;
font-family: inherit;
box-sizing: border-box;
width: 100%;
}
.system-input:focus, .system-textarea:focus { outline: none; border-color: var(--color-primary); }
.system-input:focus, .system-textarea:focus { outline: none; border-color: var(--fs-accent); }
.system-textarea { resize: vertical; }
.system-form-actions { display: flex; gap: 0.4rem; }
@@ -417,9 +417,9 @@ async function confirmDelete() {
align-items: flex-start;
gap: 0.6rem;
padding: 0.6rem 0.75rem;
background: var(--color-bg-card);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-lg);
}
.system-card--archived { opacity: 0.6; }
@@ -433,13 +433,13 @@ async function confirmDelete() {
}
.system-body { flex: 1; min-width: 0; }
.system-name-row { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.system-name { font-weight: 500; color: var(--color-text); word-break: break-word; }
.system-name { font-weight: 500; color: var(--fs-text-primary); word-break: break-word; }
.issue-badge {
font-size: 0.7rem;
font-weight: 500;
background: color-mix(in srgb, var(--color-primary) 12%, transparent);
border: 1px solid color-mix(in srgb, var(--color-primary) 30%, transparent);
color: var(--color-primary);
background: color-mix(in srgb, var(--fs-accent) 12%, transparent);
border: 1px solid color-mix(in srgb, var(--fs-accent) 30%, transparent);
color: var(--fs-accent);
border-radius: 999px;
padding: 0.05rem 0.45rem;
flex-shrink: 0;
@@ -449,15 +449,15 @@ async function confirmDelete() {
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.04em;
color: var(--color-text-muted);
background: color-mix(in srgb, var(--color-text-muted) 12%, transparent);
color: var(--fs-text-tertiary);
background: color-mix(in srgb, var(--fs-text-tertiary) 12%, transparent);
border-radius: 999px;
padding: 0.05rem 0.45rem;
}
.system-description {
margin: 0.25rem 0 0;
font-size: 0.82rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
line-height: 1.4;
word-break: break-word;
}
@@ -472,15 +472,15 @@ async function confirmDelete() {
background: none;
border: none;
cursor: pointer;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
width: 26px;
height: 26px;
border-radius: var(--radius-sm);
border-radius: var(--fs-radius-sm);
transition: background 0.12s, color 0.12s;
}
.action-btn:hover { background: var(--color-bg-secondary); color: var(--color-text); }
.action-btn:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 1px; opacity: 1; }
.action-delete:hover { color: var(--color-danger); }
.action-btn:hover { background: var(--fs-surface-raised); color: var(--fs-text-primary); }
.action-btn:focus-visible { outline: 2px solid var(--fs-accent); outline-offset: 1px; opacity: 1; }
.action-delete:hover { color: var(--fs-error); }
/* ── Empty ────────────────────────────────────────────────────── */
.systems-empty {
@@ -490,25 +490,25 @@ async function confirmDelete() {
gap: 0.4rem;
padding: 2rem 1rem;
text-align: center;
border: 1px dashed var(--color-border);
border-radius: var(--radius-md);
border: 1px dashed var(--fs-border-color);
border-radius: var(--fs-radius-lg);
}
.empty-title { margin: 0; font-weight: 500; color: var(--color-text); }
.empty-sub { margin: 0 0 0.5rem; font-size: 0.82rem; color: var(--color-text-muted); max-width: 32ch; }
.empty-title { margin: 0; font-weight: 500; color: var(--fs-text-primary); }
.empty-sub { margin: 0 0 0.5rem; font-size: 0.82rem; color: var(--fs-text-tertiary); max-width: 32ch; }
.error-msg { color: var(--color-danger); font-size: 0.9rem; }
.error-msg { color: var(--fs-error); font-size: 0.9rem; }
/* ── Skeleton ─────────────────────────────────────────────────── */
@keyframes skel-shine { to { background-position: 200% center; } }
.systems-skeleton { display: flex; flex-direction: column; gap: 0.4rem; }
.skel-row {
height: 3rem;
border-radius: var(--radius-md);
border-radius: var(--fs-radius-lg);
background: linear-gradient(
90deg,
var(--color-bg-secondary) 25%,
color-mix(in srgb, var(--color-text-muted) 16%, var(--color-bg-secondary)) 50%,
var(--color-bg-secondary) 75%
var(--fs-surface-raised) 25%,
color-mix(in srgb, var(--fs-text-tertiary) 16%, var(--fs-surface-raised)) 50%,
var(--fs-surface-raised) 75%
);
background-size: 200% 100%;
animation: skel-shine 1.5s ease infinite;
@@ -518,33 +518,33 @@ async function confirmDelete() {
/* ── Modal ────────────────────────────────────────────────────── */
.modal-overlay {
position: fixed; inset: 0;
background: var(--color-overlay);
background: var(--fs-overlay);
display: flex; align-items: center; justify-content: center;
z-index: 200;
}
.modal-card {
background: var(--color-bg-card);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-lg);
padding: 1.5rem;
width: 100%;
max-width: 400px;
box-shadow: 0 8px 32px var(--color-shadow);
}
.modal-title { margin: 0 0 0.75rem; font-size: 1.05rem; }
.modal-message { font-size: 0.9rem; color: var(--color-text-secondary); margin: 0 0 1.25rem; line-height: 1.5; }
.modal-message { font-size: 0.9rem; color: var(--fs-text-secondary); margin: 0 0 1.25rem; line-height: 1.5; }
.modal-actions { display: flex; justify-content: flex-end; gap: 0.5rem; }
.modal-btn {
padding: 0.4rem 0.9rem;
border: 1px solid var(--color-border);
background: var(--color-bg-secondary);
color: var(--color-text);
border-radius: var(--radius-sm);
border: 1px solid var(--fs-border-color);
background: var(--fs-surface-raised);
color: var(--fs-text-primary);
border-radius: var(--fs-radius-sm);
cursor: pointer;
font-size: 0.875rem;
font-family: inherit;
}
.modal-btn:hover { background: var(--color-bg); }
.modal-btn-danger { background: var(--color-action-destructive); border-color: var(--color-action-destructive); color: var(--fs-text-on-action); }
.modal-btn-danger:hover { background: var(--color-action-destructive-hover); border-color: var(--color-action-destructive-hover); }
.modal-btn:hover { background: var(--fs-surface-page); }
.modal-btn-danger { background: var(--fs-action-destructive); border-color: var(--fs-action-destructive); color: var(--fs-text-on-action); }
.modal-btn-danger:hover { background: var(--fs-action-destructive-hover); border-color: var(--fs-action-destructive-hover); }
</style>
+3 -3
View File
@@ -60,7 +60,7 @@ function scrollTo(id: string) {
.toc-title {
font-size: 0.8rem;
text-transform: uppercase;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
margin: 0 0 0.5rem;
letter-spacing: 0.05em;
}
@@ -73,11 +73,11 @@ function scrollTo(id: string) {
margin-bottom: 0.25rem;
}
.toc-link {
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
text-decoration: none;
cursor: pointer;
}
.toc-link:hover {
color: var(--color-primary);
color: var(--fs-accent);
}
</style>
+13 -13
View File
@@ -154,9 +154,9 @@ function focusInput() {
align-items: center;
gap: 0.35rem;
padding: 0.35rem 0.6rem;
border: 1px solid var(--color-input-border);
border-radius: var(--radius-sm);
background: var(--color-bg-card);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
background: var(--fs-surface-raised);
cursor: text;
min-height: 2.25rem;
}
@@ -166,9 +166,9 @@ function focusInput() {
gap: 0.2rem;
padding: 0.15rem 0.5rem;
border-radius: 999px;
background: color-mix(in srgb, var(--color-primary) 15%, transparent);
border: 1px solid var(--color-primary);
color: var(--color-primary);
background: color-mix(in srgb, var(--fs-accent) 15%, transparent);
border: 1px solid var(--fs-accent);
color: var(--fs-accent);
font-size: 0.8rem;
white-space: nowrap;
}
@@ -195,7 +195,7 @@ function focusInput() {
border: none;
outline: none;
background: transparent;
color: var(--color-text);
color: var(--fs-text-primary);
font-size: 0.875rem;
padding: 0;
}
@@ -205,9 +205,9 @@ function focusInput() {
left: 0;
min-width: 160px;
max-width: 280px;
background: var(--color-bg-card);
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
list-style: none;
margin: 0;
@@ -218,11 +218,11 @@ function focusInput() {
padding: 0.35rem 0.75rem;
font-size: 0.85rem;
cursor: pointer;
color: var(--color-text);
color: var(--fs-text-primary);
}
.tag-autocomplete-item:hover,
.tag-autocomplete-item.selected {
background: var(--color-bg-hover);
color: var(--color-primary);
background: var(--fs-surface-hover);
color: var(--fs-accent);
}
</style>
+5 -5
View File
@@ -29,8 +29,8 @@ defineEmits<{
display: inline-flex;
align-items: center;
gap: 0.25rem;
background: var(--color-tag-bg);
color: var(--color-tag-text);
background: var(--fs-accent-soft);
color: var(--fs-accent);
padding: 0.15rem 0.5rem;
border-radius: 12px;
font-size: 0.8rem;
@@ -39,13 +39,13 @@ defineEmits<{
transition: color 0.15s, background 0.15s;
}
.tag-pill:hover {
color: var(--color-primary);
background: var(--color-primary-tint);
color: var(--fs-accent);
background: var(--fs-accent-soft);
}
.dismiss {
background: none;
border: none;
color: var(--color-tag-text);
color: var(--fs-accent);
cursor: pointer;
font-size: 0.9rem;
line-height: 1;
+20 -20
View File
@@ -108,15 +108,15 @@ function isOverdue(): boolean {
.task-card {
display: block;
padding: 1rem;
border-radius: var(--radius-md);
border-radius: var(--fs-radius-lg);
text-decoration: none;
color: inherit;
background: var(--color-bg-card);
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06), 0 0 0 1px color-mix(in srgb, var(--color-primary) 6%, transparent);
background: var(--fs-surface-raised);
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06), 0 0 0 1px color-mix(in srgb, var(--fs-accent) 6%, transparent);
transition: box-shadow 0.2s, transform 0.18s ease;
}
.task-card:hover {
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.10), 0 0 0 1px color-mix(in srgb, var(--color-primary) 14.0%, transparent);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.10), 0 0 0 1px color-mix(in srgb, var(--fs-accent) 14.0%, transparent);
transform: translateY(-2px);
}
@@ -144,19 +144,19 @@ function isOverdue(): boolean {
opacity: 0.8;
}
.dot-todo {
background: var(--color-status-todo);
border: 2px solid var(--color-status-todo);
background: var(--fs-status-todo);
border: 2px solid var(--fs-status-todo);
background: transparent;
border: 2px solid var(--color-text-muted);
border: 2px solid var(--fs-text-tertiary);
}
.dot-in-progress {
background: var(--color-status-in-progress);
background: var(--fs-status-in-progress);
}
.dot-done {
background: var(--color-status-done);
background: var(--fs-status-done);
}
.dot-cancelled {
background: var(--color-status-cancelled);
background: var(--fs-status-cancelled);
}
.task-title-compact {
@@ -170,10 +170,10 @@ function isOverdue(): boolean {
}
.project-crumb {
font-size: 0.75rem;
color: var(--color-text-muted);
background: var(--color-bg-secondary);
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
color: var(--fs-text-tertiary);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
padding: 0.1rem 0.4rem;
white-space: nowrap;
flex-shrink: 0;
@@ -185,12 +185,12 @@ function isOverdue(): boolean {
}
.due-compact {
font-size: 0.75rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
white-space: nowrap;
flex-shrink: 0;
}
.due-compact.overdue {
color: var(--color-danger);
color: var(--fs-error);
font-weight: 600;
}
/* Full layout */
@@ -211,7 +211,7 @@ function isOverdue(): boolean {
}
.task-preview {
margin: 0 0 0.5rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
font-size: 0.9rem;
max-height: 7.5em;
overflow: hidden;
@@ -224,15 +224,15 @@ function isOverdue(): boolean {
}
.due-date {
font-size: 0.8rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
}
.due-date.overdue {
color: var(--color-overdue);
color: var(--fs-overdue);
font-weight: 600;
}
.timestamp {
margin-left: auto;
font-size: 0.75rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
</style>
+19 -19
View File
@@ -175,9 +175,9 @@ onMounted(loadLogs);
<style scoped>
.log-section {
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
background: var(--color-bg-secondary);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
background: var(--fs-surface-raised);
padding: 0.6rem 0.75rem;
display: flex;
flex-direction: column;
@@ -187,7 +187,7 @@ onMounted(loadLogs);
.log-header {
font-size: 0.8rem;
font-weight: 600;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
text-transform: uppercase;
letter-spacing: 0.04em;
margin-bottom: 0.15rem;
@@ -195,11 +195,11 @@ onMounted(loadLogs);
.log-empty {
font-size: 0.8rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.log-entry {
border-top: 1px solid var(--color-border);
border-top: 1px solid var(--fs-border-color);
padding-top: 0.5rem;
}
@@ -212,11 +212,11 @@ onMounted(loadLogs);
}
.log-date {
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.log-duration-badge {
background: var(--color-primary);
background: var(--fs-accent);
color: var(--fs-text-on-action);
border-radius: 99px;
padding: 0.1rem 0.5rem;
@@ -235,10 +235,10 @@ onMounted(loadLogs);
.log-textarea {
width: 100%;
padding: 0.4rem 0.5rem;
border: 1px solid var(--color-input-border);
border-radius: var(--radius-sm);
background: var(--color-bg);
color: var(--color-text);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
background: var(--fs-surface-page);
color: var(--fs-text-primary);
font-size: 0.875rem;
font-family: inherit;
resize: vertical;
@@ -247,7 +247,7 @@ onMounted(loadLogs);
.log-textarea:focus {
outline: none;
border-color: var(--color-primary);
border-color: var(--fs-accent);
}
.log-add-controls,
@@ -259,7 +259,7 @@ onMounted(loadLogs);
.log-duration-label {
font-size: 0.8rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
display: flex;
align-items: center;
gap: 0.25rem;
@@ -268,16 +268,16 @@ onMounted(loadLogs);
.log-duration-input {
width: 5rem;
padding: 0.3rem 0.4rem;
border: 1px solid var(--color-input-border);
border-radius: var(--radius-sm);
background: var(--color-bg);
color: var(--color-text);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
background: var(--fs-surface-page);
color: var(--fs-text-primary);
font-size: 0.875rem;
}
.log-duration-input:focus {
outline: none;
border-color: var(--color-primary);
border-color: var(--fs-accent);
}
+1 -1
View File
@@ -156,7 +156,7 @@ defineExpose({ editor });
<style scoped>
.editor-error {
padding: 1rem;
color: var(--color-danger);
color: var(--fs-error);
font-size: 0.9rem;
}
</style>
@@ -57,13 +57,13 @@ const toastStore = useToastStore();
color: var(--fs-text-on-action);
}
.toast--success {
background: var(--color-toast-success);
background: var(--fs-success);
}
.toast--error {
background: var(--color-toast-error);
background: var(--fs-error);
}
.toast--warning {
background: var(--color-warning);
background: var(--fs-warning);
color: #1a1a1a;
}
.toast--warning .toast-close {
+20 -20
View File
@@ -183,22 +183,22 @@ function ruleWidth(value: string): string {
padding: 0.2rem 0.6rem;
font: inherit;
font-size: var(--fs-size-body-sm);
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
background: transparent;
border: 1px solid var(--color-border);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
cursor: pointer;
}
.tp-mode:hover { color: var(--color-text); }
.tp-mode:hover { color: var(--fs-text-primary); }
.tp-mode.active {
color: var(--color-primary-solid);
border-color: var(--color-primary);
background: var(--color-primary-faint);
color: var(--fs-accent);
border-color: var(--fs-accent);
background: var(--fs-accent-faint);
}
.tp-modes-note {
font-size: var(--fs-size-tiny);
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.tp-group { margin-bottom: var(--fs-space-6); }
@@ -207,7 +207,7 @@ function ruleWidth(value: string): string {
text-transform: uppercase;
letter-spacing: var(--fs-tracking-tiny);
font-size: var(--fs-size-tiny);
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
margin: 0 0 var(--fs-space-3);
padding-bottom: var(--fs-space-2);
border-bottom: var(--fs-border);
@@ -243,7 +243,7 @@ function ruleWidth(value: string): string {
border-radius: var(--fs-radius-sm);
padding: var(--fs-space-1);
overflow: hidden;
background: var(--color-bg-secondary);
background: var(--fs-surface-raised);
}
/* Text-bearing specimens get no box at all — a border around a value is a
@@ -272,8 +272,8 @@ function ruleWidth(value: string): string {
background-image:
linear-gradient(var(--tp-fill), var(--tp-fill)),
repeating-conic-gradient(
var(--color-border) 0% 25%,
var(--color-bg-secondary) 0% 50%
var(--fs-border-color) 0% 25%,
var(--fs-surface-raised) 0% 50%
);
background-size: auto, 10px 10px;
}
@@ -282,7 +282,7 @@ function ruleWidth(value: string): string {
width: 100%;
height: 100%;
border-radius: calc(var(--fs-radius-sm) - 2px);
background: var(--color-bg-card);
background: var(--fs-surface-raised);
}
.tp-rule-wrap {
@@ -297,27 +297,27 @@ function ruleWidth(value: string): string {
height: 0.4rem;
min-width: 1px;
flex: none;
background: var(--color-primary-solid);
background: var(--fs-accent);
border-radius: 999px;
}
.tp-rule-label {
font-family: var(--fs-font-mono);
font-size: var(--fs-size-tiny);
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
white-space: nowrap;
}
.tp-font {
font-size: 1.4rem;
color: var(--color-text);
color: var(--fs-text-primary);
line-height: 1;
}
.tp-plain {
font-family: var(--fs-font-mono);
font-size: var(--fs-size-code);
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@@ -325,7 +325,7 @@ function ruleWidth(value: string): string {
.tp-undecided {
font-size: var(--fs-size-tiny);
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
font-style: italic;
}
@@ -346,17 +346,17 @@ function ruleWidth(value: string): string {
.tp-name {
font-size: var(--fs-size-body-sm);
color: var(--color-text);
color: var(--fs-text-primary);
}
.tp-value {
font-family: var(--fs-font-mono);
font-size: var(--fs-size-tiny);
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
}
.tp-purpose {
font-size: var(--fs-size-tiny);
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
</style>
@@ -164,7 +164,7 @@ function restore() {
<style scoped>
.vh-section {
border-top: 1px solid var(--color-border);
border-top: 1px solid var(--fs-border-color);
}
.vh-header {
@@ -179,19 +179,19 @@ function restore() {
font-family: inherit;
text-align: left;
}
.vh-header:hover { background: var(--color-bg-secondary); }
.vh-header:hover { background: var(--fs-surface-raised); }
.vh-title {
font-size: 0.75rem;
font-weight: 700;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
text-transform: uppercase;
letter-spacing: 0.05em;
}
.vh-chevron {
font-size: 0.7rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.vh-body {
@@ -201,20 +201,20 @@ function restore() {
.vh-empty {
padding: 0.5rem 0.75rem;
font-size: 0.8rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.vh-item {
padding: 0.35rem 0.75rem;
font-size: 0.8rem;
color: var(--color-text);
color: var(--fs-text-primary);
cursor: pointer;
font-family: monospace;
border-left: 2px solid transparent;
}
.vh-item:hover {
background: var(--color-bg-secondary);
border-left-color: var(--color-primary);
background: var(--fs-surface-raised);
border-left-color: var(--fs-accent);
}
.vh-diff-actions {
@@ -225,20 +225,20 @@ function restore() {
.vh-btn-back {
background: none;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
padding: 0.25rem 0.6rem;
font-size: 0.78rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
cursor: pointer;
font-family: inherit;
}
.vh-btn-back:hover { border-color: var(--color-primary); color: var(--color-primary); }
.vh-btn-back:hover { border-color: var(--fs-accent); color: var(--fs-accent); }
.vh-btn-restore {
background: var(--color-action-primary);
background: var(--fs-action-primary);
border: none;
border-radius: var(--radius-sm);
border-radius: var(--fs-radius-sm);
padding: 0.25rem 0.6rem;
font-size: 0.78rem;
color: var(--fs-text-on-action);
+2 -2
View File
@@ -50,11 +50,11 @@ const label = computed(() => {
background: none;
border: none;
font-size: 0.72rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
cursor: pointer;
padding: 0;
white-space: nowrap;
flex-shrink: 0;
}
.word-count:hover { color: var(--color-text); }
.word-count:hover { color: var(--fs-text-primary); }
</style>
+35 -35
View File
@@ -452,8 +452,8 @@ defineExpose({ reload: loadProjectNotes });
flex-direction: row;
height: 100%;
overflow: hidden;
background: var(--color-surface);
border-left: 1px solid var(--color-border);
background: var(--fs-surface-hover);
border-left: 1px solid var(--fs-border-color);
}
/* ── Left rail ── */
@@ -463,7 +463,7 @@ defineExpose({ reload: loadProjectNotes });
display: flex;
flex-direction: column;
overflow: hidden;
background: var(--color-bg-card);
background: var(--fs-surface-raised);
}
.rail-header {
@@ -471,12 +471,12 @@ defineExpose({ reload: loadProjectNotes });
align-items: center;
gap: 0.3rem;
padding: 0.5rem 0.6rem;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
flex-shrink: 0;
}
.rail-title {
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
text-transform: uppercase;
letter-spacing: 0.04em;
font-size: 0.72rem;
@@ -490,7 +490,7 @@ defineExpose({ reload: loadProjectNotes });
background: transparent;
border: none;
font-size: 0.78rem;
color: var(--color-text);
color: var(--fs-text-primary);
min-width: 0;
padding: 0;
}
@@ -503,7 +503,7 @@ defineExpose({ reload: loadProjectNotes });
.rail-state {
padding: 1rem 0.65rem;
font-size: 0.78rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
/* Note list */
@@ -519,16 +519,16 @@ defineExpose({ reload: loadProjectNotes });
display: flex;
flex-direction: column;
padding: 0.4rem 0.6rem;
border-bottom: 1px solid color-mix(in srgb, var(--color-border) 60%, transparent);
border-bottom: 1px solid color-mix(in srgb, var(--fs-border-color) 60%, transparent);
cursor: pointer;
gap: 0.15rem;
border-right: 2px solid transparent;
transition: background 0.12s;
}
.note-row:hover { background: color-mix(in srgb, var(--color-primary) 5%, var(--color-surface)); }
.note-row:hover { background: color-mix(in srgb, var(--fs-accent) 5%, var(--fs-surface-hover)); }
.note-row.active {
background: color-mix(in srgb, var(--color-primary) 8%, var(--color-surface));
border-right-color: var(--color-primary);
background: color-mix(in srgb, var(--fs-accent) 8%, var(--fs-surface-hover));
border-right-color: var(--fs-accent);
}
.note-row-main {
@@ -544,12 +544,12 @@ defineExpose({ reload: loadProjectNotes });
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: var(--color-text);
color: var(--fs-text-primary);
}
.note-row-age {
font-size: 0.62rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
white-space: nowrap;
flex-shrink: 0;
}
@@ -562,8 +562,8 @@ defineExpose({ reload: loadProjectNotes });
.note-tag-pill {
font-size: 0.58rem;
color: var(--color-primary);
background: color-mix(in srgb, var(--color-primary) 10%, transparent);
color: var(--fs-accent);
background: color-mix(in srgb, var(--fs-accent) 10%, transparent);
border-radius: 999px;
padding: 0 0.3rem;
white-space: nowrap;
@@ -572,13 +572,13 @@ defineExpose({ reload: loadProjectNotes });
max-width: 5rem;
}
.note-tag-pill.tag-match {
background: color-mix(in srgb, var(--color-primary) 22%, transparent);
outline: 1px solid var(--color-primary);
background: color-mix(in srgb, var(--fs-accent) 22%, transparent);
outline: 1px solid var(--fs-accent);
}
.note-tag-more {
font-size: 0.58rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
white-space: nowrap;
}
@@ -606,8 +606,8 @@ defineExpose({ reload: loadProjectNotes });
margin-left: auto;
}
.unsaved { font-size: 0.72rem; color: var(--color-text-muted); }
.saving-txt { font-size: 0.72rem; color: var(--color-primary); }
.unsaved { font-size: 0.72rem; color: var(--fs-text-tertiary); }
.saving-txt { font-size: 0.72rem; color: var(--fs-accent); }
/* Moss action-primary per Hybrid */
@@ -618,14 +618,14 @@ defineExpose({ reload: loadProjectNotes });
font-size: 1.4rem;
font-weight: 500;
line-height: 1.25;
color: var(--color-text);
color: var(--fs-text-primary);
padding: 0;
font-family: 'Fraunces', serif;
letter-spacing: -0.01em;
}
.note-title-input:focus { outline: none; }
.note-title-input::placeholder {
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.tag-row {
@@ -645,25 +645,25 @@ defineExpose({ reload: loadProjectNotes });
align-items: center;
gap: 0.3rem;
padding: 0.35rem 0.6rem;
background: color-mix(in srgb, var(--color-primary) 5%, var(--color-surface));
background: color-mix(in srgb, var(--fs-accent) 5%, var(--fs-surface-hover));
flex-shrink: 0;
}
.tag-suggestions-label { font-size: 0.72rem; color: var(--color-text-muted); flex-shrink: 0; }
.tag-suggestions-label { font-size: 0.72rem; color: var(--fs-text-tertiary); flex-shrink: 0; }
.btn-tag-suggestion {
background: none;
border: 1px solid var(--color-border);
border: 1px solid var(--fs-border-color);
border-radius: 999px;
padding: 0.15rem 0.55rem;
font-size: 0.75rem;
color: var(--color-text);
color: var(--fs-text-primary);
cursor: pointer;
}
.btn-tag-suggestion:hover { border-color: var(--color-primary); color: var(--color-primary); }
.btn-tag-suggestion:hover { border-color: var(--fs-accent); color: var(--fs-accent); }
.btn-tag-suggestion.applied {
background: color-mix(in srgb, var(--color-primary) 15%, transparent);
border-color: var(--color-primary);
color: var(--color-primary);
background: color-mix(in srgb, var(--fs-accent) 15%, transparent);
border-color: var(--fs-accent);
color: var(--fs-accent);
}
@@ -673,12 +673,12 @@ defineExpose({ reload: loadProjectNotes });
flex-wrap: wrap;
gap: 0.25rem;
padding: 0.3rem 0.6rem;
background: color-mix(in srgb, var(--color-primary) 5%, var(--color-surface));
background: color-mix(in srgb, var(--fs-accent) 5%, var(--fs-surface-hover));
flex-shrink: 0;
}
.link-suggest-label {
font-size: 0.7rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
flex-shrink: 0;
font-weight: 500;
text-transform: uppercase;
@@ -688,15 +688,15 @@ defineExpose({ reload: loadProjectNotes });
.btn-chip-link {
background: none;
border: 1px solid var(--color-primary);
border: 1px solid var(--fs-accent);
border-radius: 999px;
padding: 0.1rem 0.45rem;
font-size: 0.7rem;
color: var(--color-primary);
color: var(--fs-accent);
cursor: pointer;
font-family: monospace;
white-space: nowrap;
}
.btn-chip-link:hover { background: color-mix(in srgb, var(--color-primary) 15%, transparent); }
.btn-chip-link:hover { background: color-mix(in srgb, var(--fs-accent) 15%, transparent); }
</style>
+48 -48
View File
@@ -344,8 +344,8 @@ defineExpose({ reload: loadAll });
flex-direction: column;
height: 100%;
overflow: hidden;
background: var(--color-surface);
border-right: 1px solid var(--color-border);
background: var(--fs-surface-hover);
border-right: 1px solid var(--fs-border-color);
}
/* ── List view ── */
@@ -360,17 +360,17 @@ defineExpose({ reload: loadAll });
flex: 0 0 44%;
}
.task-active {
background: color-mix(in srgb, var(--color-primary) 6%, var(--color-surface)) !important;
background: color-mix(in srgb, var(--fs-accent) 6%, var(--fs-surface-hover)) !important;
}
.panel-header {
padding: 0.6rem 0.75rem;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
flex-shrink: 0;
}
.panel-title {
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
text-transform: uppercase;
letter-spacing: 0.04em;
font-size: 0.75rem;
@@ -381,20 +381,20 @@ defineExpose({ reload: loadAll });
display: flex;
gap: 0.4rem;
padding: 0.45rem 0.6rem;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
flex-shrink: 0;
}
.task-add-input {
flex: 1;
background: var(--color-input-bg);
border: 1px solid var(--color-border);
background: var(--fs-surface-page);
border: 1px solid var(--fs-border-color);
border-radius: 5px;
padding: 0.28rem 0.5rem;
font-size: 0.83rem;
color: var(--color-text);
color: var(--fs-text-primary);
}
.task-add-input:focus { outline: none; border-color: var(--color-primary); }
.task-add-input:focus { outline: none; border-color: var(--fs-accent); }
.btn-add { font-size: 1rem; } /* a '+' glyph, not a label */
@@ -404,7 +404,7 @@ defineExpose({ reload: loadAll });
}
.ms-group {
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
}
.ms-group-header {
@@ -413,18 +413,18 @@ defineExpose({ reload: loadAll });
gap: 0.4rem;
width: 100%;
padding: 0.4rem 0.65rem;
background: var(--color-surface-raised);
background: var(--fs-surface-raised);
border: none;
cursor: pointer;
text-align: left;
font-size: 0.8rem;
color: var(--color-text);
color: var(--fs-text-primary);
}
.ms-group-header:hover { background: color-mix(in srgb, var(--color-primary) 8%, var(--color-surface)); }
.ms-group-header:hover { background: color-mix(in srgb, var(--fs-accent) 8%, var(--fs-surface-hover)); }
.ms-chevron { font-size: 0.6rem; color: var(--color-text-muted); width: 0.8rem; }
.ms-chevron { font-size: 0.6rem; color: var(--fs-text-tertiary); width: 0.8rem; }
.ms-name { flex: 1; font-weight: 500; font-size: 0.8rem; }
.ms-count { font-size: 0.72rem; color: var(--color-text-muted); background: var(--color-bg); border-radius: 10px; padding: 0 0.4rem; }
.ms-count { font-size: 0.72rem; color: var(--fs-text-tertiary); background: var(--fs-surface-page); border-radius: 10px; padding: 0 0.4rem; }
.ms-status {
font-size: 0.68rem;
@@ -432,8 +432,8 @@ defineExpose({ reload: loadAll });
border-radius: 10px;
text-transform: capitalize;
}
.ms-status-active { background: color-mix(in srgb, var(--color-primary) 15%, transparent); color: var(--color-primary); }
.ms-status-completed { background: color-mix(in srgb, var(--color-success) 15%, transparent); color: var(--color-success); }
.ms-status-active { background: color-mix(in srgb, var(--fs-accent) 15%, transparent); color: var(--fs-accent); }
.ms-status-completed { background: color-mix(in srgb, var(--fs-success) 15%, transparent); color: var(--fs-success); }
.task-items {
list-style: none;
@@ -447,9 +447,9 @@ defineExpose({ reload: loadAll });
gap: 0.4rem;
padding: 0.35rem 0.65rem 0.35rem 1.4rem;
cursor: pointer;
border-bottom: 1px solid color-mix(in srgb, var(--color-border) 50%, transparent);
border-bottom: 1px solid color-mix(in srgb, var(--fs-border-color) 50%, transparent);
}
.task-row:hover { background: color-mix(in srgb, var(--color-primary) 5%, var(--color-surface)); }
.task-row:hover { background: color-mix(in srgb, var(--fs-accent) 5%, var(--fs-surface-hover)); }
.task-row:last-child { border-bottom: none; }
.status-dot {
@@ -457,7 +457,7 @@ defineExpose({ reload: loadAll });
width: 1.35rem;
height: 1.35rem;
border-radius: 50%;
border: 1.5px solid var(--color-border);
border: 1.5px solid var(--fs-border-color);
background: none;
cursor: pointer;
font-size: 0.62rem;
@@ -465,8 +465,8 @@ defineExpose({ reload: loadAll });
align-items: center;
justify-content: center;
}
.status-dot.status-in_progress { border-color: var(--color-primary); color: var(--color-primary); }
.status-dot.status-done { border-color: var(--color-success); color: var(--color-success); }
.status-dot.status-in_progress { border-color: var(--fs-accent); color: var(--fs-accent); }
.status-dot.status-done { border-color: var(--fs-success); color: var(--fs-success); }
.task-title {
flex: 1;
@@ -474,20 +474,20 @@ defineExpose({ reload: loadAll });
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: var(--color-text);
color: var(--fs-text-primary);
}
.task-title.done { text-decoration: line-through; color: var(--color-text-muted); }
.task-title.done { text-decoration: line-through; color: var(--fs-text-tertiary); }
.task-age {
font-size: 0.68rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
white-space: nowrap;
flex-shrink: 0;
}
.empty-group { padding: 0.4rem 1.4rem; font-size: 0.78rem; color: var(--color-text-muted); }
.empty-group { padding: 0.4rem 1.4rem; font-size: 0.78rem; color: var(--fs-text-tertiary); }
.state-msg { padding: 1.5rem; text-align: center; font-size: 0.85rem; color: var(--color-text-muted); }
.state-msg { padding: 1.5rem; text-align: center; font-size: 0.85rem; color: var(--fs-text-tertiary); }
/* ── Detail pane (bottom split) ── */
.task-detail {
@@ -496,8 +496,8 @@ defineExpose({ reload: loadAll });
display: flex;
flex-direction: column;
overflow: hidden;
background: var(--color-surface);
border-top: 2px solid var(--color-border);
background: var(--fs-surface-hover);
border-top: 2px solid var(--fs-border-color);
}
.detail-header {
@@ -505,7 +505,7 @@ defineExpose({ reload: loadAll });
align-items: center;
gap: 0.6rem;
padding: 0.6rem 0.75rem;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
flex-shrink: 0;
}
@@ -515,21 +515,21 @@ defineExpose({ reload: loadAll });
font-size: 0.75rem;
font-weight: 500;
cursor: pointer;
border: 1.5px solid var(--color-border);
border: 1.5px solid var(--fs-border-color);
background: none;
text-transform: capitalize;
user-select: none;
margin-left: auto;
}
.status-badge.status-in_progress { border-color: var(--color-primary); color: var(--color-primary); background: color-mix(in srgb, var(--color-primary) 10%, transparent); }
.status-badge.status-done { border-color: var(--color-success); color: var(--color-success); background: color-mix(in srgb, var(--color-success) 10%, transparent); }
.status-badge.status-in_progress { border-color: var(--fs-accent); color: var(--fs-accent); background: color-mix(in srgb, var(--fs-accent) 10%, transparent); }
.status-badge.status-done { border-color: var(--fs-success); color: var(--fs-success); background: color-mix(in srgb, var(--fs-success) 10%, transparent); }
.btn-edit-task { margin-left: 0.25rem; }
.btn-edit-task:hover { text-decoration: underline; }
.detail-body {
padding: 0.5rem 0.75rem 0.5rem;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
flex-shrink: 0;
max-height: 40%;
overflow-y: auto;
@@ -537,17 +537,17 @@ defineExpose({ reload: loadAll });
.body-loading {
font-size: 0.8rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.detail-body .prose {
font-size: 0.83rem;
line-height: 1.5;
color: var(--color-text);
color: var(--fs-text-primary);
}
.btn-delete-task { margin-left: 0.25rem; }
.btn-delete-task:hover { color: var(--color-action-destructive); }
.btn-delete-task:hover { color: var(--fs-action-destructive); }
.btn-delete-confirm { margin-left: 0.25rem; }
@@ -563,9 +563,9 @@ defineExpose({ reload: loadAll });
font-size: 0.72rem;
padding: 0.15rem 0.5rem;
border-radius: 10px;
background: var(--color-bg);
border: 1px solid var(--color-border);
color: var(--color-text-muted);
background: var(--fs-surface-page);
border: 1px solid var(--fs-border-color);
color: var(--fs-text-tertiary);
text-transform: capitalize;
}
@@ -573,20 +573,20 @@ defineExpose({ reload: loadAll });
font-size: 0.72rem;
padding: 0.15rem 0.4rem;
border-radius: 10px;
background: var(--color-bg);
border: 1px solid var(--color-border);
color: var(--color-text-muted);
background: var(--fs-surface-page);
border: 1px solid var(--fs-border-color);
color: var(--fs-text-tertiary);
cursor: pointer;
max-width: 140px;
}
.milestone-select:disabled { opacity: 0.5; cursor: default; }
.milestone-select:focus { outline: none; border-color: var(--color-primary); }
.milestone-select:focus { outline: none; border-color: var(--fs-accent); }
.detail-log {
flex: 1;
overflow-y: auto;
padding: 0 0.6rem 0.6rem;
border-top: 1px solid var(--color-border);
border-top: 1px solid var(--fs-border-color);
}
/* Detail fade transition */
@@ -609,12 +609,12 @@ defineExpose({ reload: loadAll });
/* Due date on task rows */
.task-due {
font-size: 0.65rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
white-space: nowrap;
flex-shrink: 0;
}
.task-due.overdue {
color: var(--color-danger);
color: var(--fs-error);
font-weight: 500;
}
@@ -46,7 +46,7 @@ watch(() => props.projectId, load);
<style scoped>
.plan-rules {
margin-top: 1.5rem;
border-top: 1px solid var(--color-border);
border-top: 1px solid var(--fs-border-color);
padding-top: 1rem;
}
.plan-rules h3 {
@@ -66,7 +66,7 @@ watch(() => props.projectId, load);
}
.plan-rules ul {
list-style: none; padding-left: 0.75rem; margin: 0.25rem 0;
border-left: 2px solid var(--color-primary);
border-left: 2px solid var(--fs-accent);
}
.plan-rules li { margin: 0.35rem 0; font-size: 0.92em; }
.truncated { opacity: 0.7; font-style: italic; font-size: 0.85em; }
@@ -329,7 +329,7 @@ h3 {
.chips { display: flex; gap: 0.5rem; flex-wrap: wrap; align-items: center; }
.chip {
display: inline-flex; align-items: center; gap: 0.25rem;
background: var(--color-primary-bg);
background: var(--fs-accent-soft);
padding: 0.25rem 0.5rem; border-radius: 999px;
}
.chip a { cursor: pointer; }
@@ -337,13 +337,13 @@ h3 {
.chip-remove:hover { opacity: 1; }
.add {
background: none;
border: 1px dashed var(--color-border);
border: 1px dashed var(--fs-border-color);
padding: 0.25rem 0.75rem; border-radius: 999px; cursor: pointer;
color: inherit;
}
select {
background: var(--color-bg); color: inherit;
border: 1px solid var(--color-border); border-radius: 6px;
background: var(--fs-surface-page); color: inherit;
border: 1px solid var(--fs-border-color); border-radius: 6px;
padding: 0.25rem 0.5rem;
}
.applicable { margin-top: 2rem; }
@@ -359,7 +359,7 @@ select {
}
ul { list-style: none; padding: 0; margin: 0; }
.rule {
border-left: 2px solid var(--color-primary);
border-left: 2px solid var(--fs-accent);
padding-left: 0.75rem; margin: 0.5rem 0;
}
.rule-head { cursor: pointer; }
@@ -367,12 +367,12 @@ ul { list-style: none; padding: 0; margin: 0; }
.rule-statement { display: block; opacity: 0.85; margin-top: 0.25rem; }
.rule-detail {
margin-top: 0.5rem; padding: 0.5rem;
background: var(--color-bg); border-radius: 6px;
background: var(--fs-surface-page); border-radius: 6px;
}
.rule-detail > div { margin-bottom: 0.5rem; }
.edit-link {
background: none; border: none; cursor: pointer;
color: var(--color-primary); padding: 0.5rem 0 0 0;
color: var(--fs-accent); padding: 0.5rem 0 0 0;
}
.empty, .truncated { opacity: 0.7; font-style: italic; }
.empty a { cursor: pointer; text-decoration: underline; }
@@ -381,18 +381,18 @@ ul { list-style: none; padding: 0; margin: 0; }
.new-rule-form {
display: flex; flex-direction: column; gap: 0.5rem;
padding: 0.75rem; margin: 0.5rem 0;
background: var(--color-bg);
border: 1px solid var(--color-border); border-radius: 6px;
background: var(--fs-surface-page);
border: 1px solid var(--fs-border-color); border-radius: 6px;
}
.new-rule-form input, .new-rule-form textarea {
background: var(--color-surface); color: inherit;
border: 1px solid var(--color-border); border-radius: 6px;
background: var(--fs-surface-hover); color: inherit;
border: 1px solid var(--fs-border-color); border-radius: 6px;
padding: 0.5rem; font: inherit; resize: vertical;
}
.rule-list { margin-top: 0.5rem; }
.delete-link {
background: none; border: none; cursor: pointer;
color: var(--color-destructive); padding: 0.5rem 0 0 0;
color: var(--fs-destructive); padding: 0.5rem 0 0 0;
}
/* Per-rule / per-topic suppress affordance — quiet by default, reveal on hover */
.topic-group h5 {
@@ -404,14 +404,14 @@ ul { list-style: none; padding: 0; margin: 0; }
.rule-head-text { flex: 1; cursor: pointer; }
.skip-btn {
background: none; border: none; cursor: pointer;
color: var(--color-muted); font-size: 0.75rem;
color: var(--fs-text-tertiary); font-size: 0.75rem;
padding: 0.1rem 0.4rem; opacity: 0; transition: opacity 0.15s;
white-space: nowrap;
}
.topic-group h5:hover .skip-btn,
.rule:hover .skip-btn,
.skip-btn:focus { opacity: 1; }
.skip-btn:hover { color: var(--color-destructive); }
.skip-btn:hover { color: var(--fs-destructive); }
/* Suppressed section */
.suppressed { margin-top: 1.5rem; }
.suppressed-toggle {
@@ -430,13 +430,13 @@ ul { list-style: none; padding: 0; margin: 0; }
.suppressed-kind {
font-size: 0.7em; text-transform: uppercase; letter-spacing: 0.05em;
padding: 0.1rem 0.4rem; border-radius: 3px;
background: var(--color-bg);
border: 1px solid var(--color-border);
background: var(--fs-surface-page);
border: 1px solid var(--fs-border-color);
}
.suppressed-path { flex: 1; }
.reenable-btn {
background: none; border: none; cursor: pointer;
color: var(--color-primary); font-size: 0.85em;
color: var(--fs-accent); font-size: 0.85em;
}
.reenable-btn:hover { text-decoration: underline; }
</style>
@@ -98,8 +98,8 @@ watch(() => props.ruleId, load);
.slide-over {
position: fixed; top: 0; right: 0; bottom: 0;
width: min(520px, 90vw);
background: var(--color-surface);
border-left: 2px solid var(--color-primary);
background: var(--fs-surface-hover);
border-left: 2px solid var(--fs-accent);
padding: 1.5rem;
overflow-y: auto;
box-shadow: -8px 0 32px rgba(0, 0, 0, 0.3);
@@ -110,11 +110,11 @@ header h2 {
font-family: Fraunces, serif; font-style: italic;
}
label { display: block; margin-bottom: 1rem; }
.required { color: var(--color-primary); }
.required { color: var(--fs-accent); }
input, textarea {
width: 100%; margin-top: 0.25rem;
background: var(--color-bg); color: inherit;
border: 1px solid var(--color-border); border-radius: 6px;
background: var(--fs-surface-page); color: inherit;
border: 1px solid var(--fs-border-color); border-radius: 6px;
padding: 0.5rem; font: inherit;
font-family: inherit;
}
@@ -22,18 +22,18 @@ const emit = defineEmits<{
</template>
<style scoped>
.pane { background: var(--color-surface); padding: 1rem; overflow-y: auto; }
.pane { background: var(--fs-surface-hover); padding: 1rem; overflow-y: auto; }
header h2 { font-family: Fraunces, serif; font-style: italic; margin: 0 0 0.5rem 0; }
ul { list-style: none; padding: 0; margin: 1rem 0; }
li {
padding: 0.75rem;
cursor: pointer;
border-radius: 6px;
border-left: 2px solid var(--color-primary);
border-left: 2px solid var(--fs-accent);
margin-bottom: 0.5rem;
background: rgba(255, 255, 255, 0.02);
}
li:hover { background: var(--color-hover); }
li:hover { background: var(--fs-surface-hover); }
.title { font-family: Fraunces, serif; font-style: italic; font-size: 1.05em; }
.statement { font-size: 0.9em; opacity: 0.8; margin-top: 0.25rem; }
.new-rule { cursor: pointer; }
@@ -122,7 +122,7 @@ watch(() => props.rulebookId, () => {/* re-render of isSubscribed from existing
</template>
<style scoped>
.pane { background: var(--color-surface); padding: 1rem; overflow-y: auto; }
.pane { background: var(--fs-surface-hover); padding: 1rem; overflow-y: auto; }
header { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
header h2 { font-family: Fraunces, serif; font-style: italic; margin: 0 0 0.5rem 0; }
.always-on-toggle {
@@ -133,8 +133,8 @@ header h2 { font-family: Fraunces, serif; font-style: italic; margin: 0 0 0.5rem
.always-on-toggle input { cursor: pointer; }
ul { list-style: none; padding: 0; margin: 1rem 0; }
li { padding: 0.5rem; cursor: pointer; border-radius: 6px; }
li.active { background: var(--color-primary-bg); }
li:hover { background: var(--color-hover); }
li.active { background: var(--fs-accent-soft); }
li:hover { background: var(--fs-surface-hover); }
/* `.new-topic` and `.sub-list` are deliberately bare (#2444). The first wraps a
button-or-form whose children style themselves; the second is a `<ul>`, and
the bare `ul` rule above already gives it list-style, padding and margin —
@@ -142,14 +142,14 @@ li:hover { background: var(--color-hover); }
selector. Both namespace descendant rules and assume nothing about layout. */
.new-topic input {
width: 100%; margin-bottom: 0.5rem;
background: var(--color-bg); color: inherit;
border: 1px solid var(--color-border); border-radius: 6px;
background: var(--fs-surface-page); color: inherit;
border: 1px solid var(--fs-border-color); border-radius: 6px;
padding: 0.5rem;
}
.form-buttons { display: flex; gap: 0.5rem; }
.subscriptions {
margin-top: 2rem;
border-top: 1px solid var(--color-border);
border-top: 1px solid var(--fs-border-color);
padding-top: 1rem;
}
.subscriptions h3 { font-size: 0.9em; opacity: 0.7; text-transform: uppercase; letter-spacing: 0.05em; }
@@ -48,27 +48,27 @@ async function submitNew() {
</template>
<style scoped>
.pane { background: var(--color-surface); padding: 1rem; overflow-y: auto; }
.pane { background: var(--fs-surface-hover); padding: 1rem; overflow-y: auto; }
header h2 { font-family: Fraunces, serif; font-style: italic; margin: 0 0 0.5rem 0; }
ul { list-style: none; padding: 0; margin: 1rem 0; }
li { padding: 0.5rem; cursor: pointer; border-radius: 6px; display: flex; align-items: center; gap: 0.5rem; }
li.active { background: var(--color-primary-bg); }
li:hover { background: var(--color-hover); }
li.active { background: var(--fs-accent-soft); }
li:hover { background: var(--fs-surface-hover); }
.always-on-badge {
font-size: 0.7rem;
text-transform: uppercase;
letter-spacing: 0.05em;
padding: 0.1rem 0.4rem;
border-radius: 3px;
background: var(--color-accent);
color: var(--color-accent-fg);
background: var(--fs-accent);
color: var(--fs-text-on-action);
margin-left: auto;
}
.new-rulebook { margin-top: 1rem; }
.new-rulebook input {
width: 100%; margin-bottom: 0.5rem;
background: var(--color-bg); color: inherit;
border: 1px solid var(--color-border); border-radius: 6px;
background: var(--fs-surface-page); color: inherit;
border: 1px solid var(--fs-border-color); border-radius: 6px;
padding: 0.5rem;
}
.form-buttons { display: flex; gap: 0.5rem; }
+3 -3
View File
@@ -1,10 +1,10 @@
/** Cyclic color palette for milestone progress bars. */
export const MILESTONE_PALETTE = [
'var(--color-primary)',
'var(--color-success, #22c55e)',
'var(--fs-accent)',
'var(--fs-success, #22c55e)',
'#c98a00',
'#8b5cf6',
'var(--color-danger, #ef4444)',
'var(--fs-error, #ef4444)',
'#06b6d4',
]
+38 -38
View File
@@ -79,7 +79,7 @@ onMounted(async () => {
<article v-for="p in data.active_projects" :key="p.id" class="proj-panel">
<header class="proj-head">
<span class="proj-dot" :style="{ background: p.color || 'var(--color-primary)' }" />
<span class="proj-dot" :style="{ background: p.color || 'var(--fs-accent)' }" />
<router-link :to="`/projects/${p.id}`" class="proj-title">{{ p.title }}</router-link>
<span class="proj-meta">{{ relativeTime(p.last_activity) }} · {{ p.open_count }} open</span>
</header>
@@ -156,7 +156,7 @@ onMounted(async () => {
:to="`/projects/${p.id}`"
class="pstat-row"
>
<span class="pstat-dot" :style="{ background: p.color || 'var(--color-primary)' }" />
<span class="pstat-dot" :style="{ background: p.color || 'var(--fs-accent)' }" />
<span class="pstat-title">{{ p.title }}</span>
<span class="pstat-counts">{{ p.open_count }} open · {{ p.done_count }} done</span>
</router-link>
@@ -180,68 +180,68 @@ onMounted(async () => {
all the spacing between them (h1 zeroed, .dash-sub margined). Nothing in it
assumes a flex parent, which is the tell for a deleted rule (#2444). */
.dash-head h1 { margin: 0; font-family: 'Fraunces', Georgia, serif; }
.dash-sub { margin: 0.2rem 0 1.25rem; color: var(--color-muted); font-size: 0.9rem; }
.dash-label { display: block; font-size: 0.72rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--color-muted); margin-bottom: 0.6rem; }
.dash-empty { color: var(--color-muted); padding: 1rem 0; }
.dash-empty.card { padding: 1rem; border: 1px dashed var(--color-border); border-radius: 10px; }
.dash-sub { margin: 0.2rem 0 1.25rem; color: var(--fs-text-tertiary); font-size: 0.9rem; }
.dash-label { display: block; font-size: 0.72rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--fs-text-tertiary); margin-bottom: 0.6rem; }
.dash-empty { color: var(--fs-text-tertiary); padding: 1rem 0; }
.dash-empty.card { padding: 1rem; border: 1px dashed var(--fs-border-color); border-radius: 10px; }
.done-recent { margin-bottom: 1.5rem; }
.done-row { display: flex; align-items: center; gap: 0.5rem; padding: 0.35rem 0.55rem; border-radius: 7px; text-decoration: none; color: var(--color-text); font-size: 0.86rem; }
.done-row:hover { background: var(--color-hover); }
.done-mark { color: var(--color-primary); flex-shrink: 0; }
.done-row { display: flex; align-items: center; gap: 0.5rem; padding: 0.35rem 0.55rem; border-radius: 7px; text-decoration: none; color: var(--fs-text-primary); font-size: 0.86rem; }
.done-row:hover { background: var(--fs-surface-hover); }
.done-mark { color: var(--fs-accent); flex-shrink: 0; }
.done-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.done-meta { font-size: 0.72rem; color: var(--color-muted); white-space: nowrap; flex-shrink: 0; }
.done-more { background: none; border: none; cursor: pointer; margin-top: 0.25rem; padding: 0.2rem 0.55rem; font-size: 0.78rem; color: var(--color-primary); font-family: inherit; }
.done-meta { font-size: 0.72rem; color: var(--fs-text-tertiary); white-space: nowrap; flex-shrink: 0; }
.done-more { background: none; border: none; cursor: pointer; margin-top: 0.25rem; padding: 0.2rem 0.55rem; font-size: 0.78rem; color: var(--fs-accent); font-family: inherit; }
.done-more:hover { text-decoration: underline; }
.dash-cols { display: flex; gap: 1.25rem; align-items: flex-start; }
.dash-main { flex: 1.7; min-width: 0; }
.dash-rail { flex: 1; min-width: 240px; }
.proj-panel { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: 12px; padding: 0.9rem 1rem; margin-bottom: 0.9rem; }
.proj-panel { background: var(--fs-surface-hover); border: 1px solid var(--fs-border-color); border-radius: 12px; padding: 0.9rem 1rem; margin-bottom: 0.9rem; }
.proj-head { display: flex; align-items: center; gap: 0.5rem; }
.proj-dot { width: 9px; height: 9px; border-radius: 50%; flex-shrink: 0; }
.proj-title { font-weight: 700; color: var(--color-text); text-decoration: none; }
.proj-title:hover { color: var(--color-primary); }
.proj-meta { margin-left: auto; font-size: 0.74rem; color: var(--color-muted); }
.bar { height: 5px; background: var(--color-border); border-radius: 3px; margin: 0.55rem 0 0.2rem; }
.bar-fill { height: 5px; background: var(--color-primary); border-radius: 3px; }
.proj-title { font-weight: 700; color: var(--fs-text-primary); text-decoration: none; }
.proj-title:hover { color: var(--fs-accent); }
.proj-meta { margin-left: auto; font-size: 0.74rem; color: var(--fs-text-tertiary); }
.bar { height: 5px; background: var(--fs-border-color); border-radius: 3px; margin: 0.55rem 0 0.2rem; }
.bar-fill { height: 5px; background: var(--fs-accent); border-radius: 3px; }
.ms-block { margin-top: 0.7rem; }
.ms-head { display: flex; align-items: baseline; gap: 0.5rem; margin-bottom: 0.3rem; }
.ms-title { font-size: 0.82rem; font-weight: 600; color: var(--color-text); }
.ms-title.ms-none { color: var(--color-muted); font-weight: 500; }
.ms-pct { margin-left: auto; font-size: 0.72rem; color: var(--color-muted); }
.ms-title { font-size: 0.82rem; font-weight: 600; color: var(--fs-text-primary); }
.ms-title.ms-none { color: var(--fs-text-tertiary); font-weight: 500; }
.ms-pct { margin-left: auto; font-size: 0.72rem; color: var(--fs-text-tertiary); }
.task-row { display: flex; align-items: center; gap: 0.5rem; padding: 0.4rem 0.55rem; border-radius: 7px; text-decoration: none; color: var(--color-text); font-size: 0.86rem; }
.task-row:hover { background: var(--color-hover); }
.task-inprogress { border-left: 3px solid var(--color-primary); padding-left: calc(0.55rem - 3px); }
.task-mark { color: var(--color-muted); }
.task-row { display: flex; align-items: center; gap: 0.5rem; padding: 0.4rem 0.55rem; border-radius: 7px; text-decoration: none; color: var(--fs-text-primary); font-size: 0.86rem; }
.task-row:hover { background: var(--fs-surface-hover); }
.task-inprogress { border-left: 3px solid var(--fs-accent); padding-left: calc(0.55rem - 3px); }
.task-mark { color: var(--fs-text-tertiary); }
.task-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.task-pri { font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.04em; padding: 1px 6px; border-radius: 8px; border: 1px solid var(--color-border); color: var(--color-muted); }
.task-pri { font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.04em; padding: 1px 6px; border-radius: 8px; border: 1px solid var(--fs-border-color); color: var(--fs-text-tertiary); }
.pri-high { color: #c0556b; border-color: #c0556b66; }
.proj-more { display: inline-block; margin-top: 0.6rem; font-size: 0.78rem; color: var(--color-primary); text-decoration: none; }
.proj-more { display: inline-block; margin-top: 0.6rem; font-size: 0.78rem; color: var(--fs-accent); text-decoration: none; }
.rail-card { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: 12px; padding: 0.7rem 0.85rem; margin-bottom: 1.25rem; }
.rail-card { background: var(--fs-surface-hover); border: 1px solid var(--fs-border-color); border-radius: 12px; padding: 0.7rem 0.85rem; margin-bottom: 1.25rem; }
.stats { display: flex; flex-direction: column; gap: 0.2rem; font-size: 0.9rem; }
.stats-sub { color: var(--color-muted); font-size: 0.78rem; }
.stats-sub { color: var(--fs-text-tertiary); font-size: 0.78rem; }
.proj-stats { display: flex; flex-direction: column; gap: 0.1rem; padding: 0.4rem 0.45rem; }
.pstat-row { display: flex; align-items: center; gap: 0.5rem; padding: 0.35rem 0.4rem; border-radius: 7px; text-decoration: none; color: var(--color-text); font-size: 0.85rem; }
.pstat-row:hover { background: var(--color-hover); }
.pstat-row { display: flex; align-items: center; gap: 0.5rem; padding: 0.35rem 0.4rem; border-radius: 7px; text-decoration: none; color: var(--fs-text-primary); font-size: 0.85rem; }
.pstat-row:hover { background: var(--fs-surface-hover); }
.pstat-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.pstat-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
.pstat-counts { font-size: 0.74rem; color: var(--color-muted); white-space: nowrap; flex-shrink: 0; }
.pstat-counts { font-size: 0.74rem; color: var(--fs-text-tertiary); white-space: nowrap; flex-shrink: 0; }
.quick-add { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.qa-btn { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: 8px; padding: 6px 12px; font-size: 0.82rem; color: var(--color-text); text-decoration: none; }
.qa-btn:hover { border-color: var(--color-primary); color: var(--color-primary); }
.qa-btn { background: var(--fs-surface-hover); border: 1px solid var(--fs-border-color); border-radius: 8px; padding: 6px 12px; font-size: 0.82rem; color: var(--fs-text-primary); text-decoration: none; }
.qa-btn:hover { border-color: var(--fs-accent); color: var(--fs-accent); }
.issues-card { display: flex; flex-direction: column; gap: 0.1rem; padding: 0.4rem 0.45rem; }
.issue-row { display: flex; align-items: center; gap: 0.5rem; padding: 0.35rem 0.4rem; border-radius: 7px; text-decoration: none; color: var(--color-text); font-size: 0.85rem; }
.issue-row:hover { background: var(--color-hover); }
.issue-mark { color: var(--color-muted); flex-shrink: 0; }
.issue-mark.imk-in_progress { color: var(--color-primary); }
.issue-row { display: flex; align-items: center; gap: 0.5rem; padding: 0.35rem 0.4rem; border-radius: 7px; text-decoration: none; color: var(--fs-text-primary); font-size: 0.85rem; }
.issue-row:hover { background: var(--fs-surface-hover); }
.issue-mark { color: var(--fs-text-tertiary); flex-shrink: 0; }
.issue-mark.imk-in_progress { color: var(--fs-accent); }
.issue-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.issue-meta { font-size: 0.72rem; color: var(--color-muted); white-space: nowrap; flex-shrink: 0; }
.issue-meta { font-size: 0.72rem; color: var(--fs-text-tertiary); white-space: nowrap; flex-shrink: 0; }
@media (max-width: 760px) { .dash-cols { flex-direction: column; } }
</style>
+55 -55
View File
@@ -1115,7 +1115,7 @@ function isSelfContainedColour(value: string): boolean {
}
.lede {
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
max-width: 70ch;
line-height: 1.6;
margin: 0 0 1.5rem;
@@ -1137,9 +1137,9 @@ function isSelfContainedColour(value: string): boolean {
/* Sidebar ---------------------------------------------------------------- */
.ds-sidebar {
background: var(--color-bg-card);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-lg);
padding: 1rem;
}
@@ -1156,7 +1156,7 @@ function isSelfContainedColour(value: string): boolean {
font-size: 0.75rem;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.system-list {
@@ -1173,22 +1173,22 @@ function isSelfContainedColour(value: string): boolean {
text-align: left;
background: none;
border: 1px solid transparent;
border-radius: var(--radius-sm);
border-radius: var(--fs-radius-sm);
padding: 0.5rem 0.6rem;
cursor: pointer;
color: var(--color-text);
color: var(--fs-text-primary);
display: flex;
flex-direction: column;
gap: 0.15rem;
}
.system-btn:hover {
background: var(--color-bg-secondary);
background: var(--fs-surface-raised);
}
.system-btn.active {
border-color: var(--color-primary);
background: var(--color-bg-secondary);
border-color: var(--fs-accent);
background: var(--fs-surface-raised);
}
@@ -1198,7 +1198,7 @@ function isSelfContainedColour(value: string): boolean {
.system-kind {
font-size: 0.75rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
/* Sections --------------------------------------------------------------- */
@@ -1211,9 +1211,9 @@ function isSelfContainedColour(value: string): boolean {
}
.ds-section {
background: var(--color-bg-card);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-lg);
padding: 1.25rem;
}
@@ -1232,7 +1232,7 @@ function isSelfContainedColour(value: string): boolean {
.section-note,
.muted {
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
font-size: 0.85rem;
margin: 0 0 1rem;
}
@@ -1247,17 +1247,17 @@ function isSelfContainedColour(value: string): boolean {
}
.chain-link {
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
}
.chain-link.self {
color: var(--color-text);
color: var(--fs-text-primary);
font-weight: 500;
}
.chain-arrow,
.chain-note {
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
/* Fields ----------------------------------------------------------------- */
@@ -1282,24 +1282,24 @@ function isSelfContainedColour(value: string): boolean {
font-size: 0.75rem;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
margin-bottom: 0.3rem;
}
.field-hint {
margin: 0.3rem 0 0;
font-size: 0.8rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
line-height: 1.5;
}
.input {
width: 100%;
padding: 0.45rem 0.6rem;
background: var(--color-bg);
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
color: var(--color-text);
background: var(--fs-surface-page);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
color: var(--fs-text-primary);
font: inherit;
}
@@ -1328,15 +1328,15 @@ textarea.input {
.confirm-copy {
font-size: 0.85rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
max-width: 40ch;
}
/* Tokens ----------------------------------------------------------------- */
.token-form {
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
padding: 1rem;
margin-bottom: 1rem;
}
@@ -1371,7 +1371,7 @@ textarea.input {
align-items: center;
gap: 0.6rem;
padding: 0.5rem 0;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
}
.token-name {
@@ -1386,7 +1386,7 @@ textarea.input {
}
.token-meta {
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
font-size: 0.8rem;
flex: 1;
min-width: 0;
@@ -1405,18 +1405,18 @@ textarea.input {
.finding-list li {
padding: 0.6rem 0;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
}
.finding-title {
font-weight: 500;
color: var(--color-text);
color: var(--fs-text-primary);
}
.finding-line {
margin: 0.3rem 0 0;
font-size: 0.85rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
display: flex;
flex-wrap: wrap;
align-items: center;
@@ -1428,24 +1428,24 @@ textarea.input {
text-transform: uppercase;
letter-spacing: 0.06em;
padding: 0.1rem 0.45rem;
border-radius: var(--radius-sm);
border-radius: var(--fs-radius-sm);
flex: none;
}
.spec-status.violated {
background: var(--color-priority-high-bg);
color: var(--color-priority-high);
background: var(--fs-priority-high-bg);
color: var(--fs-priority-high);
}
.spec-status.missing {
background: var(--color-priority-medium-bg);
color: var(--color-priority-medium);
background: var(--fs-priority-medium-bg);
color: var(--fs-priority-medium);
}
.sheet {
background: var(--color-bg);
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
background: var(--fs-surface-page);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
padding: 0.75rem 1rem;
margin-top: 0.75rem;
overflow-x: auto;
@@ -1472,7 +1472,7 @@ textarea.input {
.supersedes {
font-size: 0.75rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
font-style: italic;
}
@@ -1484,7 +1484,7 @@ textarea.input {
}
.mode-name {
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
text-transform: uppercase;
font-size: 0.7rem;
letter-spacing: 0.06em;
@@ -1495,7 +1495,7 @@ textarea.input {
width: 0.9rem;
height: 0.9rem;
border-radius: 3px;
border: 1px solid var(--color-border);
border: 1px solid var(--fs-border-color);
flex: none;
}
@@ -1510,12 +1510,12 @@ textarea.input {
font-size: 0.7rem;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.resolved-list li {
padding: 0.5rem 0;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
}
.resolved-head {
@@ -1551,33 +1551,33 @@ textarea.input {
text-transform: uppercase;
letter-spacing: 0.06em;
padding: 0.1rem 0.45rem;
border-radius: var(--radius-sm);
background: var(--color-bg-secondary);
color: var(--color-text-muted);
border-radius: var(--fs-radius-sm);
background: var(--fs-surface-raised);
color: var(--fs-text-tertiary);
}
.origin-badge.own {
background: var(--color-primary-tint);
color: var(--color-primary);
background: var(--fs-accent-soft);
color: var(--fs-accent);
}
/* Notices ---------------------------------------------------------------- */
.notice {
background: var(--color-bg-card);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-lg);
padding: 1.25rem;
max-width: 60ch;
}
.notice-warn {
border-left: 3px solid var(--color-warning);
border-left: 3px solid var(--fs-warning);
}
.notice p {
margin: 0.5rem 0 1rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
line-height: 1.6;
}
</style>
+13 -13
View File
@@ -78,9 +78,9 @@ async function handleSubmit() {
.auth-card {
width: 100%;
max-width: 400px;
background: var(--color-bg-card);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-lg);
padding: 2rem;
}
.auth-brand {
@@ -97,7 +97,7 @@ async function handleSubmit() {
.auth-hint {
text-align: center;
font-size: 0.9rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
margin-bottom: 1rem;
}
.field {
@@ -112,25 +112,25 @@ async function handleSubmit() {
.input {
width: 100%;
padding: 0.5rem 0.75rem;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
font-size: 0.95rem;
background: var(--color-bg);
color: var(--color-text);
background: var(--fs-surface-page);
color: var(--fs-text-primary);
box-sizing: border-box;
}
.input:focus {
outline: none;
border-color: var(--color-primary);
border-color: var(--fs-accent);
}
.error-msg {
color: var(--color-danger);
color: var(--fs-error);
font-size: 0.9rem;
margin: 0 0 0.75rem;
}
.success-msg {
text-align: center;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
font-size: 0.95rem;
padding: 0.5rem 0;
}
@@ -140,10 +140,10 @@ async function handleSubmit() {
.auth-footer {
text-align: center;
font-size: 0.9rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
margin: 1rem 0 0;
}
.auth-footer a {
color: var(--color-primary);
color: var(--fs-accent);
}
</style>
+59 -59
View File
@@ -208,7 +208,7 @@ function initGraph() {
.attr("orient", "auto")
.append("path")
.attr("d", "M0,-4L8,0L0,4")
.attr("fill", "var(--color-primary)")
.attr("fill", "var(--fs-accent)")
.attr("opacity", "0.6");
// Zoom layer
@@ -237,7 +237,7 @@ function initGraph() {
.append("line")
.attr("class", "graph-edge")
.attr("stroke", (d: any) =>
d.type === "wikilink" ? "var(--color-primary)" : "var(--color-text-muted)"
d.type === "wikilink" ? "var(--fs-accent)" : "var(--fs-text-tertiary)"
)
.attr("stroke-opacity", (d: any) => (d.type === "wikilink" ? 0.5 : 0.4))
.attr("stroke-dasharray", null)
@@ -295,11 +295,11 @@ function initGraph() {
.append("circle")
.attr("r", (d: GraphNode) => d.radius ?? 8)
.attr("fill", (d: GraphNode) => {
if (d.type === "tag") return "color-mix(in srgb, var(--color-primary) 20%, transparent)";
return d.project_color ?? "var(--color-bg-secondary)";
if (d.type === "tag") return "color-mix(in srgb, var(--fs-accent) 20%, transparent)";
return d.project_color ?? "var(--fs-surface-raised)";
})
.attr("stroke", (d: GraphNode) =>
d.type === "tag" ? "var(--color-primary)" : "var(--color-border)"
d.type === "tag" ? "var(--fs-accent)" : "var(--fs-border-color)"
)
.attr("stroke-width", (d: GraphNode) => (d.type === "tag" ? 1.5 : 1.5))
.attr("stroke-dasharray", (d: GraphNode) => (d.type === "task" ? "3" : null))
@@ -317,7 +317,7 @@ function initGraph() {
.attr("dy", (d: GraphNode) => (d.radius ?? 8) + 12)
.attr("font-size", "10px")
.attr("fill", (d: GraphNode) =>
d.type === "tag" ? "var(--color-primary)" : "var(--color-text-secondary)"
d.type === "tag" ? "var(--fs-accent)" : "var(--fs-text-secondary)"
)
.attr("pointer-events", "none");
@@ -600,7 +600,7 @@ onUnmounted(() => {
.graph-page {
display: flex;
flex-direction: column;
height: calc(100vh - var(--header-height));
height: calc(100vh - var(--fs-layout-header));
overflow: hidden;
}
@@ -609,17 +609,17 @@ onUnmounted(() => {
align-items: center;
gap: 0.75rem;
padding: 0.6rem 1rem;
background: var(--color-bg-secondary);
border-bottom: 1px solid var(--color-border);
background: var(--fs-surface-raised);
border-bottom: 1px solid var(--fs-border-color);
flex-shrink: 0;
flex-wrap: wrap;
}
.graph-select {
background: var(--color-bg-card);
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
color: var(--color-text);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
color: var(--fs-text-primary);
font-size: 0.875rem;
padding: 0.3rem 0.6rem;
cursor: pointer;
@@ -631,27 +631,27 @@ onUnmounted(() => {
align-items: center;
gap: 0.35rem;
font-size: 0.875rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
cursor: pointer;
user-select: none;
}
.graph-toggle input {
cursor: pointer;
accent-color: var(--color-primary);
accent-color: var(--fs-accent);
}
.graph-stats {
margin-left: auto;
font-size: 0.8rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.graph-physics-btn {
background: var(--color-bg-card);
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
color: var(--color-text-secondary);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
color: var(--fs-text-secondary);
font-size: 0.875rem;
font-family: inherit;
padding: 0.3rem 0.7rem;
@@ -659,12 +659,12 @@ onUnmounted(() => {
transition: border-color 0.15s, color 0.15s;
}
.graph-physics-btn:hover {
border-color: var(--color-primary);
color: var(--color-text);
border-color: var(--fs-accent);
color: var(--fs-text-primary);
}
.graph-physics-btn.active {
border-color: var(--color-primary);
color: var(--color-primary);
border-color: var(--fs-accent);
color: var(--fs-accent);
}
.graph-physics-panel {
@@ -672,8 +672,8 @@ onUnmounted(() => {
flex-wrap: wrap;
gap: 0.5rem 1.5rem;
padding: 0.6rem 1rem;
background: var(--color-bg-secondary);
border-bottom: 1px solid var(--color-border);
background: var(--fs-surface-raised);
border-bottom: 1px solid var(--fs-border-color);
flex-shrink: 0;
}
@@ -688,20 +688,20 @@ onUnmounted(() => {
.knob-label {
font-size: 0.75rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
display: flex;
justify-content: space-between;
}
.knob-label em {
font-style: normal;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
font-variant-numeric: tabular-nums;
}
.physics-knob input[type="range"] {
width: 100%;
accent-color: var(--color-primary);
accent-color: var(--fs-accent);
cursor: pointer;
}
@@ -709,7 +709,7 @@ onUnmounted(() => {
flex: 1;
position: relative;
overflow: hidden;
background: var(--color-bg);
background: var(--fs-surface-page);
}
.graph-svg {
@@ -728,15 +728,15 @@ onUnmounted(() => {
}
.graph-empty p {
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
font-size: 0.95rem;
}
.spinner {
width: 28px;
height: 28px;
border: 3px solid var(--color-border);
border-top-color: var(--color-primary);
border: 3px solid var(--fs-border-color);
border-top-color: var(--fs-accent);
border-radius: 50%;
animation: spin 0.7s linear infinite;
}
@@ -747,9 +747,9 @@ onUnmounted(() => {
.graph-tooltip {
position: absolute;
background: var(--color-bg-card);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-lg);
box-shadow: 0 4px 16px var(--color-shadow);
padding: 0.5rem 0.75rem;
pointer-events: none;
@@ -760,7 +760,7 @@ onUnmounted(() => {
.tooltip-title {
font-size: 0.875rem;
font-weight: 500;
color: var(--color-text);
color: var(--fs-text-primary);
margin-bottom: 0.25rem;
}
@@ -773,15 +773,15 @@ onUnmounted(() => {
.tag-chip {
font-size: 0.7rem;
background: color-mix(in srgb, var(--color-primary) 15%, transparent);
color: var(--color-primary);
background: color-mix(in srgb, var(--fs-accent) 15%, transparent);
color: var(--fs-accent);
border-radius: 999px;
padding: 0.1rem 0.4rem;
}
.tooltip-meta {
font-size: 0.75rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
text-transform: capitalize;
}
@@ -792,8 +792,8 @@ onUnmounted(() => {
right: 0;
bottom: 0;
width: 340px;
background: var(--color-bg-card);
border-left: 1px solid var(--color-border);
background: var(--fs-surface-raised);
border-left: 1px solid var(--fs-border-color);
box-shadow: -4px 0 16px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
@@ -815,7 +815,7 @@ onUnmounted(() => {
align-items: center;
gap: 0.5rem;
padding: 0.6rem 0.75rem;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
flex-shrink: 0;
}
@@ -826,10 +826,10 @@ onUnmounted(() => {
letter-spacing: 0.05em;
padding: 0.15rem 0.45rem;
border-radius: 10px;
border: 1px solid var(--color-border);
color: var(--color-text-muted);
border: 1px solid var(--fs-border-color);
color: var(--fs-text-tertiary);
}
.peek-type-task { border-color: var(--color-primary); color: var(--color-primary); }
.peek-type-task { border-color: var(--fs-accent); color: var(--fs-accent); }
.peek-actions {
display: flex;
@@ -840,7 +840,7 @@ onUnmounted(() => {
.peek-link {
font-size: 0.78rem;
color: var(--color-primary);
color: var(--fs-accent);
text-decoration: none;
}
.peek-link:hover { text-decoration: underline; }
@@ -848,20 +848,20 @@ onUnmounted(() => {
.peek-close {
background: none;
border: none;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
font-size: 0.8rem;
cursor: pointer;
padding: 0.1rem 0.25rem;
border-radius: 3px;
}
.peek-close:hover { color: var(--color-text); }
.peek-close:hover { color: var(--fs-text-primary); }
.peek-title {
margin: 0;
padding: 0.75rem 0.75rem 0.4rem;
font-size: 1rem;
font-weight: 500;
color: var(--color-text);
color: var(--fs-text-primary);
flex-shrink: 0;
}
@@ -877,7 +877,7 @@ onUnmounted(() => {
flex: 1;
overflow-y: auto;
padding: 0 0.75rem 0.5rem;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
}
.peek-prose {
@@ -887,7 +887,7 @@ onUnmounted(() => {
.peek-loading,
.peek-empty {
font-size: 0.82rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
padding-top: 0.5rem;
}
@@ -901,7 +901,7 @@ onUnmounted(() => {
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
margin-bottom: 0.4rem;
}
@@ -921,14 +921,14 @@ onUnmounted(() => {
align-items: center;
gap: 0.4rem;
font-size: 0.82rem;
color: var(--color-text);
color: var(--fs-text-primary);
cursor: pointer;
padding: 0.25rem 0.4rem;
border-radius: 4px;
}
.peek-linked-item:hover {
background: color-mix(in srgb, var(--color-primary) 8%, var(--color-bg-card));
color: var(--color-primary);
background: color-mix(in srgb, var(--fs-accent) 8%, var(--fs-surface-raised));
color: var(--fs-accent);
}
.peek-linked-type {
@@ -937,12 +937,12 @@ onUnmounted(() => {
width: 1.1rem;
height: 1.1rem;
border-radius: 50%;
background: var(--color-bg);
border: 1px solid var(--color-border);
background: var(--fs-surface-page);
border: 1px solid var(--fs-border-color);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
</style>
+70 -70
View File
@@ -579,7 +579,7 @@ onUnmounted(() => {
.knowledge-root {
display: flex;
flex-direction: column;
height: calc(100vh - var(--header-height));
height: calc(100vh - var(--fs-layout-header));
overflow: hidden;
}
@@ -590,8 +590,8 @@ onUnmounted(() => {
justify-content: space-between;
gap: 12px;
padding: 8px 20px;
background: var(--color-bg-secondary);
border-bottom: 1px solid var(--color-border);
background: var(--fs-surface-raised);
border-bottom: 1px solid var(--fs-border-color);
flex-shrink: 0;
font-size: 0.82rem;
flex-wrap: wrap;
@@ -607,7 +607,7 @@ onUnmounted(() => {
font-size: 0.78rem;
}
.today-link {
color: var(--color-primary);
color: var(--fs-accent);
text-decoration: none;
font-weight: 500;
opacity: 0.85;
@@ -625,19 +625,19 @@ onUnmounted(() => {
/* ── Filter panel ────────────────────────────────────────── */
.filter-panel {
width: var(--sidebar-width);
width: var(--fs-layout-sidebar);
flex-shrink: 0;
padding: 16px 12px;
border-right: 1px solid var(--color-border);
border-right: 1px solid var(--fs-border-color);
overflow-y: auto;
background: var(--color-bg-secondary);
background: var(--fs-surface-raised);
}
.filter-section { margin-bottom: 20px; }
.filter-section + .filter-section::before {
content: '· · ·';
display: block;
text-align: center;
color: color-mix(in srgb, var(--color-primary) 30%, transparent);
color: color-mix(in srgb, var(--fs-accent) 30%, transparent);
font-size: 0.9rem;
letter-spacing: 0.4em;
padding: 4px 0 12px;
@@ -645,7 +645,7 @@ onUnmounted(() => {
.filter-label {
font-family: 'Fraunces', Georgia, serif;
font-size: 0.95rem;
color: var(--color-primary);
color: var(--fs-accent);
margin-bottom: 8px;
padding: 0 4px;
}
@@ -662,14 +662,14 @@ onUnmounted(() => {
padding: 8px 12px;
border-radius: 10px;
border: none;
background: var(--gradient-cta);
background: var(--fs-gradient-cta);
color: var(--fs-text-on-action);
cursor: pointer;
font-size: 0.85rem;
font-weight: 500;
transition: box-shadow 0.15s;
}
.btn-new-note:hover { box-shadow: var(--glow-cta-hover); }
.btn-new-note:hover { box-shadow: var(--fs-glow-cta-hover); }
.btn-new-icon {
font-size: 1.1rem;
line-height: 1;
@@ -680,8 +680,8 @@ onUnmounted(() => {
top: calc(100% + 6px);
left: 0;
right: 0;
background: var(--color-bg-card);
border: 1px solid var(--color-border);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: 10px;
overflow: hidden;
z-index: 50;
@@ -696,15 +696,15 @@ onUnmounted(() => {
padding: 9px 14px;
background: none;
border: none;
color: var(--color-text);
color: var(--fs-text-primary);
cursor: pointer;
font-size: 0.84rem;
text-align: left;
transition: background 0.12s, color 0.12s;
}
.new-note-menu button:hover {
background: var(--color-primary-tint);
color: var(--color-primary);
background: var(--fs-accent-soft);
color: var(--fs-accent);
}
.new-note-menu button svg {
flex-shrink: 0;
@@ -712,7 +712,7 @@ onUnmounted(() => {
}
.new-note-menu button:hover svg {
opacity: 1;
stroke: var(--color-primary);
stroke: var(--fs-accent);
}
.filter-btn {
@@ -725,7 +725,7 @@ onUnmounted(() => {
border-radius: 7px;
border: none;
background: transparent;
color: var(--color-text);
color: var(--fs-text-primary);
cursor: pointer;
font-size: 0.85rem;
margin-bottom: 2px;
@@ -734,8 +734,8 @@ onUnmounted(() => {
}
.filter-btn:hover { background: rgba(255,255,255,0.05); opacity: 1; }
.filter-btn.active {
background: var(--color-primary-wash);
color: var(--color-primary);
background: var(--fs-accent-wash);
color: var(--fs-accent);
opacity: 1;
}
.filter-btn-label { flex: 1; }
@@ -744,15 +744,15 @@ onUnmounted(() => {
padding: 1px 6px;
border-radius: 10px;
background: rgba(255,255,255,0.07);
color: var(--color-muted);
color: var(--fs-text-tertiary);
font-weight: 500;
min-width: 20px;
text-align: center;
flex-shrink: 0;
}
.filter-btn.active .filter-count {
background: color-mix(in srgb, var(--color-primary) 20%, transparent);
color: var(--color-primary);
background: color-mix(in srgb, var(--fs-accent) 20%, transparent);
color: var(--fs-accent);
}
.filter-tag { font-size: 0.78rem; }
@@ -772,7 +772,7 @@ onUnmounted(() => {
gap: 10px;
padding: 12px 20px;
flex-shrink: 0;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
}
.search-wrap {
flex: 1;
@@ -783,27 +783,27 @@ onUnmounted(() => {
left: 10px;
top: 50%;
transform: translateY(-50%);
color: var(--color-muted);
color: var(--fs-text-tertiary);
pointer-events: none;
}
.search-input {
width: 100%;
padding: 7px 12px 7px 32px;
border-radius: 8px;
border: 1px solid var(--color-border);
background: var(--color-bg-tertiary);
color: var(--color-text);
border: 1px solid var(--fs-border-color);
background: var(--fs-surface-hover);
color: var(--fs-text-primary);
font-size: 0.88rem;
outline: none;
transition: border-color 0.15s;
}
.search-input:focus { border-color: var(--color-primary); }
.search-input:focus { border-color: var(--fs-accent); }
.sort-select {
padding: 7px 10px;
border-radius: 8px;
border: 1px solid var(--color-border);
background: var(--color-bg-tertiary);
color: var(--color-text);
border: 1px solid var(--fs-border-color);
background: var(--fs-surface-hover);
color: var(--fs-text-primary);
font-size: 0.85rem;
cursor: pointer;
outline: none;
@@ -824,9 +824,9 @@ onUnmounted(() => {
.k-card {
position: relative;
background: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: var(--radius-lg);
background: var(--fs-surface-hover);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-xl);
padding: 14px;
cursor: pointer;
transition: border-color 0.15s, transform 0.12s, box-shadow 0.15s;
@@ -838,12 +838,12 @@ onUnmounted(() => {
}
.k-card:hover {
transform: translateY(-2px);
box-shadow: 0 8px 28px color-mix(in srgb, var(--color-primary) 25%, transparent), 0 2px 8px rgba(0, 0, 0, 0.3);
border-color: color-mix(in srgb, var(--color-primary) 35%, transparent);
box-shadow: 0 8px 28px color-mix(in srgb, var(--fs-accent) 25%, transparent), 0 2px 8px rgba(0, 0, 0, 0.3);
border-color: color-mix(in srgb, var(--fs-accent) 35%, transparent);
}
/* Type-specific card DNA */
.k-card--note { border-color: color-mix(in srgb, var(--color-primary) 20%, transparent); }
.k-card--note { border-color: color-mix(in srgb, var(--fs-accent) 20%, transparent); }
.k-card--task { border-color: rgba(212, 160, 23, 0.18); }
/* Top gradient bars */
@@ -858,7 +858,7 @@ onUnmounted(() => {
}
.k-card--note::before {
right: 0;
background: linear-gradient(90deg, var(--color-primary), #7A6DA8);
background: linear-gradient(90deg, var(--fs-accent), #7A6DA8);
}
.k-card--task::before {
right: 0;
@@ -877,7 +877,7 @@ onUnmounted(() => {
text-transform: uppercase;
letter-spacing: 0.04em;
}
.badge--note { background: color-mix(in srgb, var(--color-primary) 15%, transparent); color: #7A6DA8; }
.badge--note { background: color-mix(in srgb, var(--fs-accent) 15%, transparent); color: #7A6DA8; }
.badge--task { background: rgba(212,160,23,0.15); color: #fbbf24; }
.badge--plan { background: rgba(99,102,241,0.18); color: #818cf8; }
@@ -894,7 +894,7 @@ onUnmounted(() => {
}
.k-card-snippet {
font-size: 0.8rem;
color: var(--color-muted);
color: var(--fs-text-tertiary);
display: -webkit-box;
-webkit-line-clamp: 4;
-webkit-box-orient: vertical;
@@ -914,9 +914,9 @@ onUnmounted(() => {
padding: 1px 6px;
border-radius: 8px;
background: rgba(255,255,255,0.05);
color: var(--color-muted);
color: var(--fs-text-tertiary);
}
.k-card-date { font-size: 0.72rem; color: var(--color-text-secondary); white-space: nowrap; opacity: 0.7; }
.k-card-date { font-size: 0.72rem; color: var(--fs-text-secondary); white-space: nowrap; opacity: 0.7; }
/* Only rendered for a record another user owns, so an unmarked card is
unambiguously the viewer's own. */
.shared-tag {
@@ -924,8 +924,8 @@ onUnmounted(() => {
padding: 0.08rem 0.35rem;
border-radius: 4px;
white-space: nowrap;
background: color-mix(in srgb, var(--color-text-secondary) 15%, transparent);
color: var(--color-text-secondary);
background: color-mix(in srgb, var(--fs-text-secondary) 15%, transparent);
color: var(--fs-text-secondary);
}
/* ── Task card ──────────────────────────────────────────── */
@@ -945,10 +945,10 @@ onUnmounted(() => {
border-radius: 8px;
font-weight: 500;
}
.status--todo { background: var(--color-status-todo-bg); color: var(--color-status-todo); }
.status--in_progress { background: var(--color-status-in-progress-bg); color: var(--color-status-in-progress); }
.status--done { background: var(--color-status-done-bg); color: var(--color-status-done); }
.status--cancelled { background: var(--color-status-todo-bg); color: var(--color-status-todo); text-decoration: line-through; }
.status--todo { background: var(--fs-status-todo-bg); color: var(--fs-status-todo); }
.status--in_progress { background: var(--fs-status-in-progress-bg); color: var(--fs-status-in-progress); }
.status--done { background: var(--fs-status-done-bg); color: var(--fs-status-done); }
.status--cancelled { background: var(--fs-status-todo-bg); color: var(--fs-status-todo); text-decoration: line-through; }
.priority-badge {
font-size: 0.7rem;
@@ -956,16 +956,16 @@ onUnmounted(() => {
border-radius: 8px;
font-weight: 500;
}
.priority--low { background: var(--color-priority-low-bg); color: var(--color-priority-low); }
.priority--normal { background: var(--color-priority-medium-bg); color: var(--color-priority-medium); }
.priority--high { background: var(--color-priority-high-bg); color: var(--color-priority-high); }
.priority--low { background: var(--fs-priority-low-bg); color: var(--fs-priority-low); }
.priority--normal { background: var(--fs-priority-medium-bg); color: var(--fs-priority-medium); }
.priority--high { background: var(--fs-priority-high-bg); color: var(--fs-priority-high); }
.task-due {
font-size: 0.78rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
}
.task-overdue {
color: var(--color-overdue);
color: var(--fs-overdue);
font-weight: 500;
}
@@ -977,7 +977,7 @@ onUnmounted(() => {
align-items: center;
justify-content: center;
padding: 60px 20px;
color: var(--color-muted);
color: var(--fs-text-tertiary);
text-align: center;
gap: 6px;
}
@@ -985,7 +985,7 @@ onUnmounted(() => {
.empty-narrator {
font-family: 'Fraunces', Georgia, serif;
font-size: 1rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
opacity: 0.85;
}
@@ -999,17 +999,17 @@ onUnmounted(() => {
}
.sentinel-loading {
font-size: 0.8rem;
color: var(--color-muted);
color: var(--fs-text-tertiary);
}
/* ── Graph panel ─────────────────────────────────────────── */
.graph-panel {
width: 500px;
flex-shrink: 0;
border-left: 1px solid var(--color-border);
border-left: 1px solid var(--fs-border-color);
display: flex;
flex-direction: column;
background: var(--color-bg-secondary);
background: var(--fs-surface-raised);
transition: width 0.2s ease;
}
.graph-panel.expanded {
@@ -1022,7 +1022,7 @@ onUnmounted(() => {
padding: 10px 14px;
font-size: 0.85rem;
font-weight: 500;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
flex-shrink: 0;
}
/* RESTORED (#2444). The panel is a flex COLUMN and its header is
@@ -1050,15 +1050,15 @@ onUnmounted(() => {
.dup-panel {
margin-bottom: 1.25rem;
padding: 0.85rem 1rem;
border: 1px solid var(--color-border);
border: 1px solid var(--fs-border-color);
border-radius: 8px;
background: var(--color-surface-alt);
background: var(--fs-surface-hover);
}
.dup-empty,
.dup-head {
margin: 0 0 0.5rem;
font-size: 0.85rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.dup-empty { margin-bottom: 0; }
.dup-group {
@@ -1067,7 +1067,7 @@ onUnmounted(() => {
gap: 0.75rem;
flex-wrap: wrap;
padding: 0.5rem 0;
border-top: 1px solid var(--color-border);
border-top: 1px solid var(--fs-border-color);
}
.dup-members {
display: flex;
@@ -1080,23 +1080,23 @@ onUnmounted(() => {
font-size: 0.8rem;
padding: 0.1rem 0.45rem;
border-radius: 4px;
background: color-mix(in srgb, var(--color-text-muted) 12%, transparent);
color: var(--color-text);
background: color-mix(in srgb, var(--fs-text-tertiary) 12%, transparent);
color: var(--fs-text-primary);
text-decoration: none;
overflow-wrap: anywhere;
}
.dup-member:hover { background: var(--color-hover); }
.dup-member:hover { background: var(--fs-surface-hover); }
.dup-score {
font-size: 0.75rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
font-variant-numeric: tabular-nums;
white-space: nowrap;
}
/* A set someone already ruled on — quiet, not celebratory: it means "skip". */
.dup-claimed {
font-size: 0.72rem;
color: var(--color-text-muted);
border: 1px solid var(--color-border);
color: var(--fs-text-tertiary);
border: 1px solid var(--fs-border-color);
border-radius: 4px;
padding: 0.05rem 0.4rem;
white-space: nowrap;
+17 -17
View File
@@ -123,9 +123,9 @@ function loginWithOAuth() {
.auth-card {
width: 100%;
max-width: 400px;
background: var(--color-bg-card);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-lg);
padding: 2rem;
}
.auth-brand {
@@ -142,11 +142,11 @@ function loginWithOAuth() {
.auth-hint {
text-align: center;
font-size: 0.9rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
margin-bottom: 1rem;
}
.auth-hint a {
color: var(--color-primary);
color: var(--fs-accent);
}
.field {
margin-bottom: 1rem;
@@ -160,19 +160,19 @@ function loginWithOAuth() {
.input {
width: 100%;
padding: 0.5rem 0.75rem;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
font-size: 0.95rem;
background: var(--color-bg);
color: var(--color-text);
background: var(--fs-surface-page);
color: var(--fs-text-primary);
box-sizing: border-box;
}
.input:focus {
outline: none;
border-color: var(--color-primary);
border-color: var(--fs-accent);
}
.error-msg {
color: var(--color-danger);
color: var(--fs-error);
font-size: 0.9rem;
margin: 0 0 0.75rem;
}
@@ -181,23 +181,23 @@ function loginWithOAuth() {
align-items: center;
gap: 0.75rem;
margin: 1.25rem 0;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
font-size: 0.85rem;
}
.divider::before,
.divider::after {
content: "";
flex: 1;
border-top: 1px solid var(--color-border);
border-top: 1px solid var(--fs-border-color);
}
.auth-footer {
text-align: center;
font-size: 0.9rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
margin: 1rem 0 0;
}
.auth-footer a {
color: var(--color-primary);
color: var(--fs-accent);
}
.forgot-link {
text-align: right;
@@ -205,9 +205,9 @@ function loginWithOAuth() {
font-size: 0.85rem;
}
.forgot-link a {
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
}
.forgot-link a:hover {
color: var(--color-primary);
color: var(--fs-accent);
}
</style>
+37 -37
View File
@@ -263,9 +263,9 @@ function clearFilters() {
margin: 0 0 1.5rem;
}
.settings-section {
background: var(--color-bg-card);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-lg);
padding: 1.25rem;
margin-bottom: 1.5rem;
}
@@ -292,23 +292,23 @@ function clearFilters() {
.stat-count {
font-size: 1.5rem;
font-weight: 700;
color: var(--color-text);
color: var(--fs-text-primary);
}
.stat-label {
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.stat-audit {
color: var(--color-primary);
color: var(--fs-accent);
}
.stat-usage {
color: var(--color-success);
color: var(--fs-success);
}
.stat-error {
color: var(--color-danger);
color: var(--fs-error);
}
/* Filters */
@@ -321,10 +321,10 @@ function clearFilters() {
.filter-input,
.filter-date {
padding: 0.4rem 0.6rem;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
background: var(--color-bg);
color: var(--color-text);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
background: var(--fs-surface-page);
color: var(--fs-text-primary);
font-size: 0.85rem;
}
.filter-select {
@@ -342,7 +342,7 @@ function clearFilters() {
.loading-msg,
.empty-msg {
text-align: center;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
font-size: 0.9rem;
padding: 1rem 0;
}
@@ -356,13 +356,13 @@ function clearFilters() {
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
padding: 0.5rem 0.75rem;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
}
.logs-table td {
padding: 0.5rem 0.75rem;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
font-size: 0.85rem;
}
.logs-table tbody tr:last-child td {
@@ -373,18 +373,18 @@ function clearFilters() {
transition: background 0.1s;
}
.log-row:hover {
background: var(--color-bg-secondary);
background: var(--fs-surface-raised);
}
.row-expanded {
background: var(--color-bg-secondary);
background: var(--fs-surface-raised);
}
.cell-time {
white-space: nowrap;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
font-size: 0.8rem;
}
.cell-user {
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
}
.cell-action {
max-width: 280px;
@@ -399,22 +399,22 @@ function clearFilters() {
.cell-ip {
font-family: monospace;
font-size: 0.8rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
white-space: nowrap;
}
.cell-duration {
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
font-size: 0.8rem;
white-space: nowrap;
}
.detail-ip {
font-family: monospace;
font-size: 0.8rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
margin-bottom: 0.4rem;
}
.text-error {
color: var(--color-danger);
color: var(--fs-error);
}
/* Category badges */
@@ -425,19 +425,19 @@ function clearFilters() {
text-transform: uppercase;
letter-spacing: 0.05em;
padding: 0.1rem 0.35rem;
border-radius: var(--radius-sm);
border-radius: var(--fs-radius-sm);
}
.cat-audit {
color: var(--color-primary);
background: color-mix(in srgb, var(--color-primary) 15%, transparent);
color: var(--fs-accent);
background: color-mix(in srgb, var(--fs-accent) 15%, transparent);
}
.cat-usage {
color: var(--color-success);
background: color-mix(in srgb, var(--color-success) 15%, transparent);
color: var(--fs-success);
background: color-mix(in srgb, var(--fs-success) 15%, transparent);
}
.cat-error {
color: var(--color-danger);
background: color-mix(in srgb, var(--color-danger) 15%, transparent);
color: var(--fs-error);
background: color-mix(in srgb, var(--fs-error) 15%, transparent);
}
/* Method tag */
@@ -448,8 +448,8 @@ function clearFilters() {
font-family: monospace;
padding: 0.05rem 0.25rem;
border-radius: 3px;
background: var(--color-bg-secondary);
color: var(--color-text-muted);
background: var(--fs-surface-raised);
color: var(--fs-text-tertiary);
margin-right: 0.25rem;
}
@@ -458,14 +458,14 @@ function clearFilters() {
cells don't carry, and the row exists to scope the rule below (#2444). */
.detail-row td {
padding: 0 0.75rem 0.75rem;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
}
.detail-json {
margin: 0;
padding: 0.75rem;
background: var(--color-bg);
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
background: var(--fs-surface-page);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
font-size: 0.8rem;
overflow-x: auto;
white-space: pre-wrap;
+35 -35
View File
@@ -633,13 +633,13 @@ onUnmounted(() => assist.clearSelection());
gap: 0.75rem;
flex-wrap: wrap;
padding-bottom: 0.5rem;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
}
.editor-tabs {
display: inline-flex;
background: var(--color-bg);
border: 1px solid var(--color-border);
background: var(--fs-surface-page);
border: 1px solid var(--fs-border-color);
border-radius: 8px;
padding: 2px;
gap: 2px;
@@ -653,14 +653,14 @@ onUnmounted(() => assist.clearSelection());
padding: 0.22rem 0.75rem;
font-size: 0.78rem;
font-weight: 500;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
cursor: pointer;
transition: background 0.15s, color 0.15s;
}
.tab:hover { color: var(--color-text); }
.tab:hover { color: var(--fs-text-primary); }
.tab.active {
background: var(--color-surface);
color: var(--color-text);
background: var(--fs-surface-hover);
color: var(--fs-text-primary);
box-shadow: 0 1px 3px rgba(0,0,0,0.12);
}
@@ -679,14 +679,14 @@ onUnmounted(() => assist.clearSelection());
.stream-label {
font-size: 0.8rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.stream-preview {
border: 1px solid var(--color-input-border);
border-radius: var(--radius-sm);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
padding: 0.75rem;
background: var(--color-bg-card);
background: var(--fs-surface-raised);
min-height: 200px;
}
@@ -699,7 +699,7 @@ onUnmounted(() => assist.clearSelection());
.note-sidebar {
width: 280px;
flex-shrink: 0;
border-left: 1px solid var(--color-border);
border-left: 1px solid var(--fs-border-color);
overflow-y: auto;
display: flex;
flex-direction: column;
@@ -708,17 +708,17 @@ onUnmounted(() => assist.clearSelection());
.sb-select, .sb-input {
width: 100%;
padding: 5px 8px;
border-radius: var(--radius-sm);
border: 1px solid var(--color-input-border);
background: var(--color-bg-tertiary);
color: var(--color-text);
border-radius: var(--fs-radius-sm);
border: 1px solid var(--fs-border-color);
background: var(--fs-surface-hover);
color: var(--fs-text-primary);
font-size: 0.82rem;
font-family: inherit;
outline: none;
transition: border-color 0.15s;
}
.sb-select:focus, .sb-input:focus {
border-color: var(--color-primary);
border-color: var(--fs-accent);
}
/* Tag suggest row inside sidebar */
@@ -742,13 +742,13 @@ onUnmounted(() => assist.clearSelection());
font-size: 0.72rem;
padding: 0.15rem 0.5rem;
background: none;
border: 1px solid var(--color-primary);
border-radius: var(--radius-sm);
color: var(--color-primary);
border: 1px solid var(--fs-accent);
border-radius: var(--fs-radius-sm);
color: var(--fs-accent);
cursor: pointer;
font-family: inherit;
}
.btn-link-all:hover { background: var(--color-action-primary); color: var(--fs-text-on-action); }
.btn-link-all:hover { background: var(--fs-action-primary); color: var(--fs-text-on-action); }
.link-suggest-list {
display: flex;
@@ -766,14 +766,14 @@ onUnmounted(() => assist.clearSelection());
.link-suggest-title {
flex: 1;
font-family: monospace;
color: var(--color-primary);
color: var(--fs-accent);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.link-suggest-count {
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
font-size: 0.72rem;
flex-shrink: 0;
}
@@ -783,13 +783,13 @@ onUnmounted(() => assist.clearSelection());
font-size: 0.72rem;
padding: 0.1rem 0.4rem;
background: none;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
cursor: pointer;
font-family: inherit;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
}
.btn-apply-link:hover { border-color: var(--color-primary); color: var(--color-primary); }
.btn-apply-link:hover { border-color: var(--fs-accent); color: var(--fs-accent); }
/* Writing Assistant section */
.assist-section {
@@ -801,7 +801,7 @@ onUnmounted(() => assist.clearSelection());
.assist-section-title {
font-size: 0.78rem;
font-weight: 500;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
text-transform: uppercase;
letter-spacing: 0.05em;
}
@@ -810,19 +810,19 @@ onUnmounted(() => assist.clearSelection());
.ef-label {
font-family: 'Fraunces', Georgia, serif;
font-size: 0.92rem;
color: var(--color-primary);
color: var(--fs-accent);
}
.prompt-editor {
width: 100%;
min-height: 60vh;
margin-top: 8px;
padding: 14px 16px;
border: 1px solid var(--color-border);
border: 1px solid var(--fs-border-color);
border-radius: 8px;
background: var(--color-surface);
color: var(--color-text);
background: var(--fs-surface-hover);
color: var(--fs-text-primary);
/* Prompts are plain markdown — a code-style editor, not rich text. */
font-family: var(--font-mono);
font-family: var(--fs-font-mono);
font-size: 0.88rem;
line-height: 1.55;
tab-size: 2;
@@ -830,7 +830,7 @@ onUnmounted(() => assist.clearSelection());
outline: none;
}
.prompt-editor:focus {
border-color: var(--color-primary);
border-color: var(--fs-accent);
}
/* Narrow screen: sidebar collapses */
@media (max-width: 720px) {
@@ -839,7 +839,7 @@ onUnmounted(() => assist.clearSelection());
.note-sidebar {
width: 100%;
border-left: none;
border-top: 1px solid var(--color-border);
border-top: 1px solid var(--fs-border-color);
overflow-y: visible;
}
}
+19 -19
View File
@@ -340,7 +340,7 @@ async function convertToTask() {
gap: 0.5rem;
flex-wrap: wrap;
font-size: 0.83rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
margin: 0 0 0.75rem;
}
.meta-item {
@@ -359,7 +359,7 @@ async function convertToTask() {
}
.backlinks {
margin-top: 2.5rem;
border-top: 1px solid var(--color-border);
border-top: 1px solid var(--fs-border-color);
padding-top: 1.25rem;
}
.backlinks-heading {
@@ -370,14 +370,14 @@ async function convertToTask() {
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
margin: 0 0 0.75rem;
}
.backlinks-count {
margin-left: 0.2rem;
font-size: 0.72rem;
background: var(--color-bg-secondary);
border: 1px solid var(--color-border);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: 999px;
padding: 0 0.4rem;
line-height: 1.4;
@@ -392,18 +392,18 @@ async function convertToTask() {
align-items: center;
gap: 0.6rem;
padding: 0.5rem 0.75rem;
border-radius: var(--radius-md);
background: var(--color-bg-card);
border: 1px solid var(--color-border);
border-radius: var(--fs-radius-lg);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
text-decoration: none;
color: var(--color-text);
color: var(--fs-text-primary);
transition: border-color 0.15s, box-shadow 0.15s;
font-size: 0.9rem;
}
.backlink-card:hover {
border-color: color-mix(in srgb, var(--color-primary) 50%, transparent);
border-color: color-mix(in srgb, var(--fs-accent) 50%, transparent);
box-shadow: 0 2px 8px rgba(0,0,0,0.06);
color: var(--color-primary);
color: var(--fs-accent);
}
.backlink-type-badge {
font-size: 0.68rem;
@@ -415,9 +415,9 @@ async function convertToTask() {
flex-shrink: 0;
}
.badge-note {
background: color-mix(in srgb, var(--color-primary) 12%, transparent);
color: var(--color-primary);
border: 1px solid color-mix(in srgb, var(--color-primary) 25%, transparent);
background: color-mix(in srgb, var(--fs-accent) 12%, transparent);
color: var(--fs-accent);
border: 1px solid color-mix(in srgb, var(--fs-accent) 25%, transparent);
}
.badge-task {
background: color-mix(in srgb, #f59e0b 12%, transparent);
@@ -446,12 +446,12 @@ async function convertToTask() {
.skel-title,
.skel-meta,
.skel-line {
border-radius: var(--radius-sm);
border-radius: var(--fs-radius-sm);
background: linear-gradient(
90deg,
var(--color-bg-secondary) 25%,
color-mix(in srgb, var(--color-text-muted) 18%, var(--color-bg-secondary)) 50%,
var(--color-bg-secondary) 75%
var(--fs-surface-raised) 25%,
color-mix(in srgb, var(--fs-text-tertiary) 18%, var(--fs-surface-raised)) 50%,
var(--fs-surface-raised) 75%
);
background-size: 200% 100%;
animation: skel-shine 1.5s ease infinite;
@@ -463,7 +463,7 @@ async function convertToTask() {
}
.skel-btn { width: 70px; height: 32px; }
.skel-btn--wide { width: 90px; }
.skel-title { height: 2.2rem; width: 70%; border-radius: var(--radius-md); }
.skel-title { height: 2.2rem; width: 70%; border-radius: var(--fs-radius-lg); }
.skel-meta { height: 0.85rem; width: 40%; }
.skel-line { height: 0.9rem; }
.skel-line--short { width: 55%; }
+55 -55
View File
@@ -317,9 +317,9 @@ function overallPct(project: Project): { total: number; pct: number } {
<style scoped>
.projects-list {
max-width: var(--page-max-width);
max-width: var(--fs-layout-page-max);
margin: 2rem auto;
padding: 0 var(--page-padding-x);
padding: 0 var(--fs-layout-page-pad);
overflow-x: clip;
}
@@ -340,7 +340,7 @@ function overallPct(project: Project): { total: number; pct: number } {
display: flex;
gap: 0.25rem;
margin-bottom: 1.25rem;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
padding-bottom: 0;
}
.tab-btn {
@@ -350,40 +350,40 @@ function overallPct(project: Project): { total: number; pct: number } {
border-bottom: 2px solid transparent;
cursor: pointer;
font-size: 0.875rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
font-family: inherit;
margin-bottom: -1px;
}
.tab-btn:hover {
color: var(--color-primary);
color: var(--fs-accent);
}
.tab-btn.active {
color: var(--color-primary);
border-bottom-color: var(--color-primary);
color: var(--fs-accent);
border-bottom-color: var(--fs-accent);
font-weight: 500;
}
.loading-msg,
.error-msg {
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
font-size: 0.9rem;
margin-top: 1rem;
}
.error-msg {
color: var(--color-danger);
color: var(--fs-error);
}
.empty-state-rich { text-align: center; padding: 3rem 1rem; color: var(--color-text-muted); }
.empty-state-rich { text-align: center; padding: 3rem 1rem; color: var(--fs-text-tertiary); }
.empty-icon { font-size: 2.5rem; margin-bottom: 0.75rem; opacity: 0.3; }
.empty-title { font-size: 1rem; font-weight: 500; color: var(--color-text-secondary); margin: 0 0 0.35rem; }
.empty-title { font-size: 1rem; font-weight: 500; color: var(--fs-text-secondary); margin: 0 0 0.35rem; }
.empty-sub { font-size: 0.85rem; margin: 0 0 1rem; }
.empty-action { display: inline-block; padding: 0.4rem 1rem; border: 1px solid var(--color-action-primary); border-radius: var(--radius-sm); color: var(--color-action-primary); background: none; cursor: pointer; font-size: 0.85rem; transition: background 0.15s, color 0.15s; }
.empty-action:hover { background: var(--color-action-primary); color: var(--fs-text-on-action); }
.empty-action { display: inline-block; padding: 0.4rem 1rem; border: 1px solid var(--fs-action-primary); border-radius: var(--fs-radius-sm); color: var(--fs-action-primary); background: none; cursor: pointer; font-size: 0.85rem; transition: background 0.15s, color 0.15s; }
.empty-action:hover { background: var(--fs-action-primary); color: var(--fs-text-on-action); }
.skeleton-card {
height: 140px;
border-radius: var(--radius-md);
background: linear-gradient(90deg, var(--color-bg-secondary) 25%, var(--color-border) 50%, var(--color-bg-secondary) 75%);
border-radius: var(--fs-radius-lg);
background: linear-gradient(90deg, var(--fs-surface-raised) 25%, var(--fs-border-color) 50%, var(--fs-surface-raised) 75%);
background-size: 200% 100%;
animation: skeleton-shimmer 1.4s ease infinite;
}
@@ -404,9 +404,9 @@ function overallPct(project: Project): { total: number; pct: number } {
}
.project-card {
background: var(--color-bg-card);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-lg);
padding: 1rem 1.1rem;
cursor: pointer;
transition: border-color 0.15s, box-shadow 0.15s, transform 0.18s ease;
@@ -415,7 +415,7 @@ function overallPct(project: Project): { total: number; pct: number } {
gap: 0.5rem;
}
.project-card:hover {
border-color: var(--color-primary);
border-color: var(--fs-accent);
box-shadow: 0 2px 8px var(--color-shadow);
transform: translateY(-2px);
}
@@ -429,7 +429,7 @@ function overallPct(project: Project): { total: number; pct: number } {
.project-title {
font-size: 1rem;
font-weight: 500;
color: var(--color-text);
color: var(--fs-text-primary);
min-width: 0;
flex: 1;
word-break: break-word;
@@ -446,32 +446,32 @@ function overallPct(project: Project): { total: number; pct: number } {
white-space: nowrap;
}
.status-active {
background: color-mix(in srgb, var(--color-success) 15%, transparent);
color: var(--color-success);
background: color-mix(in srgb, var(--fs-success) 15%, transparent);
color: var(--fs-success);
}
.status-completed {
background: color-mix(in srgb, var(--color-primary) 15%, transparent);
color: var(--color-primary);
background: color-mix(in srgb, var(--fs-accent) 15%, transparent);
color: var(--fs-accent);
}
.status-archived {
background: color-mix(in srgb, var(--color-text-muted) 15%, transparent);
color: var(--color-text-muted);
background: color-mix(in srgb, var(--fs-text-tertiary) 15%, transparent);
color: var(--fs-text-tertiary);
}
.project-goal {
font-size: 0.875rem;
color: var(--color-text);
color: var(--fs-text-primary);
margin: 0;
line-height: 1.4;
}
.field-label {
font-weight: 500;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
}
.project-desc {
font-size: 0.82rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
margin: 0;
line-height: 1.45;
}
@@ -486,18 +486,18 @@ function overallPct(project: Project): { total: number; pct: number } {
.overall-bar-track {
flex: 1;
height: 6px;
background: var(--color-border);
background: var(--fs-border-color);
border-radius: 999px;
overflow: hidden;
}
.overall-bar-fill {
height: 100%;
border-radius: 999px;
background: var(--color-primary);
background: var(--fs-accent);
transition: width 0.3s ease;
}
.overall-bar-pct {
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
flex-shrink: 0;
min-width: 2.5rem;
text-align: right;
@@ -517,7 +517,7 @@ function overallPct(project: Project): { total: number; pct: number } {
font-size: 0.72rem;
}
.milestone-bar-label {
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
min-width: 0;
flex: 0 0 30%;
overflow: hidden;
@@ -527,7 +527,7 @@ function overallPct(project: Project): { total: number; pct: number } {
.milestone-bar-track {
flex: 1;
height: 5px;
background: var(--color-border);
background: var(--fs-border-color);
border-radius: 999px;
overflow: hidden;
}
@@ -537,7 +537,7 @@ function overallPct(project: Project): { total: number; pct: number } {
transition: width 0.3s ease;
}
.milestone-bar-pct {
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
flex-shrink: 0;
min-width: 2.5rem;
text-align: right;
@@ -546,7 +546,7 @@ function overallPct(project: Project): { total: number; pct: number } {
/* Deliberately quiet — it is a footnote about what is not shown, not another
row competing with the bars above it. */
.milestone-more {
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
font-size: var(--fs-size-tiny);
padding-top: 0.15rem;
}
@@ -556,23 +556,23 @@ function overallPct(project: Project): { total: number; pct: number } {
}
.meta-date {
font-size: 0.75rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
/* Modal */
.modal-overlay {
position: fixed;
inset: 0;
background: var(--color-overlay);
background: var(--fs-overlay);
display: flex;
align-items: center;
justify-content: center;
z-index: 200;
}
.modal-card {
background: var(--color-bg-card);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-lg);
padding: 1.5rem;
width: 100%;
max-width: 480px;
@@ -593,18 +593,18 @@ function overallPct(project: Project): { total: number; pct: number } {
.modal-field label {
font-size: 0.875rem;
font-weight: 500;
color: var(--color-text);
color: var(--fs-text-primary);
}
.required {
color: var(--color-danger);
color: var(--fs-error);
}
.modal-input,
.modal-textarea {
padding: 0.45rem 0.7rem;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
background: var(--color-bg);
color: var(--color-text);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
background: var(--fs-surface-page);
color: var(--fs-text-primary);
font-size: 0.9rem;
font-family: inherit;
box-sizing: border-box;
@@ -613,7 +613,7 @@ function overallPct(project: Project): { total: number; pct: number } {
.modal-input:focus,
.modal-textarea:focus {
outline: none;
border-color: var(--color-primary);
border-color: var(--fs-accent);
}
.modal-textarea {
resize: vertical;
@@ -625,20 +625,20 @@ function overallPct(project: Project): { total: number; pct: number } {
}
.modal-btn {
padding: 0.4rem 0.9rem;
border: 1px solid var(--color-border);
background: var(--color-bg-secondary);
color: var(--color-text);
border-radius: var(--radius-sm);
border: 1px solid var(--fs-border-color);
background: var(--fs-surface-raised);
color: var(--fs-text-primary);
border-radius: var(--fs-radius-sm);
cursor: pointer;
font-size: 0.875rem;
font-family: inherit;
}
.modal-btn:hover {
background: var(--color-bg);
background: var(--fs-surface-page);
}
.modal-btn-primary {
background: var(--color-action-primary);
border-color: var(--color-action-primary);
background: var(--fs-action-primary);
border-color: var(--fs-action-primary);
color: var(--fs-text-on-action);
}
.modal-btn-primary:hover:not(:disabled) {
+140 -140
View File
@@ -932,9 +932,9 @@ async function confirmDelete() {
<style scoped>
/* ── Layout ─────────────────────────────────────────────────── */
.project-view {
max-width: var(--page-max-width);
max-width: var(--fs-layout-page-max);
margin: 2rem auto;
padding: 0 var(--page-padding-x);
padding: 0 var(--fs-layout-page-pad);
overflow-x: clip;
}
@@ -947,9 +947,9 @@ async function confirmDelete() {
}
.page-header-actions { display: flex; gap: 0.5rem; align-items: center; }
.plan-title-input {
background: var(--color-bg);
background: var(--fs-surface-page);
color: inherit;
border: 1px solid var(--color-border);
border: 1px solid var(--fs-border-color);
border-radius: 6px;
padding: 0.4rem 0.6rem;
font: inherit;
@@ -961,7 +961,7 @@ async function confirmDelete() {
font-size: 1.75rem;
font-weight: 500;
font-family: "Fraunces", Georgia, serif;
color: var(--color-text);
color: var(--fs-text-primary);
background: transparent;
border: none;
border-bottom: 1.5px solid transparent;
@@ -970,8 +970,8 @@ async function confirmDelete() {
min-width: 0;
transition: border-color 0.15s;
}
.project-title-input:focus { border-bottom-color: var(--color-primary); }
.project-title-input::placeholder { color: var(--color-text-muted); font-weight: 400; }
.project-title-input:focus { border-bottom-color: var(--fs-accent); }
.project-title-input::placeholder { color: var(--fs-text-tertiary); font-weight: 400; }
.status-badge {
font-size: 0.68rem;
@@ -982,14 +982,14 @@ async function confirmDelete() {
border-radius: 999px;
flex-shrink: 0;
}
.status-active { background: color-mix(in srgb, var(--color-success) 14%, transparent); color: var(--color-success); border: 1px solid color-mix(in srgb, var(--color-success) 30%, transparent); }
.status-paused { background: color-mix(in srgb, var(--color-warning) 14%, transparent); color: var(--color-warning); border: 1px solid color-mix(in srgb, var(--color-warning) 30%, transparent); }
.status-completed { background: color-mix(in srgb, var(--color-primary) 14%, transparent); color: var(--color-primary); border: 1px solid color-mix(in srgb, var(--color-primary) 30%, transparent); }
.status-archived { background: color-mix(in srgb, var(--color-text-muted) 14%, transparent); color: var(--color-text-muted); border: 1px solid color-mix(in srgb, var(--color-text-muted) 30%, transparent); }
.status-active { background: color-mix(in srgb, var(--fs-success) 14%, transparent); color: var(--fs-success); border: 1px solid color-mix(in srgb, var(--fs-success) 30%, transparent); }
.status-paused { background: color-mix(in srgb, var(--fs-warning) 14%, transparent); color: var(--fs-warning); border: 1px solid color-mix(in srgb, var(--fs-warning) 30%, transparent); }
.status-completed { background: color-mix(in srgb, var(--fs-accent) 14%, transparent); color: var(--fs-accent); border: 1px solid color-mix(in srgb, var(--fs-accent) 30%, transparent); }
.status-archived { background: color-mix(in srgb, var(--fs-text-tertiary) 14%, transparent); color: var(--fs-text-tertiary); border: 1px solid color-mix(in srgb, var(--fs-text-tertiary) 30%, transparent); }
.project-goal {
font-size: 1rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
margin: 0 0 0.3rem;
line-height: 1.45;
}
@@ -998,7 +998,7 @@ async function confirmDelete() {
align-items: center;
gap: 0.3rem;
font-size: 0.78rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
margin: 0;
}
@@ -1015,7 +1015,7 @@ async function confirmDelete() {
align-items: center;
gap: 0.35rem;
padding: 0.3rem 0.65rem;
border-radius: var(--radius-md);
border-radius: var(--fs-radius-lg);
font-size: 0.82rem;
border: 1px solid;
}
@@ -1028,14 +1028,14 @@ async function confirmDelete() {
border-radius: 50%;
flex-shrink: 0;
}
.dot-todo { background: transparent; border: 2px solid var(--color-text-muted); }
.dot-inprogress { background: var(--color-status-in-progress); }
.dot-done { background: var(--color-status-done); }
.dot-todo { background: transparent; border: 2px solid var(--fs-text-tertiary); }
.dot-inprogress { background: var(--fs-status-in-progress); }
.dot-done { background: var(--fs-status-done); }
.stat-todo { background: color-mix(in srgb, var(--color-text-muted) 8%, transparent); color: var(--color-text-secondary); border-color: var(--color-border); }
.stat-todo { background: color-mix(in srgb, var(--fs-text-tertiary) 8%, transparent); color: var(--fs-text-secondary); border-color: var(--fs-border-color); }
.stat-inprogress { background: color-mix(in srgb, #3b82f6 10%, transparent); color: #3b82f6; border-color: color-mix(in srgb, #3b82f6 28%, transparent); }
.stat-done { background: color-mix(in srgb, var(--color-success) 10%, transparent); color: var(--color-success); border-color: color-mix(in srgb, var(--color-success) 28%, transparent); }
.stat-notes { background: color-mix(in srgb, var(--color-primary) 8%, transparent); color: var(--color-primary); border-color: color-mix(in srgb, var(--color-primary) 22%, transparent); }
.stat-done { background: color-mix(in srgb, var(--fs-success) 10%, transparent); color: var(--fs-success); border-color: color-mix(in srgb, var(--fs-success) 28%, transparent); }
.stat-notes { background: color-mix(in srgb, var(--fs-accent) 8%, transparent); color: var(--fs-accent); border-color: color-mix(in srgb, var(--fs-accent) 22%, transparent); }
/* ── Two-column body ─────────────────────────────────────────── */
/* `minmax(0, 1fr)`, not `1fr`. A bare `1fr` track has an AUTO minimum, so it
@@ -1059,9 +1059,9 @@ async function confirmDelete() {
/* ── Edit panel ──────────────────────────────────────────────── */
.edit-panel {
background: var(--color-bg-card);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-lg);
padding: 1rem 1.1rem;
display: flex;
flex-direction: column;
@@ -1075,28 +1075,28 @@ async function confirmDelete() {
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.edit-field { display: flex; flex-direction: column; gap: 0.3rem; }
.edit-label {
font-size: 0.75rem;
font-weight: 500;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
text-transform: uppercase;
letter-spacing: 0.03em;
}
.edit-input, .edit-textarea, .edit-select {
padding: 0.4rem 0.6rem;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
background: var(--color-bg);
color: var(--color-text);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
background: var(--fs-surface-page);
color: var(--fs-text-primary);
font-size: 0.875rem;
font-family: inherit;
box-sizing: border-box;
width: 100%;
}
.edit-input:focus, .edit-textarea:focus, .edit-select:focus { outline: none; border-color: var(--color-primary); }
.edit-input:focus, .edit-textarea:focus, .edit-select:focus { outline: none; border-color: var(--fs-accent); }
.edit-textarea { resize: vertical; }
/* Save panel: Moss action-primary per Hybrid rule */
@@ -1110,27 +1110,27 @@ async function confirmDelete() {
border-bottom: 2px solid transparent;
cursor: pointer;
font-size: 0.875rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
font-family: inherit;
margin-bottom: -1px;
transition: color 0.15s;
}
.tab-btn:hover { color: var(--color-primary); }
.tab-btn.active { color: var(--color-primary); border-bottom-color: var(--color-primary); font-weight: 500; }
.tab-btn:hover { color: var(--fs-accent); }
.tab-btn.active { color: var(--fs-accent); border-bottom-color: var(--fs-accent); font-weight: 500; }
.tab-count {
font-size: 0.7rem;
font-weight: 500;
background: var(--color-bg-secondary);
border: 1px solid var(--color-border);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: 999px;
padding: 0 0.4rem;
line-height: 1.5;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.tab-btn.active .tab-count {
background: color-mix(in srgb, var(--color-primary) 12%, transparent);
border-color: color-mix(in srgb, var(--color-primary) 30%, transparent);
color: var(--color-primary);
background: color-mix(in srgb, var(--fs-accent) 12%, transparent);
border-color: color-mix(in srgb, var(--fs-accent) 30%, transparent);
color: var(--fs-accent);
}
/* ── Tasks view ──────────────────────────────────────────────── */
@@ -1139,28 +1139,28 @@ async function confirmDelete() {
.milestone-actions { display: flex; align-items: center; }
.btn-add-milestone {
background: none;
border: 1px dashed var(--color-border);
color: var(--color-text-secondary);
border: 1px dashed var(--fs-border-color);
color: var(--fs-text-secondary);
padding: 0.28rem 0.65rem;
border-radius: var(--radius-sm);
border-radius: var(--fs-radius-sm);
cursor: pointer;
font-size: 0.78rem;
font-family: inherit;
}
.btn-add-milestone:hover { border-color: var(--color-primary); color: var(--color-primary); }
.btn-add-milestone:hover { border-color: var(--fs-accent); color: var(--fs-accent); }
.new-milestone-row { display: flex; gap: 0.4rem; align-items: center; flex: 1; }
.milestone-title-input {
flex: 1;
padding: 0.3rem 0.5rem;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
background: var(--color-bg);
color: var(--color-text);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
background: var(--fs-surface-page);
color: var(--fs-text-primary);
font-size: 0.875rem;
font-family: inherit;
}
.milestone-title-input:focus { outline: none; border-color: var(--color-primary); }
.milestone-title-input:focus { outline: none; border-color: var(--fs-accent); }
/* Milestone confirm: Moss action-primary; Cancel: Bronze action-secondary */
/* RESTORED. Both of these lost their base rule to a CSS sweep and left only
modifiers behind — `.milestone-header.clickable`, `.milestone-header:hover`.
@@ -1170,9 +1170,9 @@ async function confirmDelete() {
the "uses space poorly" the operator saw, and it was a deletion rather than a
design change. A dangling `:hover` is the tell, and it is now checked for. */
.milestone-group {
background: var(--color-bg-card);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-lg);
overflow: hidden;
margin-bottom: 0.75rem;
}
@@ -1182,20 +1182,20 @@ async function confirmDelete() {
align-items: center;
gap: 0.5rem;
padding: 0.5rem 0.85rem;
background: var(--color-bg-secondary);
background: var(--fs-surface-raised);
}
.milestone-header.clickable { cursor: pointer; }
.milestone-header.clickable:hover { background: color-mix(in srgb, var(--color-primary) 4%, var(--color-bg-secondary)); }
.milestone-header.clickable:hover { background: color-mix(in srgb, var(--fs-accent) 4%, var(--fs-surface-raised)); }
/* Plan body: the milestone's design/intent, shown above its task columns. */
.ms-plan {
padding: 0.6rem 0.85rem;
background: color-mix(in srgb, var(--color-primary) 3%, var(--color-bg-card));
border-bottom: 1px solid var(--color-border);
background: color-mix(in srgb, var(--fs-accent) 3%, var(--fs-surface-raised));
border-bottom: 1px solid var(--fs-border-color);
}
.ms-plan-rendered { font-size: 0.85rem; color: var(--color-text); cursor: text; }
.ms-plan-rendered:hover { background: color-mix(in srgb, var(--color-primary) 4%, transparent); }
.ms-plan-rendered { font-size: 0.85rem; color: var(--fs-text-primary); cursor: text; }
.ms-plan-rendered:hover { background: color-mix(in srgb, var(--fs-accent) 4%, transparent); }
/* max-height rather than -webkit-line-clamp: the body is rendered markdown, so
it holds headings, lists and tables. line-clamp counts lines inside ONE inline
@@ -1216,21 +1216,21 @@ async function confirmDelete() {
background: linear-gradient(
to bottom,
transparent,
color-mix(in srgb, var(--color-primary) 3%, var(--color-bg-card))
color-mix(in srgb, var(--fs-accent) 3%, var(--fs-surface-raised))
);
pointer-events: none; /* the text under the fade stays clickable to edit */
}
.ms-plan-toggle { padding-left: 0; margin-top: 0.15rem; }
.ms-plan-editor {
width: 100%;
font-family: var(--font-mono);
font-family: var(--fs-font-mono);
font-size: 0.8rem;
line-height: 1.5;
padding: 0.5rem;
border: 1px solid var(--color-border);
border: 1px solid var(--fs-border-color);
border-radius: 6px;
background: var(--color-bg);
color: var(--color-text);
background: var(--fs-surface-page);
color: var(--fs-text-primary);
resize: vertical;
box-sizing: border-box;
}
@@ -1241,19 +1241,19 @@ async function confirmDelete() {
padding: 0.3rem 0.75rem;
border-radius: 6px;
cursor: pointer;
border: 1px solid var(--color-border);
border: 1px solid var(--fs-border-color);
}
.ms-plan-actions .btn-primary { background: var(--color-action-primary); color: var(--fs-text-on-action); border-color: var(--color-action-primary); }
.ms-plan-actions .btn-primary { background: var(--fs-action-primary); color: var(--fs-text-on-action); border-color: var(--fs-action-primary); }
.ms-plan-actions .btn-primary:disabled { opacity: 0.6; cursor: default; }
.ms-plan-actions .btn-secondary { background: var(--color-bg-card); color: var(--color-text); }
.ms-plan-actions .btn-secondary { background: var(--fs-surface-raised); color: var(--fs-text-primary); }
.ms-chevron { display: flex; align-items: center; color: var(--color-text-muted); flex-shrink: 0; }
.ms-name { font-weight: 500; color: var(--color-text); flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ms-chevron { display: flex; align-items: center; color: var(--fs-text-tertiary); flex-shrink: 0; }
.ms-name { font-weight: 500; color: var(--fs-text-primary); flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ms-count {
font-size: 0.7rem;
color: var(--color-text-muted);
background: var(--color-bg-card);
border: 1px solid var(--color-border);
color: var(--fs-text-tertiary);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: 999px;
padding: 0.05rem 0.4rem;
flex-shrink: 0;
@@ -1262,18 +1262,18 @@ async function confirmDelete() {
.ms-progress-track {
width: 72px;
height: 6px;
background: var(--color-border);
background: var(--fs-border-color);
border-radius: 999px;
overflow: hidden;
flex-shrink: 0;
}
.ms-progress-fill {
height: 100%;
background: linear-gradient(90deg, var(--color-primary), color-mix(in srgb, var(--color-primary) 70%, var(--color-success)));
background: linear-gradient(90deg, var(--fs-accent), color-mix(in srgb, var(--fs-accent) 70%, var(--fs-success)));
border-radius: 999px;
transition: width 0.4s ease;
}
.ms-pct { font-size: 0.72rem; color: var(--color-text-secondary); flex-shrink: 0; min-width: 2.4rem; text-align: right; font-weight: 500; }
.ms-pct { font-size: 0.72rem; color: var(--fs-text-secondary); flex-shrink: 0; min-width: 2.4rem; text-align: right; font-weight: 500; }
.ms-actions { display: flex; gap: 0.15rem; margin-left: 0.2rem; opacity: 0; transition: opacity 0.15s; }
.milestone-header:hover .ms-actions { opacity: 1; }
@@ -1284,22 +1284,22 @@ async function confirmDelete() {
background: none;
border: none;
cursor: pointer;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
width: 24px;
height: 24px;
border-radius: var(--radius-sm);
border-radius: var(--fs-radius-sm);
}
.ms-action-btn:hover { background: var(--color-bg-card); color: var(--color-text); }
.ms-action-delete:hover { color: var(--color-danger); }
.ms-action-btn:hover { background: var(--fs-surface-raised); color: var(--fs-text-primary); }
.ms-action-delete:hover { color: var(--fs-error); }
.ms-rename-input {
flex: 1;
min-width: 0;
padding: 0.1rem 0.35rem;
border: 1px solid var(--color-primary);
border-radius: var(--radius-sm);
background: var(--color-bg);
color: var(--color-text);
border: 1px solid var(--fs-accent);
border-radius: var(--fs-radius-sm);
background: var(--fs-surface-page);
color: var(--fs-text-primary);
font-size: 0.85rem;
font-family: inherit;
font-weight: 500;
@@ -1316,20 +1316,20 @@ async function confirmDelete() {
gap: 0.75rem;
align-items: start;
padding: 0.75rem;
background: color-mix(in srgb, var(--color-bg) 60%, var(--color-bg-secondary));
background: color-mix(in srgb, var(--fs-surface-page) 60%, var(--fs-surface-raised));
}
.kanban-col {
background: var(--color-bg-secondary);
border-radius: var(--radius-md);
background: var(--fs-surface-raised);
border-radius: var(--fs-radius-lg);
padding: 0.65rem;
display: flex;
flex-direction: column;
gap: 0.4rem;
border-top: 3px solid;
}
.col-todo { border-top-color: var(--color-border); }
.col-inprogress { border-top-color: var(--color-status-in-progress); }
.col-done { border-top-color: var(--color-status-done); }
.col-todo { border-top-color: var(--fs-border-color); }
.col-inprogress { border-top-color: var(--fs-status-in-progress); }
.col-done { border-top-color: var(--fs-status-done); }
.kanban-col-header {
display: flex;
@@ -1339,18 +1339,18 @@ async function confirmDelete() {
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
margin-bottom: 0.3rem;
}
.col-status-dot { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; }
.col-label { flex: 1; }
.col-count {
background: var(--color-bg-card);
border: 1px solid var(--color-border);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: 999px;
padding: 0.05rem 0.4rem;
font-size: 0.68rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
font-weight: 500;
}
.col-add-btn {
@@ -1359,40 +1359,40 @@ async function confirmDelete() {
justify-content: center;
width: 18px;
height: 18px;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
text-decoration: none;
font-size: 1rem;
line-height: 1;
border-radius: 3px;
margin-left: auto;
}
.col-add-btn:hover { color: var(--color-primary); background: color-mix(in srgb, var(--color-primary) 10%, transparent); }
.col-add-btn:hover { color: var(--fs-accent); background: color-mix(in srgb, var(--fs-accent) 10%, transparent); }
.kanban-cards { display: flex; flex-direction: column; gap: 0.3rem; }
.task-card {
display: block;
background: var(--color-bg-card);
border: 1px solid var(--color-border);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-left: 3px solid transparent;
border-radius: var(--radius-sm);
border-radius: var(--fs-radius-sm);
padding: 0.45rem 0.55rem;
text-decoration: none;
color: var(--color-text);
color: var(--fs-text-primary);
font-size: 0.85rem;
transition: border-color 0.12s, box-shadow 0.18s, transform 0.18s ease;
box-shadow: 0 1px 3px rgba(0,0,0,0.04);
}
.task-card:hover {
border-color: color-mix(in srgb, var(--color-primary) 50%, var(--color-border));
border-left-color: var(--color-primary);
border-color: color-mix(in srgb, var(--fs-accent) 50%, var(--fs-border-color));
border-left-color: var(--fs-accent);
box-shadow: 0 3px 10px rgba(0,0,0,0.08);
transform: translateY(-2px);
}
/* Priority left-border colors */
.task-card.pri-high { border-left-color: var(--color-danger); }
.task-card.pri-high { border-left-color: var(--fs-error); }
.task-card.pri-medium { border-left-color: #f59e0b; }
.task-card.pri-low { border-left-color: var(--color-success); }
.task-card.pri-low { border-left-color: var(--fs-success); }
.task-card-done { opacity: 0.65; }
.task-card-done .task-title { text-decoration: line-through; }
@@ -1404,10 +1404,10 @@ async function confirmDelete() {
flex-shrink: 0;
display: inline-flex; align-items: center; justify-content: center;
width: 1.4rem; height: 1.4rem;
border: 1px solid var(--color-border);
border: 1px solid var(--fs-border-color);
border-radius: 4px;
background: transparent;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
font-size: 0.75rem;
cursor: pointer;
opacity: 0;
@@ -1415,8 +1415,8 @@ async function confirmDelete() {
line-height: 1;
}
.task-card:hover .task-advance-btn { opacity: 1; }
.task-advance-btn:hover { background: var(--color-action-primary); border-color: var(--color-action-primary); color: var(--fs-text-on-action); }
.task-advance-btn--done:hover { background: var(--color-success); border-color: var(--color-success); color: var(--fs-text-on-action); }
.task-advance-btn:hover { background: var(--fs-action-primary); border-color: var(--fs-action-primary); color: var(--fs-text-on-action); }
.task-advance-btn--done:hover { background: var(--fs-success); border-color: var(--fs-success); color: var(--fs-text-on-action); }
.task-advance-btn:disabled { opacity: 0.4; cursor: default; }
.priority-dot {
@@ -1425,18 +1425,18 @@ async function confirmDelete() {
border-radius: 50%;
flex-shrink: 0;
}
.dot-pri-high { background: var(--color-danger); }
.dot-pri-high { background: var(--fs-error); }
.dot-pri-medium { background: #f59e0b; }
.dot-pri-low { background: var(--color-success); }
.dot-pri-low { background: var(--fs-success); }
.due-date { font-size: 0.7rem; color: var(--color-text-muted); }
.due-date { font-size: 0.7rem; color: var(--fs-text-tertiary); }
.col-empty {
text-align: center;
padding: 1.25rem 0.5rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
font-size: 0.78rem;
border: 1px dashed var(--color-border);
border-radius: var(--radius-sm);
border: 1px dashed var(--fs-border-color);
border-radius: var(--fs-radius-sm);
opacity: 0.7;
}
@@ -1447,62 +1447,62 @@ async function confirmDelete() {
align-items: center;
gap: 0.6rem;
padding: 0.6rem 0.9rem;
background: var(--color-bg-card);
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
text-decoration: none;
color: var(--color-text);
color: var(--fs-text-primary);
font-size: 0.9rem;
transition: border-color 0.12s, box-shadow 0.15s, transform 0.15s;
box-shadow: 0 1px 3px rgba(0,0,0,0.04);
}
.note-row:hover {
border-color: color-mix(in srgb, var(--color-primary) 50%, var(--color-border));
border-color: color-mix(in srgb, var(--fs-accent) 50%, var(--fs-border-color));
box-shadow: 0 3px 10px rgba(0,0,0,0.07);
transform: translateY(-1px);
}
.note-icon { color: var(--color-text-muted); flex-shrink: 0; }
.note-icon { color: var(--fs-text-tertiary); flex-shrink: 0; }
.note-title { font-weight: 500; min-width: 0; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.note-date { font-size: 0.75rem; color: var(--color-text-muted); flex-shrink: 0; }
.note-date { font-size: 0.75rem; color: var(--fs-text-tertiary); flex-shrink: 0; }
.empty-msg { color: var(--color-text-muted); font-size: 0.875rem; text-align: center; padding: 1rem; }
.empty-msg { color: var(--fs-text-tertiary); font-size: 0.875rem; text-align: center; padding: 1rem; }
/* Deliberately NOT styled like .empty-msg: "no tasks" and "the tasks did not
load" look identical to a user, and conflating them is what let a silent
failure read as an empty project. */
.tasks-error { color: var(--color-danger); font-size: 0.875rem; padding: 1rem; text-align: center; }
.tasks-error { color: var(--fs-error); font-size: 0.875rem; padding: 1rem; text-align: center; }
/* ── Modal ───────────────────────────────────────────────────── */
.modal-overlay {
position: fixed; inset: 0;
background: var(--color-overlay);
background: var(--fs-overlay);
display: flex; align-items: center; justify-content: center;
z-index: 200;
}
.modal-card {
background: var(--color-bg-card);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-lg);
padding: 1.5rem;
width: 100%;
max-width: 400px;
box-shadow: 0 8px 32px var(--color-shadow);
}
.modal-title { margin: 0 0 0.75rem; font-size: 1.05rem; }
.modal-message { font-size: 0.9rem; color: var(--color-text-secondary); margin: 0 0 1.25rem; line-height: 1.5; }
.modal-message { font-size: 0.9rem; color: var(--fs-text-secondary); margin: 0 0 1.25rem; line-height: 1.5; }
.modal-actions { display: flex; justify-content: flex-end; gap: 0.5rem; }
.modal-btn {
padding: 0.4rem 0.9rem;
border: 1px solid var(--color-border);
background: var(--color-bg-secondary);
color: var(--color-text);
border-radius: var(--radius-sm);
border: 1px solid var(--fs-border-color);
background: var(--fs-surface-raised);
color: var(--fs-text-primary);
border-radius: var(--fs-radius-sm);
cursor: pointer;
font-size: 0.875rem;
font-family: inherit;
}
.modal-btn:hover { background: var(--color-bg); }
.modal-btn-danger { background: var(--color-action-destructive); border-color: var(--color-action-destructive); color: var(--fs-text-on-action); }
.modal-btn-danger:hover { background: var(--color-action-destructive-hover); border-color: var(--color-action-destructive-hover); }
.modal-btn:hover { background: var(--fs-surface-page); }
.modal-btn-danger { background: var(--fs-action-destructive); border-color: var(--fs-action-destructive); color: var(--fs-text-on-action); }
.modal-btn-danger:hover { background: var(--fs-action-destructive-hover); border-color: var(--fs-action-destructive-hover); }
/* ── Skeleton ────────────────────────────────────────────────── */
@keyframes skel-shine { to { background-position: 200% center; } }
@@ -1512,21 +1512,21 @@ async function confirmDelete() {
gap: 0.65rem;
}
.skel-title, .skel-goal, .skel-stats, .skel-body, .skel-row {
border-radius: var(--radius-sm);
border-radius: var(--fs-radius-sm);
background: linear-gradient(
90deg,
var(--color-bg-secondary) 25%,
color-mix(in srgb, var(--color-text-muted) 16%, var(--color-bg-secondary)) 50%,
var(--color-bg-secondary) 75%
var(--fs-surface-raised) 25%,
color-mix(in srgb, var(--fs-text-tertiary) 16%, var(--fs-surface-raised)) 50%,
var(--fs-surface-raised) 75%
);
background-size: 200% 100%;
animation: skel-shine 1.5s ease infinite;
}
.skel-title { height: 2.2rem; width: 55%; border-radius: var(--radius-md); }
.skel-title { height: 2.2rem; width: 55%; border-radius: var(--fs-radius-lg); }
.skel-goal { height: 1rem; width: 75%; }
.skel-stats { height: 2rem; width: 50%; border-radius: var(--radius-md); }
.skel-body { height: 200px; border-radius: var(--radius-md); }
.skel-row { height: 2.5rem; border-radius: var(--radius-sm); }
.skel-stats { height: 2rem; width: 50%; border-radius: var(--fs-radius-lg); }
.skel-body { height: 200px; border-radius: var(--fs-radius-lg); }
.skel-row { height: 2.5rem; border-radius: var(--fs-radius-sm); }
.skel-row--short { width: 65%; }
/* ── Responsive ──────────────────────────────────────────────── */
+17 -17
View File
@@ -168,9 +168,9 @@ async function handleSubmit() {
.auth-card {
width: 100%;
max-width: 400px;
background: var(--color-bg-card);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-lg);
padding: 2rem;
}
.auth-brand {
@@ -186,13 +186,13 @@ async function handleSubmit() {
}
.loading-msg {
text-align: center;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
font-size: 0.95rem;
padding: 1rem 0;
}
.error-block {
text-align: center;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
font-size: 0.95rem;
padding: 0.5rem 0;
}
@@ -211,11 +211,11 @@ async function handleSubmit() {
.input {
width: 100%;
padding: 0.5rem 0.75rem;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
font-size: 0.95rem;
background: var(--color-bg);
color: var(--color-text);
background: var(--fs-surface-page);
color: var(--fs-text-primary);
box-sizing: border-box;
}
.input:disabled {
@@ -224,36 +224,36 @@ async function handleSubmit() {
}
.input:focus {
outline: none;
border-color: var(--color-primary);
border-color: var(--fs-accent);
}
.input-error {
border-color: var(--color-danger);
border-color: var(--fs-error);
}
.input-error:focus {
border-color: var(--color-danger);
border-color: var(--fs-error);
}
.field-hint {
margin: 0.35rem 0 0;
font-size: 0.8rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.error-hint {
margin: 0.35rem 0 0;
font-size: 0.8rem;
color: var(--color-danger);
color: var(--fs-error);
}
.error-msg {
color: var(--color-danger);
color: var(--fs-error);
font-size: 0.9rem;
margin: 0 0 0.75rem;
}
.auth-footer {
text-align: center;
font-size: 0.9rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
margin: 1rem 0 0;
}
.auth-footer a {
color: var(--color-primary);
color: var(--fs-accent);
}
</style>
+17 -17
View File
@@ -141,9 +141,9 @@ async function handleSubmit() {
.auth-card {
width: 100%;
max-width: 400px;
background: var(--color-bg-card);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-lg);
padding: 2rem;
}
.auth-brand {
@@ -159,13 +159,13 @@ async function handleSubmit() {
}
.loading-msg {
text-align: center;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
font-size: 0.9rem;
padding: 1rem 0;
}
.closed-msg {
text-align: center;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
font-size: 0.95rem;
padding: 0.5rem 0;
}
@@ -184,45 +184,45 @@ async function handleSubmit() {
.input {
width: 100%;
padding: 0.5rem 0.75rem;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
font-size: 0.95rem;
background: var(--color-bg);
color: var(--color-text);
background: var(--fs-surface-page);
color: var(--fs-text-primary);
box-sizing: border-box;
}
.input:focus {
outline: none;
border-color: var(--color-primary);
border-color: var(--fs-accent);
}
.input-error {
border-color: var(--color-danger);
border-color: var(--fs-error);
}
.input-error:focus {
border-color: var(--color-danger);
border-color: var(--fs-error);
}
.field-hint {
margin: 0.35rem 0 0;
font-size: 0.8rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.error-hint {
margin: 0.35rem 0 0;
font-size: 0.8rem;
color: var(--color-danger);
color: var(--fs-error);
}
.error-msg {
color: var(--color-danger);
color: var(--fs-error);
font-size: 0.9rem;
margin: 0 0 0.75rem;
}
.auth-footer {
text-align: center;
font-size: 0.9rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
margin: 1rem 0 0;
}
.auth-footer a {
color: var(--color-primary);
color: var(--fs-accent);
}
</style>
+17 -17
View File
@@ -117,9 +117,9 @@ async function handleSubmit() {
.auth-card {
width: 100%;
max-width: 400px;
background: var(--color-bg-card);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-lg);
padding: 2rem;
}
.auth-brand {
@@ -135,7 +135,7 @@ async function handleSubmit() {
}
.error-block {
text-align: center;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
font-size: 0.95rem;
padding: 0.5rem 0;
}
@@ -144,7 +144,7 @@ async function handleSubmit() {
}
.success-msg {
text-align: center;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
font-size: 0.95rem;
padding: 0.5rem 0;
}
@@ -163,45 +163,45 @@ async function handleSubmit() {
.input {
width: 100%;
padding: 0.5rem 0.75rem;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
font-size: 0.95rem;
background: var(--color-bg);
color: var(--color-text);
background: var(--fs-surface-page);
color: var(--fs-text-primary);
box-sizing: border-box;
}
.input:focus {
outline: none;
border-color: var(--color-primary);
border-color: var(--fs-accent);
}
.input-error {
border-color: var(--color-danger);
border-color: var(--fs-error);
}
.input-error:focus {
border-color: var(--color-danger);
border-color: var(--fs-error);
}
.field-hint {
margin: 0.35rem 0 0;
font-size: 0.8rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.error-hint {
margin: 0.35rem 0 0;
font-size: 0.8rem;
color: var(--color-danger);
color: var(--fs-error);
}
.error-msg {
color: var(--color-danger);
color: var(--fs-error);
font-size: 0.9rem;
margin: 0 0 0.75rem;
}
.auth-footer {
text-align: center;
font-size: 0.9rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
margin: 1rem 0 0;
}
.auth-footer a {
color: var(--color-primary);
color: var(--fs-accent);
}
</style>
+2 -2
View File
@@ -107,10 +107,10 @@ watch(() => route.query, syncFromRoute);
grid-template-columns: 280px 300px 1fr;
height: 100vh;
gap: 1px;
background: var(--color-border);
background: var(--fs-border-color);
}
.pane.empty {
background: var(--color-surface);
background: var(--fs-surface-hover);
padding: 1rem;
opacity: 0.6;
font-style: italic;
+197 -197
View File
@@ -2353,7 +2353,7 @@ function formatUserDate(iso: string): string {
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.07em;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
padding: 0.25rem 0.75rem 0.2rem;
}
.sidebar-item {
@@ -2366,19 +2366,19 @@ function formatUserDate(iso: string): string {
background: none;
cursor: pointer;
font-size: 0.875rem;
color: var(--color-text-secondary);
border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
color: var(--fs-text-secondary);
border-radius: 0 var(--fs-radius-sm) var(--fs-radius-sm) 0;
transition: color 0.15s, background 0.15s, border-color 0.15s;
font-family: inherit;
}
.sidebar-item:hover {
color: var(--color-text);
background: var(--color-bg-secondary);
color: var(--fs-text-primary);
background: var(--fs-surface-raised);
}
.sidebar-item.active {
color: var(--color-primary);
background: color-mix(in srgb, var(--color-primary) 8%, transparent);
border-left-color: var(--color-primary);
color: var(--fs-accent);
background: color-mix(in srgb, var(--fs-accent) 8%, transparent);
border-left-color: var(--fs-accent);
font-weight: 500;
}
@@ -2396,9 +2396,9 @@ function formatUserDate(iso: string): string {
align-items: start;
}
.settings-section {
background: var(--color-bg-card);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-lg);
padding: 1.25rem;
}
.settings-section.full-width {
@@ -2410,12 +2410,12 @@ function formatUserDate(iso: string): string {
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.07em;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.section-desc {
margin: 0 0 1rem;
font-size: 0.875rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
line-height: 1.5;
}
@@ -2429,8 +2429,8 @@ function formatUserDate(iso: string): string {
.model-row {
display: flex; align-items: center; justify-content: space-between; gap: 0.5rem;
padding: 0.45rem 0.6rem;
background: var(--color-bg-secondary);
border: 1px solid var(--color-border);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: 6px;
}
.model-row-info { display: flex; align-items: center; gap: 0.4rem; min-width: 0; flex: 1; }
@@ -2439,44 +2439,44 @@ function formatUserDate(iso: string): string {
font-size: 0.68rem; padding: 0.1rem 0.4rem; border-radius: 3px; font-weight: 500; white-space: nowrap;
}
.model-badge--loaded { background: color-mix(in srgb, #22c55e 18%, transparent); color: #22c55e; }
.model-badge--default { background: color-mix(in srgb, var(--color-primary) 18%, transparent); color: var(--color-primary); }
.model-badge--default { background: color-mix(in srgb, var(--fs-accent) 18%, transparent); color: var(--fs-accent); }
.model-row-right { display: flex; align-items: center; gap: 0.5rem; flex-shrink: 0; }
.model-size { font-size: 0.78rem; color: var(--color-text-muted); }
.model-size { font-size: 0.78rem; color: var(--fs-text-tertiary); }
.model-delete-btn {
background: none; border: none; cursor: pointer; color: var(--color-text-muted);
background: none; border: none; cursor: pointer; color: var(--fs-text-tertiary);
font-size: 0.8rem; padding: 0.2rem 0.35rem; border-radius: 3px; line-height: 1;
transition: color 0.15s, background 0.15s;
}
.model-delete-btn:hover:not(:disabled) { color: var(--color-action-destructive); background: color-mix(in srgb, var(--color-action-destructive) 10%, transparent); }
.model-delete-btn:hover:not(:disabled) { color: var(--fs-action-destructive); background: color-mix(in srgb, var(--fs-action-destructive) 10%, transparent); }
.model-delete-btn:disabled { opacity: 0.4; cursor: default; }
.model-pull-form { display: flex; gap: 0.5rem; margin-top: 0.5rem; }
.model-pull-form .input { flex: 1; }
.model-suggestions { display: flex; align-items: center; gap: 0.35rem; flex-wrap: wrap; margin-top: 0.4rem; }
.suggestions-label { font-size: 0.75rem; color: var(--color-text-muted); white-space: nowrap; }
.suggestions-label { font-size: 0.75rem; color: var(--fs-text-tertiary); white-space: nowrap; }
.suggestion-chip {
font-size: 0.72rem; padding: 0.15rem 0.5rem; border-radius: 4px;
border: 1px solid var(--color-border); background: var(--color-bg-card);
cursor: pointer; font-family: monospace; color: var(--color-text);
border: 1px solid var(--fs-border-color); background: var(--fs-surface-raised);
cursor: pointer; font-family: monospace; color: var(--fs-text-primary);
transition: border-color 0.12s, background 0.12s;
}
.suggestion-chip:hover:not(:disabled) { border-color: var(--color-primary); background: color-mix(in srgb, var(--color-primary) 8%, var(--color-bg-card)); }
.suggestion-chip:hover:not(:disabled) { border-color: var(--fs-accent); background: color-mix(in srgb, var(--fs-accent) 8%, var(--fs-surface-raised)); }
.suggestion-chip:disabled { opacity: 0.4; cursor: default; }
.model-pull-progress { margin-top: 0.6rem; }
.pull-status { font-size: 0.8rem; color: var(--color-text-muted); margin-bottom: 0.25rem; }
.pull-status { font-size: 0.8rem; color: var(--fs-text-tertiary); margin-bottom: 0.25rem; }
.pull-bar-track {
height: 4px; background: var(--color-border); border-radius: 2px; overflow: hidden;
height: 4px; background: var(--fs-border-color); border-radius: 2px; overflow: hidden;
}
.pull-bar-fill {
height: 100%; background: var(--color-primary); border-radius: 2px;
height: 100%; background: var(--fs-accent); border-radius: 2px;
transition: width 0.3s ease;
}
.pull-bar-indeterminate {
height: 4px; background: var(--color-border); border-radius: 2px;
height: 4px; background: var(--fs-border-color); border-radius: 2px;
position: relative; overflow: hidden;
}
.pull-bar-indeterminate::after {
content: ""; position: absolute; top: 0; left: -40%;
width: 40%; height: 100%; background: var(--color-primary); border-radius: 2px;
width: 40%; height: 100%; background: var(--fs-accent); border-radius: 2px;
animation: indeterminate 1.2s ease-in-out infinite;
}
@keyframes indeterminate {
@@ -2503,27 +2503,27 @@ function formatUserDate(iso: string): string {
font-size: 0.875rem;
font-weight: 500;
margin-bottom: 0.35rem;
color: var(--color-text);
color: var(--fs-text-primary);
}
.input {
width: 100%;
padding: 0.45rem 0.7rem;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
font-size: 0.9rem;
background: var(--color-bg);
color: var(--color-text);
background: var(--fs-surface-page);
color: var(--fs-text-primary);
box-sizing: border-box;
font-family: inherit;
}
.input:focus {
outline: none;
border-color: var(--color-primary);
border-color: var(--fs-accent);
}
.field-hint {
margin: 0.3rem 0 0;
font-size: 0.78rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.field-hint-warn {
display: block;
@@ -2552,12 +2552,12 @@ function formatUserDate(iso: string): string {
font-size: 0.82rem;
padding: 0.2rem 0;
}
.db-maint-table-list .dm-status { color: var(--color-text-muted); }
.db-maint-table-list li.dm-failed .dm-status { color: var(--color-danger); }
.db-maint-table-list .dm-status { color: var(--fs-text-tertiary); }
.db-maint-table-list li.dm-failed .dm-status { color: var(--fs-error); }
/* DB table-health readout */
.db-health { margin-top: 1.5rem; }
.db-health-total { color: var(--color-text-muted); font-weight: 400; }
.db-health-total { color: var(--fs-text-tertiary); font-weight: 400; }
.db-health-scroll { overflow-x: auto; margin-top: 0.5rem; }
.db-health-table {
width: 100%;
@@ -2567,35 +2567,35 @@ function formatUserDate(iso: string): string {
.db-health-table th, .db-health-table td {
text-align: left;
padding: 0.35rem 0.6rem;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
white-space: nowrap;
}
.db-health-table th {
font-size: 0.72rem;
text-transform: uppercase;
letter-spacing: 0.04em;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
font-weight: 500;
}
.db-health-table td.num, .db-health-table th.num { text-align: right; font-variant-numeric: tabular-nums; }
.db-health-table tr.dh-warn td { color: var(--color-warning); }
.db-health-table tr.dh-warn td:first-child code { color: var(--color-warning); }
.db-health-table tr.dh-warn td { color: var(--fs-warning); }
.db-health-table tr.dh-warn td:first-child code { color: var(--fs-warning); }
.btn-warn:hover:not(:disabled) {
background: var(--color-warning);
background: var(--fs-warning);
color: var(--fs-text-on-action);
}
.saved-msg {
color: var(--color-success);
color: var(--fs-success);
font-size: 0.875rem;
font-weight: 500;
}
.input-error { border-color: var(--color-danger); }
.input-error:focus { border-color: var(--color-danger); }
.input-error { border-color: var(--fs-error); }
.input-error:focus { border-color: var(--fs-error); }
.error-hint {
margin: 0.3rem 0 0;
font-size: 0.78rem;
color: var(--color-danger);
color: var(--fs-error);
}
.retention-row {
@@ -2623,21 +2623,21 @@ function formatUserDate(iso: string): string {
align-items: center;
gap: 0.5rem;
font-size: 0.9rem;
color: var(--color-text);
color: var(--fs-text-primary);
cursor: pointer;
}
.checkbox-field input[type="checkbox"] {
width: 16px;
height: 16px;
accent-color: var(--color-primary);
accent-color: var(--fs-accent);
}
/* Search test */
.url-chip {
font-size: 0.8rem;
padding: 0.1rem 0.4rem;
background: var(--color-bg-secondary);
border: 1px solid var(--color-border);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: 4px;
}
.not-configured {
@@ -2652,7 +2652,7 @@ function formatUserDate(iso: string): string {
.search-row .input { flex: 1; }
.search-error {
font-size: 0.875rem;
color: var(--color-danger);
color: var(--fs-error);
margin: 0 0 0.5rem;
}
.search-results {
@@ -2665,9 +2665,9 @@ function formatUserDate(iso: string): string {
}
.search-result {
padding: 0.65rem 0.85rem;
background: var(--color-bg-secondary);
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
}
.result-header {
display: flex;
@@ -2679,20 +2679,20 @@ function formatUserDate(iso: string): string {
.result-title {
font-size: 0.9rem;
font-weight: 500;
color: var(--color-primary);
color: var(--fs-accent);
text-decoration: none;
word-break: break-word;
}
.result-title:hover { text-decoration: underline; }
.result-host {
font-size: 0.75rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
white-space: nowrap;
}
.result-snippet {
margin: 0;
font-size: 0.82rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
line-height: 1.45;
display: -webkit-box;
-webkit-line-clamp: 2;
@@ -2721,10 +2721,10 @@ function formatUserDate(iso: string): string {
margin: 0 0 0.5rem;
font-size: 0.875rem;
font-weight: 500;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
}
.test-email-section {
border-top: 1px solid var(--color-border);
border-top: 1px solid var(--fs-border-color);
padding-top: 1rem;
}
.test-email-row {
@@ -2737,7 +2737,7 @@ function formatUserDate(iso: string): string {
/* Push notifications */
.push-unsupported {
font-size: 0.875rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.push-status-row {
display: flex;
@@ -2747,7 +2747,7 @@ function formatUserDate(iso: string): string {
font-size: 0.875rem;
}
.push-status-label {
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
font-weight: 500;
}
.push-permission-badge,
@@ -2758,15 +2758,15 @@ function formatUserDate(iso: string): string {
letter-spacing: 0.04em;
padding: 0.1rem 0.4rem;
border-radius: 999px;
background: color-mix(in srgb, var(--color-text-muted) 15%, transparent);
color: var(--color-text-muted);
background: color-mix(in srgb, var(--fs-text-tertiary) 15%, transparent);
color: var(--fs-text-tertiary);
}
.perm-granted { background: color-mix(in srgb, var(--color-success) 15%, transparent); color: var(--color-success); }
.perm-denied { background: color-mix(in srgb, var(--color-danger) 15%, transparent); color: var(--color-danger); }
.sub-active { background: color-mix(in srgb, var(--color-success) 15%, transparent); color: var(--color-success); }
.perm-granted { background: color-mix(in srgb, var(--fs-success) 15%, transparent); color: var(--fs-success); }
.perm-denied { background: color-mix(in srgb, var(--fs-error) 15%, transparent); color: var(--fs-error); }
.sub-active { background: color-mix(in srgb, var(--fs-success) 15%, transparent); color: var(--fs-success); }
.push-error {
font-size: 0.82rem;
color: var(--color-danger);
color: var(--fs-error);
margin: 0.25rem 0 0;
}
@@ -2780,7 +2780,7 @@ function formatUserDate(iso: string): string {
position: static;
padding-right: 0;
padding-bottom: 0.5rem;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
margin-bottom: 1rem;
}
.sidebar-group {
@@ -2796,13 +2796,13 @@ function formatUserDate(iso: string): string {
width: auto;
border-left: none;
border-bottom: 2px solid transparent;
border-radius: var(--radius-sm) var(--radius-sm) 0 0;
border-radius: var(--fs-radius-sm) var(--fs-radius-sm) 0 0;
font-size: 0.82rem;
padding: 0.35rem 0.7rem;
}
.sidebar-item.active {
border-bottom-color: var(--color-primary);
background: var(--color-primary-tint);
border-bottom-color: var(--fs-accent);
background: var(--fs-accent-soft);
}
.settings-grid {
grid-template-columns: 1fr;
@@ -2827,8 +2827,8 @@ function formatUserDate(iso: string): string {
}
.registration-info { flex: 1; }
.registration-status { margin: 0; font-size: 0.95rem; }
.text-success { color: var(--color-success); }
.text-muted { color: var(--color-text-muted); }
.text-success { color: var(--fs-success); }
.text-muted { color: var(--fs-text-tertiary); }
.invite-form {
display: flex;
gap: 0.5rem;
@@ -2840,7 +2840,7 @@ function formatUserDate(iso: string): string {
margin: 0 0 0.5rem;
font-size: 0.85rem;
font-weight: 500;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
}
.users-table { width: 100%; border-collapse: collapse; }
.users-table th {
@@ -2849,19 +2849,19 @@ function formatUserDate(iso: string): string {
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
padding: 0.5rem 0.75rem;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
}
.users-table td {
padding: 0.65rem 0.75rem;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
font-size: 0.9rem;
}
.users-table tbody tr:last-child td { border-bottom: none; }
.cell-username { font-weight: 500; }
.cell-email { color: var(--color-text-secondary); }
.cell-date { color: var(--color-text-muted); font-size: 0.85rem; }
.cell-email { color: var(--fs-text-secondary); }
.cell-date { color: var(--fs-text-tertiary); font-size: 0.85rem; }
.cell-actions { white-space: nowrap; }
.role-badge {
display: inline-block;
@@ -2870,17 +2870,17 @@ function formatUserDate(iso: string): string {
text-transform: uppercase;
letter-spacing: 0.05em;
padding: 0.15rem 0.4rem;
border-radius: var(--radius-sm);
border-radius: var(--fs-radius-sm);
}
.role-admin {
color: var(--color-primary);
background: color-mix(in srgb, var(--color-primary) 15%, transparent);
color: var(--fs-accent);
background: color-mix(in srgb, var(--fs-accent) 15%, transparent);
}
.role-user {
color: var(--color-text-muted);
background: var(--color-bg-secondary);
color: var(--fs-text-tertiary);
background: var(--fs-surface-raised);
}
.you-label { font-size: 0.8rem; color: var(--color-text-muted); }
.you-label { font-size: 0.8rem; color: var(--fs-text-tertiary); }
/* Per-row delete (users / invitations / etc.): ghost → Oxblood on hover */
/* Logs panel */
@@ -2894,17 +2894,17 @@ function formatUserDate(iso: string): string {
align-items: center;
gap: 0.15rem;
}
.stat-count { font-size: 1.5rem; font-weight: 500; color: var(--color-text); }
.stat-count { font-size: 1.5rem; font-weight: 500; color: var(--fs-text-primary); }
.stat-label {
font-size: 0.75rem;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.stat-audit { color: var(--color-primary); }
.stat-usage { color: var(--color-success); }
.stat-error { color: var(--color-danger); }
.stat-audit { color: var(--fs-accent); }
.stat-usage { color: var(--fs-success); }
.stat-error { color: var(--fs-error); }
.filter-bar { display: flex; gap: 0.5rem; flex-wrap: wrap; margin-bottom: 0.75rem; }
.filter-select { min-width: 140px; }
@@ -2918,49 +2918,49 @@ function formatUserDate(iso: string): string {
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
padding: 0.5rem 0.75rem;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
}
.logs-table td {
padding: 0.5rem 0.75rem;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
font-size: 0.85rem;
}
.logs-table tbody tr:last-child td { border-bottom: none; }
.log-row { cursor: pointer; transition: background 0.1s; }
.log-row:hover { background: var(--color-bg-secondary); }
.row-expanded { background: var(--color-bg-secondary); }
.cell-time { white-space: nowrap; color: var(--color-text-muted); font-size: 0.8rem; }
.cell-user { color: var(--color-text-secondary); }
.log-row:hover { background: var(--fs-surface-raised); }
.row-expanded { background: var(--fs-surface-raised); }
.cell-time { white-space: nowrap; color: var(--fs-text-tertiary); font-size: 0.8rem; }
.cell-user { color: var(--fs-text-secondary); }
.cell-action { max-width: 260px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cell-status { font-family: monospace; font-size: 0.85rem; }
.cell-duration { color: var(--color-text-muted); font-size: 0.8rem; white-space: nowrap; }
.text-error { color: var(--color-danger); }
.cell-duration { color: var(--fs-text-tertiary); font-size: 0.8rem; white-space: nowrap; }
.text-error { color: var(--fs-error); }
/* Bare by design, like LogsView's twin of this: a `<tr>` has nothing to style
that its cells don't carry (#2444). */
.detail-row td { padding: 0 0.75rem 0.75rem; border-bottom: 1px solid var(--color-border); }
.detail-ip { font-family: monospace; font-size: 0.8rem; color: var(--color-text-muted); margin-bottom: 0.4rem; }
.detail-row td { padding: 0 0.75rem 0.75rem; border-bottom: 1px solid var(--fs-border-color); }
.detail-ip { font-family: monospace; font-size: 0.8rem; color: var(--fs-text-tertiary); margin-bottom: 0.4rem; }
.detail-json {
margin: 0; padding: 0.75rem;
background: var(--color-bg); border: 1px solid var(--color-border);
border-radius: var(--radius-sm); font-size: 0.8rem;
background: var(--fs-surface-page); border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm); font-size: 0.8rem;
overflow-x: auto; white-space: pre-wrap; word-break: break-all; max-height: 300px;
}
.category-badge {
display: inline-block;
font-size: 0.65rem; font-weight: 500;
text-transform: uppercase; letter-spacing: 0.05em;
padding: 0.1rem 0.35rem; border-radius: var(--radius-sm);
padding: 0.1rem 0.35rem; border-radius: var(--fs-radius-sm);
}
.cat-audit { color: var(--color-primary); background: color-mix(in srgb, var(--color-primary) 15%, transparent); }
.cat-usage { color: var(--color-success); background: color-mix(in srgb, var(--color-success) 15%, transparent); }
.cat-error { color: var(--color-danger); background: color-mix(in srgb, var(--color-danger) 15%, transparent); }
.cat-audit { color: var(--fs-accent); background: color-mix(in srgb, var(--fs-accent) 15%, transparent); }
.cat-usage { color: var(--fs-success); background: color-mix(in srgb, var(--fs-success) 15%, transparent); }
.cat-error { color: var(--fs-error); background: color-mix(in srgb, var(--fs-error) 15%, transparent); }
.method-tag {
display: inline-block;
font-size: 0.65rem; font-weight: 500; font-family: monospace;
padding: 0.05rem 0.25rem; border-radius: 3px;
background: var(--color-bg-secondary); color: var(--color-text-muted);
background: var(--fs-surface-raised); color: var(--fs-text-tertiary);
margin-right: 0.25rem;
}
@@ -2968,7 +2968,7 @@ function formatUserDate(iso: string): string {
.version-line {
margin: 0;
font-size: 0.9rem;
color: var(--color-text);
color: var(--fs-text-primary);
display: flex;
align-items: center;
gap: 0.6rem;
@@ -2977,10 +2977,10 @@ function formatUserDate(iso: string): string {
font-family: ui-monospace, monospace;
font-size: 0.8rem;
padding: 0.15rem 0.5rem;
background: var(--color-bg-secondary);
border: 1px solid var(--color-primary);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-accent);
border-radius: 4px;
color: var(--color-primary);
color: var(--fs-accent);
}
/* ── Groups tab ──────────────────────────────────────────────── */
@@ -2989,16 +2989,16 @@ function formatUserDate(iso: string): string {
.input-field {
width: 100%;
padding: 0.4rem 0.6rem;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
background: var(--color-surface);
color: var(--color-text);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
background: var(--fs-surface-hover);
color: var(--fs-text-primary);
font-size: 0.875rem;
font-family: inherit;
outline: none;
transition: border-color 0.15s;
}
.input-field:focus { border-color: var(--color-primary); }
.input-field:focus { border-color: var(--fs-accent); }
.group-create-form {
display: flex;
@@ -3010,7 +3010,7 @@ function formatUserDate(iso: string): string {
.group-create-form .input-field { flex: 1; min-width: 160px; }
.loading-msg, .empty-msg {
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
font-size: 0.88rem;
padding: 0.5rem 0;
}
@@ -3022,8 +3022,8 @@ function formatUserDate(iso: string): string {
}
.group-card {
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-lg);
overflow: hidden;
}
@@ -3032,7 +3032,7 @@ function formatUserDate(iso: string): string {
align-items: center;
justify-content: space-between;
padding: 0.75rem 1rem;
background: var(--color-bg-secondary);
background: var(--fs-surface-raised);
}
.group-card-info {
@@ -3046,16 +3046,16 @@ function formatUserDate(iso: string): string {
.group-name {
font-weight: 500;
font-size: 0.9rem;
color: var(--color-text);
color: var(--fs-text-primary);
}
.group-meta {
font-size: 0.78rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
white-space: nowrap;
}
.group-desc {
font-size: 0.82rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
@@ -3078,8 +3078,8 @@ function formatUserDate(iso: string): string {
top: 100%;
left: 0;
right: 0;
background: var(--color-surface);
border: 1px solid var(--color-border);
background: var(--fs-surface-hover);
border: 1px solid var(--fs-border-color);
border-radius: 6px;
margin-top: 2px;
list-style: none;
@@ -3098,16 +3098,16 @@ function formatUserDate(iso: string): string {
cursor: pointer;
transition: background 0.1s;
}
.member-result-item:hover { background: var(--color-hover); }
.member-result-item:hover { background: var(--fs-surface-hover); }
.member-result-name { font-weight: 500; font-size: 0.85rem; }
.member-result-email { color: var(--color-text-muted); font-size: 0.78rem; }
.member-result-email { color: var(--fs-text-tertiary); font-size: 0.78rem; }
.role-select {
padding: 0.4rem 0.5rem;
border: 1px solid var(--color-border);
border: 1px solid var(--fs-border-color);
border-radius: 6px;
background: var(--color-surface);
color: var(--color-text);
background: var(--fs-surface-hover);
color: var(--fs-text-primary);
font-size: 0.85rem;
cursor: pointer;
font-family: inherit;
@@ -3128,10 +3128,10 @@ function formatUserDate(iso: string): string {
gap: 0.5rem;
padding: 0.4rem 0.5rem;
border-radius: 6px;
background: var(--color-hover);
background: var(--fs-surface-hover);
}
.member-name { flex: 1; font-size: 0.88rem; font-weight: 500; color: var(--color-text); }
.member-name { flex: 1; font-size: 0.88rem; font-weight: 500; color: var(--fs-text-primary); }
.member-role-badge {
font-size: 0.7rem;
@@ -3141,11 +3141,11 @@ function formatUserDate(iso: string): string {
padding: 0.15rem 0.4rem;
border-radius: 4px;
}
.role-owner { background: color-mix(in srgb, var(--color-warning) 15%, transparent); color: var(--color-warning); }
.role-member { background: color-mix(in srgb, var(--color-muted) 15%, transparent); color: var(--color-muted); }
.role-owner { background: color-mix(in srgb, var(--fs-warning) 15%, transparent); color: var(--fs-warning); }
.role-member { background: color-mix(in srgb, var(--fs-text-tertiary) 15%, transparent); color: var(--fs-text-tertiary); }
.members-empty {
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
font-size: 0.82rem;
padding: 0.25rem 0.5rem;
}
@@ -3160,23 +3160,23 @@ function formatUserDate(iso: string): string {
font-size: 0.78rem;
margin: 0.2rem 0 0;
}
.geo-ok { color: var(--color-success); }
.geo-error { color: var(--color-danger); }
.geo-pending { color: var(--color-text-muted); }
.geo-ok { color: var(--fs-success); }
.geo-error { color: var(--fs-error); }
.geo-pending { color: var(--fs-text-tertiary); }
.unit-toggle {
display: flex;
gap: 0;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
overflow: hidden;
width: fit-content;
margin-top: 0.25rem;
}
.unit-btn {
padding: 0.4rem 1rem;
background: var(--color-bg-card);
color: var(--color-text-muted);
background: var(--fs-surface-raised);
color: var(--fs-text-tertiary);
font-size: 0.85rem;
cursor: pointer;
border: none;
@@ -3184,14 +3184,14 @@ function formatUserDate(iso: string): string {
transition: background 0.15s, color 0.15s;
}
.unit-btn:not(:last-child) {
border-right: 1px solid var(--color-border);
border-right: 1px solid var(--fs-border-color);
}
.unit-btn.active {
background: var(--color-action-primary);
background: var(--fs-action-primary);
color: var(--fs-text-on-action);
}
.unit-btn:hover:not(.active) {
color: var(--color-text);
color: var(--fs-text-primary);
}
.checkbox-label {
@@ -3216,7 +3216,7 @@ function formatUserDate(iso: string): string {
}
.time-sep {
font-size: 1.1rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.time-sep--quiet { font-size: 0.9rem; }
@@ -3239,9 +3239,9 @@ function formatUserDate(iso: string): string {
cursor: pointer;
}
.api-key-reveal {
background: color-mix(in srgb, var(--color-primary) 8%, var(--color-surface));
border: 1px solid color-mix(in srgb, var(--color-primary) 30%, transparent);
border-radius: var(--radius-md);
background: color-mix(in srgb, var(--fs-accent) 8%, var(--fs-surface-hover));
border: 1px solid color-mix(in srgb, var(--fs-accent) 30%, transparent);
border-radius: var(--fs-radius-lg);
padding: 1rem;
margin-bottom: 1.5rem;
}
@@ -3253,9 +3253,9 @@ function formatUserDate(iso: string): string {
}
.api-key-value {
flex: 1;
background: var(--color-surface-2);
background: var(--fs-surface-hover);
padding: 0.4rem 0.6rem;
border-radius: var(--radius-sm);
border-radius: var(--fs-radius-sm);
font-size: 0.85rem;
word-break: break-all;
}
@@ -3267,7 +3267,7 @@ function formatUserDate(iso: string): string {
.api-keys-table th, .api-keys-table td {
text-align: left;
padding: 0.5rem 0.75rem;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
font-size: 0.9rem;
}
.api-keys-table th { font-weight: 500; opacity: 0.7; }
@@ -3292,8 +3292,8 @@ function formatUserDate(iso: string): string {
align-items: center;
gap: 1rem;
padding: 0.65rem 0.9rem;
background: color-mix(in srgb, var(--color-primary) 8%, transparent);
border: 1px solid color-mix(in srgb, var(--color-primary) 25%, transparent);
background: color-mix(in srgb, var(--fs-accent) 8%, transparent);
border: 1px solid color-mix(in srgb, var(--fs-accent) 25%, transparent);
border-radius: 8px;
}
.mcp-pkg-name { font-family: monospace; font-size: 0.9rem; flex: 1; }
@@ -3303,8 +3303,8 @@ function formatUserDate(iso: string): string {
.mcp-code {
margin-top: 0.4rem;
padding: 0.55rem 0.75rem;
background: color-mix(in srgb, var(--color-text) 6%, transparent);
border: 1px solid var(--color-border);
background: color-mix(in srgb, var(--fs-text-primary) 6%, transparent);
border: 1px solid var(--fs-border-color);
border-radius: 6px;
font-size: 0.82rem;
font-family: monospace;
@@ -3317,23 +3317,23 @@ function formatUserDate(iso: string): string {
display: flex;
gap: 0.25rem;
margin-bottom: 1rem;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
}
.mcp-client-tab {
background: transparent;
border: none;
padding: 0.5rem 0.9rem;
font-size: 0.85rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
cursor: pointer;
border-bottom: 2px solid transparent;
margin-bottom: -1px;
transition: color 0.15s, border-color 0.15s;
}
.mcp-client-tab:hover { color: var(--color-text); }
.mcp-client-tab:hover { color: var(--fs-text-primary); }
.mcp-client-tab.active {
color: var(--color-primary);
border-bottom-color: var(--color-primary);
color: var(--fs-accent);
border-bottom-color: var(--fs-accent);
font-weight: 500;
}
.mcp-url-block { margin-top: 0.25rem; }
@@ -3371,7 +3371,7 @@ function formatUserDate(iso: string): string {
.mcp-code-row .btn-sm { white-space: nowrap; }
.mcp-advanced {
margin-top: 1.25rem;
border-top: 1px solid var(--color-border);
border-top: 1px solid var(--fs-border-color);
padding-top: 0.75rem;
}
.mcp-advanced summary {
@@ -3428,7 +3428,7 @@ function formatUserDate(iso: string): string {
list-style: none;
margin: 0;
padding: 0;
border-top: 1px solid var(--color-border);
border-top: 1px solid var(--fs-border-color);
max-height: 480px;
overflow-y: auto;
}
@@ -3438,19 +3438,19 @@ function formatUserDate(iso: string): string {
justify-content: space-between;
gap: 1rem;
padding: 0.65rem 0.25rem;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
}
.voice-library-meta {
min-width: 0;
flex: 1;
}
.voice-library-id {
font-family: var(--font-mono);
font-family: var(--fs-font-mono);
font-size: 0.9rem;
font-weight: 500;
}
.voice-library-sub {
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
font-size: 0.8rem;
margin-top: 0.15rem;
}
@@ -3462,7 +3462,7 @@ function formatUserDate(iso: string): string {
}
.voice-library-empty {
padding: 1rem 0;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
text-align: center;
font-style: italic;
}
@@ -3475,9 +3475,9 @@ function formatUserDate(iso: string): string {
letter-spacing: 0.04em;
}
.voice-badge--bundled {
background: color-mix(in srgb, var(--color-text-muted) 10%, transparent);
color: var(--color-text-muted);
border: 1px solid var(--color-border);
background: color-mix(in srgb, var(--fs-text-tertiary) 10%, transparent);
color: var(--fs-text-tertiary);
border: 1px solid var(--fs-border-color);
}
.status-badge {
font-size: 0.75rem;
@@ -3486,14 +3486,14 @@ function formatUserDate(iso: string): string {
border-radius: 999px;
}
.status-on {
background: color-mix(in srgb, var(--color-success) 15%, transparent);
color: var(--color-success);
border: 1px solid color-mix(in srgb, var(--color-success) 40%, transparent);
background: color-mix(in srgb, var(--fs-success) 15%, transparent);
color: var(--fs-success);
border: 1px solid color-mix(in srgb, var(--fs-success) 40%, transparent);
}
.status-off {
background: color-mix(in srgb, var(--color-text-muted) 10%, transparent);
color: var(--color-text-muted);
border: 1px solid var(--color-border);
background: color-mix(in srgb, var(--fs-text-tertiary) 10%, transparent);
color: var(--fs-text-tertiary);
border: 1px solid var(--fs-border-color);
}
.radio-group {
display: flex;
@@ -3513,7 +3513,7 @@ function formatUserDate(iso: string): string {
.range-input {
width: 100%;
max-width: 360px;
accent-color: var(--color-primary);
accent-color: var(--fs-accent);
margin: 0.35rem 0 0.2rem;
}
.range-labels {
@@ -3521,7 +3521,7 @@ function formatUserDate(iso: string): string {
justify-content: space-between;
max-width: 360px;
font-size: 0.75rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.form-actions {
margin-top: 1rem;
@@ -3539,7 +3539,7 @@ function formatUserDate(iso: string): string {
width: 4px;
height: 4px;
border-radius: 50%;
background: var(--color-text-muted);
background: var(--fs-text-tertiary);
animation: va-dot-bounce 1.2s ease-in-out infinite;
}
.voice-admin-spinner span:nth-child(2) { animation-delay: 0.2s; }
@@ -3553,9 +3553,9 @@ function formatUserDate(iso: string): string {
margin-bottom: 0.5rem;
}
.blend-slot {
background: color-mix(in srgb, var(--color-surface) 60%, transparent);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
background: color-mix(in srgb, var(--fs-surface-hover) 60%, transparent);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-lg);
padding: 0.75rem 1rem;
display: flex;
flex-direction: column;
@@ -3577,7 +3577,7 @@ function formatUserDate(iso: string): string {
font-variant-numeric: tabular-nums;
min-width: 2.5rem;
text-align: right;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
}
.blend-actions {
margin-top: 0.25rem;
@@ -3599,37 +3599,37 @@ function formatUserDate(iso: string): string {
}
.day-btn {
padding: 0.3rem 0.65rem;
border: 1px solid var(--color-border);
border: 1px solid var(--fs-border-color);
border-radius: 6px;
background: var(--color-bg-card);
color: var(--color-text-muted);
background: var(--fs-surface-raised);
color: var(--fs-text-tertiary);
font-size: 0.82rem;
cursor: pointer;
transition: all 0.15s;
font-family: inherit;
}
.day-btn:hover { border-color: var(--color-primary); color: var(--color-primary); }
.day-btn:hover { border-color: var(--fs-accent); color: var(--fs-accent); }
.day-btn.active {
background: color-mix(in srgb, var(--color-primary) 15%, transparent);
border-color: var(--color-primary);
color: var(--color-primary);
background: color-mix(in srgb, var(--fs-accent) 15%, transparent);
border-color: var(--fs-accent);
color: var(--fs-accent);
font-weight: 500;
}
.learned-summary {
background: var(--color-bg-secondary);
border: 1px solid var(--color-border);
border-left: 3px solid var(--color-primary);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-left: 3px solid var(--fs-accent);
border-radius: 8px;
padding: 0.85rem 1rem;
font-size: 0.9rem;
line-height: 1.55;
color: var(--color-text);
color: var(--fs-text-primary);
white-space: pre-wrap;
margin-bottom: 0.75rem;
}
.learned-empty {
font-size: 0.85rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
margin-bottom: 0.75rem;
}
</style>
+20 -20
View File
@@ -106,11 +106,11 @@ onMounted(async () => {
font-size: 1.8rem;
font-weight: 700;
margin: 0;
color: var(--color-text);
color: var(--fs-text-primary);
}
.loading-state {
color: var(--color-muted);
color: var(--fs-text-tertiary);
padding: 2rem;
text-align: center;
}
@@ -124,7 +124,7 @@ onMounted(async () => {
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.07em;
color: var(--color-muted);
color: var(--fs-text-tertiary);
margin: 0 0 0.75rem;
}
@@ -136,9 +136,9 @@ onMounted(async () => {
.shared-card {
display: flex;
background: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: var(--radius-lg);
background: var(--fs-surface-hover);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-xl);
overflow: hidden;
text-decoration: none;
transition: box-shadow 0.15s, transform 0.15s;
@@ -151,7 +151,7 @@ onMounted(async () => {
.card-color-bar {
width: 4px;
flex-shrink: 0;
background: var(--color-border);
background: var(--fs-border-color);
}
.card-body {
@@ -163,7 +163,7 @@ onMounted(async () => {
.card-title {
font-weight: 600;
font-size: 0.95rem;
color: var(--color-text);
color: var(--fs-text-primary);
margin-bottom: 0.3rem;
white-space: nowrap;
overflow: hidden;
@@ -179,12 +179,12 @@ onMounted(async () => {
.card-owner {
font-size: 0.78rem;
color: var(--color-muted);
color: var(--fs-text-tertiary);
}
.card-desc {
font-size: 0.82rem;
color: var(--color-muted);
color: var(--fs-text-tertiary);
margin: 0;
overflow: hidden;
display: -webkit-box;
@@ -203,25 +203,25 @@ onMounted(async () => {
align-items: center;
gap: 0.6rem;
padding: 0.6rem 0.9rem;
background: var(--color-surface);
border: 1px solid var(--color-border);
background: var(--fs-surface-hover);
border: 1px solid var(--fs-border-color);
border-radius: 8px;
text-decoration: none;
transition: background 0.1s;
}
.shared-row:hover {
background: var(--color-hover);
background: var(--fs-surface-hover);
}
.row-icon {
font-size: 0.9rem;
flex-shrink: 0;
color: var(--color-muted);
color: var(--fs-text-tertiary);
}
.row-title {
flex: 1;
font-size: 0.9rem;
color: var(--color-text);
color: var(--fs-text-primary);
font-weight: 500;
white-space: nowrap;
overflow: hidden;
@@ -229,7 +229,7 @@ onMounted(async () => {
}
.row-owner {
font-size: 0.78rem;
color: var(--color-muted);
color: var(--fs-text-tertiary);
white-space: nowrap;
}
@@ -242,12 +242,12 @@ onMounted(async () => {
border-radius: 4px;
white-space: nowrap;
}
.perm-viewer { background: color-mix(in srgb, var(--color-muted) 15%, transparent); color: var(--color-muted); }
.perm-editor { background: color-mix(in srgb, var(--color-primary) 15%, transparent); color: var(--color-primary); }
.perm-admin { background: color-mix(in srgb, var(--color-warning) 15%, transparent); color: var(--color-warning); }
.perm-viewer { background: color-mix(in srgb, var(--fs-text-tertiary) 15%, transparent); color: var(--fs-text-tertiary); }
.perm-editor { background: color-mix(in srgb, var(--fs-accent) 15%, transparent); color: var(--fs-accent); }
.perm-admin { background: color-mix(in srgb, var(--fs-warning) 15%, transparent); color: var(--fs-warning); }
.empty-msg {
color: var(--color-muted);
color: var(--fs-text-tertiary);
font-size: 0.88rem;
margin: 0;
padding: 1rem 0;
+33 -33
View File
@@ -205,7 +205,7 @@ async function confirmDelete() {
.snippet-detail {
max-width: 820px;
margin: 2rem auto;
padding: 0 var(--page-padding-x);
padding: 0 var(--fs-layout-page-pad);
overflow-x: clip;
}
@@ -213,20 +213,20 @@ async function confirmDelete() {
display: inline-block;
margin-bottom: 1rem;
font-size: 0.85rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
text-decoration: none;
}
.back-link:hover {
color: var(--color-primary);
color: var(--fs-accent);
}
.state-msg {
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
font-size: 0.9rem;
margin-top: 1rem;
}
.error-msg {
color: var(--color-danger);
color: var(--fs-error);
font-size: 0.9rem;
margin-top: 1rem;
}
@@ -239,7 +239,7 @@ async function confirmDelete() {
}
.snippet-name {
margin: 0;
font-family: var(--font-mono);
font-family: var(--fs-font-mono);
font-size: 1.4rem;
word-break: break-word;
}
@@ -253,7 +253,7 @@ async function confirmDelete() {
.when-to-use {
margin: 0.75rem 0 1.25rem;
font-size: 1rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
line-height: 1.55;
}
@@ -262,12 +262,12 @@ async function confirmDelete() {
.shared-notice {
margin: 0.75rem 0 0;
padding: 0.6rem 0.85rem;
border-left: 3px solid var(--color-text-muted);
border-left: 3px solid var(--fs-text-tertiary);
border-radius: 6px;
background: var(--color-bg-secondary);
background: var(--fs-surface-raised);
font-size: 0.85rem;
line-height: 1.5;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
}
.meta-grid {
@@ -280,23 +280,23 @@ async function confirmDelete() {
font-size: 0.7rem;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
padding-top: 0.15rem;
}
.meta-grid dd {
margin: 0;
font-size: 0.9rem;
color: var(--color-text);
color: var(--fs-text-primary);
min-width: 0;
}
.meta-grid code,
.tag-row + * code {
font-family: var(--font-mono);
font-family: var(--fs-font-mono);
font-size: 0.82rem;
background: color-mix(in srgb, var(--color-primary) 12%, transparent);
color: var(--color-primary);
background: color-mix(in srgb, var(--fs-accent) 12%, transparent);
color: var(--fs-accent);
padding: 0.08rem 0.35rem;
border-radius: var(--radius-sm);
border-radius: var(--fs-radius-sm);
word-break: break-all;
}
.location-list {
@@ -317,7 +317,7 @@ async function confirmDelete() {
align-items: baseline;
}
.merged-hint {
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
font-size: 0.8rem;
}
.merged-entry {
@@ -328,15 +328,15 @@ async function confirmDelete() {
.unmerge-btn {
font-size: 0.72rem;
padding: 0.05rem 0.35rem;
border: 1px solid var(--color-border);
border: 1px solid var(--fs-border-color);
border-radius: 4px;
background: transparent;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
cursor: pointer;
}
.unmerge-btn:hover:not(:disabled) {
color: var(--color-text);
border-color: var(--color-text-muted);
color: var(--fs-text-primary);
border-color: var(--fs-text-tertiary);
}
.unmerge-btn:disabled {
opacity: 0.6;
@@ -344,30 +344,30 @@ async function confirmDelete() {
}
.unmerge-na {
font-size: 0.72rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
/* Cursor cues that the explanation is in the tooltip. */
cursor: help;
}
.code-block {
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-lg);
overflow: hidden;
background: var(--color-bg);
background: var(--fs-surface-page);
}
.code-bar {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0.4rem 0.5rem 0.4rem 0.85rem;
border-bottom: 1px solid var(--color-border);
background: var(--color-bg-secondary);
border-bottom: 1px solid var(--fs-border-color);
background: var(--fs-surface-raised);
}
.code-lang {
font-size: 0.72rem;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.btn-copy {
padding: 0.2rem 0.65rem;
@@ -379,10 +379,10 @@ async function confirmDelete() {
overflow-x: auto;
}
.code-block code {
font-family: var(--font-mono);
font-family: var(--fs-font-mono);
font-size: 0.85rem;
line-height: 1.6;
color: var(--color-text);
color: var(--fs-text-primary);
white-space: pre;
}
@@ -396,9 +396,9 @@ async function confirmDelete() {
font-size: 0.72rem;
padding: 0.15rem 0.5rem;
border-radius: 999px;
background: var(--color-bg-secondary);
color: var(--color-text-secondary);
border: 1px solid var(--color-border);
background: var(--fs-surface-raised);
color: var(--fs-text-secondary);
border: 1px solid var(--fs-border-color);
}
@media (max-width: 600px) {
+37 -37
View File
@@ -365,7 +365,7 @@ function cancel() {
.snippet-editor {
max-width: 760px;
margin: 2rem auto;
padding: 0 var(--page-padding-x);
padding: 0 var(--fs-layout-page-pad);
overflow-x: clip;
}
.snippet-editor h1 {
@@ -376,19 +376,19 @@ function cancel() {
display: inline-block;
margin-bottom: 1rem;
font-size: 0.85rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
text-decoration: none;
}
.back-link:hover {
color: var(--color-primary);
color: var(--fs-accent);
}
.state-msg {
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
font-size: 0.9rem;
}
.error-msg {
color: var(--color-danger);
color: var(--fs-error);
font-size: 0.9rem;
}
@@ -415,27 +415,27 @@ function cancel() {
.location-set legend {
font-size: 0.8rem;
font-weight: 500;
color: var(--color-text);
color: var(--fs-text-primary);
}
.required {
color: var(--color-danger);
color: var(--fs-error);
}
.hint {
font-size: 0.75rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
margin: 0.1rem 0 0;
}
.hint-inline {
font-weight: 400;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.input {
padding: 0.5rem 0.7rem;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
background: var(--color-bg);
color: var(--color-text);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
background: var(--fs-surface-page);
color: var(--fs-text-primary);
font-size: 0.9rem;
font-family: inherit;
box-sizing: border-box;
@@ -443,11 +443,11 @@ function cancel() {
}
.input:focus {
outline: none;
border-color: var(--color-primary);
box-shadow: var(--focus-ring);
border-color: var(--fs-accent);
box-shadow: var(--fs-focus-ring);
}
.mono {
font-family: var(--font-mono);
font-family: var(--fs-font-mono);
}
.code-area {
resize: vertical;
@@ -459,8 +459,8 @@ function cancel() {
}
.location-set {
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-lg);
padding: 0.85rem 1rem 1rem;
margin: 0;
}
@@ -477,32 +477,32 @@ function cancel() {
.loc-remove {
width: 2rem;
height: 2rem;
border: 1px solid var(--color-border);
border: 1px solid var(--fs-border-color);
background: transparent;
color: var(--color-text-muted);
border-radius: var(--radius-sm);
color: var(--fs-text-tertiary);
border-radius: var(--fs-radius-sm);
cursor: pointer;
font-size: 1.1rem;
line-height: 1;
}
.loc-remove:hover {
border-color: var(--color-danger);
color: var(--color-danger);
border-color: var(--fs-error);
color: var(--fs-error);
}
.loc-add {
margin-top: 0.15rem;
padding: 0.35rem 0.7rem;
border: 1px dashed var(--color-border);
border: 1px dashed var(--fs-border-color);
background: transparent;
color: var(--color-text-secondary);
border-radius: var(--radius-sm);
color: var(--fs-text-secondary);
border-radius: var(--fs-radius-sm);
cursor: pointer;
font-size: 0.82rem;
font-family: inherit;
}
.loc-add:hover {
border-color: var(--color-primary);
color: var(--color-primary);
border-color: var(--fs-accent);
color: var(--fs-accent);
}
@media (max-width: 600px) {
@@ -514,7 +514,7 @@ function cancel() {
.field-label {
font-size: 0.8rem;
font-weight: 500;
color: var(--color-text);
color: var(--fs-text-primary);
}
.systems {
display: flex;
@@ -528,11 +528,11 @@ function cancel() {
align-items: center;
gap: 0.45rem;
font-size: 0.85rem;
color: var(--color-text);
color: var(--fs-text-primary);
cursor: pointer;
}
.system-opt input {
accent-color: var(--color-primary);
accent-color: var(--fs-accent);
cursor: pointer;
}
@@ -541,25 +541,25 @@ function cancel() {
flex-direction: column;
gap: 0.4rem;
padding: 0.85rem 1rem;
border: 1px solid var(--color-border);
border-left: 3px solid var(--color-warning);
border: 1px solid var(--fs-border-color);
border-left: 3px solid var(--fs-warning);
border-radius: 8px;
background: var(--color-bg-secondary);
background: var(--fs-surface-raised);
}
.duplicate-title {
margin: 0;
font-size: 0.85rem;
font-weight: 500;
color: var(--color-text);
color: var(--fs-text-primary);
}
.duplicate-body {
margin: 0;
font-size: 0.8rem;
line-height: 1.5;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
}
.duplicate-body a {
color: var(--color-primary);
color: var(--fs-accent);
}
.duplicate-actions {
display: flex;
+85 -85
View File
@@ -519,9 +519,9 @@ function usageTitle(s: SnippetListItem): string {
<style scoped>
.snippets-list {
max-width: var(--page-max-width);
max-width: var(--fs-layout-page-max);
margin: 2rem auto;
padding: 0 var(--page-padding-x);
padding: 0 var(--fs-layout-page-pad);
overflow-x: clip;
}
@@ -536,7 +536,7 @@ function usageTitle(s: SnippetListItem): string {
}
.page-sub {
margin: 0 0 1.25rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
font-size: 0.9rem;
line-height: 1.5;
max-width: 60ch;
@@ -553,8 +553,8 @@ function usageTitle(s: SnippetListItem): string {
}
/* Filter is engaged — the accent marks "you are here", per the design system. */
.filter-on {
border-color: var(--color-primary);
color: var(--color-primary);
border-color: var(--fs-accent);
color: var(--fs-accent);
}
.location-row {
@@ -569,12 +569,12 @@ function usageTitle(s: SnippetListItem): string {
min-width: 0;
max-width: 12rem;
padding: 0.4rem 0.65rem;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
background: var(--color-bg);
color: var(--color-text);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
background: var(--fs-surface-page);
color: var(--fs-text-primary);
font-size: 0.85rem;
font-family: var(--font-mono);
font-family: var(--fs-font-mono);
box-sizing: border-box;
}
.loc-input-wide {
@@ -583,46 +583,46 @@ function usageTitle(s: SnippetListItem): string {
}
.loc-input::placeholder {
font-family: inherit;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.loc-input:focus {
outline: none;
border-color: var(--color-primary);
box-shadow: var(--focus-ring);
border-color: var(--fs-accent);
box-shadow: var(--fs-focus-ring);
}
.loc-clear {
padding: 0.4rem 0.65rem;
border: none;
background: transparent;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
font-size: 0.85rem;
font-family: inherit;
cursor: pointer;
text-decoration: underline;
}
.loc-clear:hover {
color: var(--color-text);
color: var(--fs-text-primary);
}
.search-input {
width: 100%;
max-width: 420px;
padding: 0.5rem 0.8rem;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
background: var(--color-bg);
color: var(--color-text);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
background: var(--fs-surface-page);
color: var(--fs-text-primary);
font-size: 0.9rem;
font-family: inherit;
box-sizing: border-box;
}
.search-input:focus {
outline: none;
border-color: var(--color-primary);
box-shadow: var(--focus-ring);
border-color: var(--fs-accent);
box-shadow: var(--fs-focus-ring);
}
.error-msg {
color: var(--color-danger);
color: var(--fs-error);
font-size: 0.9rem;
margin-top: 1rem;
}
@@ -630,10 +630,10 @@ function usageTitle(s: SnippetListItem): string {
.empty-state-rich {
text-align: center;
padding: 3rem 1rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.empty-icon {
font-family: var(--font-mono);
font-family: var(--fs-font-mono);
font-size: 2rem;
margin-bottom: 0.75rem;
opacity: 0.35;
@@ -641,7 +641,7 @@ function usageTitle(s: SnippetListItem): string {
.empty-title {
font-size: 1rem;
font-weight: 500;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
margin: 0 0 0.35rem;
}
.empty-sub {
@@ -654,16 +654,16 @@ function usageTitle(s: SnippetListItem): string {
.empty-action {
display: inline-block;
padding: 0.4rem 1rem;
border: 1px solid var(--color-action-primary);
border-radius: var(--radius-sm);
color: var(--color-action-primary);
border: 1px solid var(--fs-action-primary);
border-radius: var(--fs-radius-sm);
color: var(--fs-action-primary);
background: none;
cursor: pointer;
font-size: 0.85rem;
transition: background 0.15s, color 0.15s;
}
.empty-action:hover {
background: var(--color-action-primary);
background: var(--fs-action-primary);
color: var(--fs-text-on-action);
}
@@ -675,8 +675,8 @@ function usageTitle(s: SnippetListItem): string {
}
.skeleton-card {
height: 96px;
border-radius: var(--radius-md);
background: linear-gradient(90deg, var(--color-bg-secondary) 25%, var(--color-border) 50%, var(--color-bg-secondary) 75%);
border-radius: var(--fs-radius-lg);
background: linear-gradient(90deg, var(--fs-surface-raised) 25%, var(--fs-border-color) 50%, var(--fs-surface-raised) 75%);
background-size: 200% 100%;
animation: skeleton-shimmer 1.4s ease infinite;
}
@@ -686,9 +686,9 @@ function usageTitle(s: SnippetListItem): string {
}
.snippet-card {
background: var(--color-bg-card);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-lg);
padding: 0.9rem 1rem;
cursor: pointer;
transition: border-color 0.15s, box-shadow 0.15s, transform 0.18s ease;
@@ -697,14 +697,14 @@ function usageTitle(s: SnippetListItem): string {
gap: 0.4rem;
}
.snippet-card:hover {
border-color: var(--color-primary);
border-color: var(--fs-accent);
box-shadow: 0 2px 8px var(--color-shadow);
transform: translateY(-2px);
}
.snippet-card:focus-visible {
outline: none;
border-color: var(--color-primary);
box-shadow: var(--focus-ring);
border-color: var(--fs-accent);
box-shadow: var(--fs-focus-ring);
}
.card-header {
@@ -716,11 +716,11 @@ function usageTitle(s: SnippetListItem): string {
.snippet-name {
font-size: 0.95rem;
font-weight: 500;
color: var(--color-text);
color: var(--fs-text-primary);
min-width: 0;
flex: 1;
word-break: break-word;
font-family: var(--font-mono);
font-family: var(--fs-font-mono);
}
/* Language tag — accent pill per the design system's tag treatment. */
@@ -731,13 +731,13 @@ function usageTitle(s: SnippetListItem): string {
border-radius: 999px;
flex-shrink: 0;
white-space: nowrap;
background: color-mix(in srgb, var(--color-primary) 15%, transparent);
color: var(--color-primary);
background: color-mix(in srgb, var(--fs-accent) 15%, transparent);
color: var(--fs-accent);
}
.snippet-when {
font-size: 0.83rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
margin: 0;
line-height: 1.45;
}
@@ -751,7 +751,7 @@ function usageTitle(s: SnippetListItem): string {
}
.meta-date {
font-size: 0.73rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
/* Marks a record someone else owns. Present only on shared rows, so an
unmarked card is unambiguously the operator's own. */
@@ -760,24 +760,24 @@ function usageTitle(s: SnippetListItem): string {
padding: 0.1rem 0.4rem;
border-radius: 4px;
white-space: nowrap;
background: color-mix(in srgb, var(--color-text-muted) 15%, transparent);
color: var(--color-text-muted);
background: color-mix(in srgb, var(--fs-text-tertiary) 15%, transparent);
color: var(--fs-text-tertiary);
}
/* Near-duplicate report */
.dup-panel {
margin-bottom: 1.25rem;
padding: 0.85rem 1rem;
border: 1px solid var(--color-border);
border: 1px solid var(--fs-border-color);
border-radius: 8px;
background: var(--color-surface-alt);
background: var(--fs-surface-hover);
}
.dup-empty,
.dup-head {
margin: 0 0 0.5rem;
font-size: 0.85rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.dup-empty {
@@ -790,7 +790,7 @@ function usageTitle(s: SnippetListItem): string {
gap: 0.75rem;
flex-wrap: wrap;
padding: 0.5rem 0;
border-top: 1px solid var(--color-border);
border-top: 1px solid var(--fs-border-color);
}
.dup-members {
@@ -805,14 +805,14 @@ function usageTitle(s: SnippetListItem): string {
font-size: 0.8rem;
padding: 0.1rem 0.45rem;
border-radius: 4px;
background: color-mix(in srgb, var(--color-text-muted) 12%, transparent);
background: color-mix(in srgb, var(--fs-text-tertiary) 12%, transparent);
/* Long snippet names must not push the row into a horizontal scroll. */
overflow-wrap: anywhere;
}
.dup-score {
font-size: 0.75rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
font-variant-numeric: tabular-nums;
white-space: nowrap;
}
@@ -828,8 +828,8 @@ function usageTitle(s: SnippetListItem): string {
padding: 0.1rem 0.4rem;
border-radius: 4px;
white-space: nowrap;
background: color-mix(in srgb, var(--color-danger) 15%, transparent);
color: var(--color-danger);
background: color-mix(in srgb, var(--fs-error) 15%, transparent);
color: var(--fs-error);
}
.usage-tag {
@@ -838,15 +838,15 @@ function usageTitle(s: SnippetListItem): string {
border-radius: 4px;
white-space: nowrap;
font-variant-numeric: tabular-nums;
background: color-mix(in srgb, var(--color-text-muted) 15%, transparent);
color: var(--color-text-muted);
background: color-mix(in srgb, var(--fs-text-tertiary) 15%, transparent);
color: var(--fs-text-tertiary);
}
/* Dead weight is a nudge, not an error — it warns in the warning colour rather
than the danger one, because the record isn't broken, just unearned. */
.usage-tag.usage-dead {
background: color-mix(in srgb, var(--color-warning) 18%, transparent);
color: var(--color-warning);
background: color-mix(in srgb, var(--fs-warning) 18%, transparent);
color: var(--fs-warning);
}
/* Header + select-mode */
@@ -858,7 +858,7 @@ function usageTitle(s: SnippetListItem): string {
/* Selected card = 2px accent border per the design system (featured/active). */
.snippet-card.selected {
border-color: var(--color-primary);
border-color: var(--fs-accent);
border-width: 2px;
padding: calc(0.9rem - 1px) calc(1rem - 1px);
}
@@ -867,14 +867,14 @@ function usageTitle(s: SnippetListItem): string {
height: 16px;
flex-shrink: 0;
margin-top: 0.15rem;
border: 1px solid var(--color-border);
border: 1px solid var(--fs-border-color);
border-radius: 4px;
background: transparent;
transition: background 0.12s, border-color 0.12s;
}
.select-box.on {
background: var(--color-primary);
border-color: var(--color-primary);
background: var(--fs-accent);
border-color: var(--fs-accent);
}
.select-bar {
@@ -885,19 +885,19 @@ function usageTitle(s: SnippetListItem): string {
align-items: center;
gap: 0.75rem;
padding: 0.6rem 0.9rem;
background: var(--color-bg-card);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-lg);
box-shadow: 0 4px 16px var(--color-shadow);
}
.select-count {
font-weight: 500;
font-size: 0.9rem;
color: var(--color-text);
color: var(--fs-text-primary);
}
.select-hint {
font-size: 0.8rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
flex: 1;
min-width: 0;
}
@@ -906,16 +906,16 @@ function usageTitle(s: SnippetListItem): string {
.modal-overlay {
position: fixed;
inset: 0;
background: var(--color-overlay);
background: var(--fs-overlay);
display: flex;
align-items: center;
justify-content: center;
z-index: 200;
}
.modal-card {
background: var(--color-bg-card);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-lg);
padding: 1.5rem;
width: 100%;
max-width: 460px;
@@ -931,7 +931,7 @@ function usageTitle(s: SnippetListItem): string {
.modal-desc {
margin: 0;
font-size: 0.85rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
line-height: 1.5;
}
.merge-choices {
@@ -944,18 +944,18 @@ function usageTitle(s: SnippetListItem): string {
align-items: center;
gap: 0.6rem;
padding: 0.5rem 0.7rem;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
cursor: pointer;
}
.merge-choice.chosen {
border-color: var(--color-primary);
background: color-mix(in srgb, var(--color-primary) 8%, transparent);
border-color: var(--fs-accent);
background: color-mix(in srgb, var(--fs-accent) 8%, transparent);
}
.merge-choice-name {
flex: 1;
min-width: 0;
font-family: var(--font-mono);
font-family: var(--fs-font-mono);
font-size: 0.85rem;
word-break: break-word;
}
@@ -963,7 +963,7 @@ function usageTitle(s: SnippetListItem): string {
font-size: 0.68rem;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
flex-shrink: 0;
}
.modal-actions {
@@ -973,24 +973,24 @@ function usageTitle(s: SnippetListItem): string {
}
.modal-btn {
padding: 0.4rem 0.9rem;
border: 1px solid var(--color-border);
background: var(--color-bg-secondary);
color: var(--color-text);
border-radius: var(--radius-sm);
border: 1px solid var(--fs-border-color);
background: var(--fs-surface-raised);
color: var(--fs-text-primary);
border-radius: var(--fs-radius-sm);
cursor: pointer;
font-size: 0.875rem;
font-family: inherit;
}
.modal-btn:hover {
background: var(--color-bg);
background: var(--fs-surface-page);
}
.modal-btn-primary {
background: var(--color-action-primary);
border-color: var(--color-action-primary);
background: var(--fs-action-primary);
border-color: var(--fs-action-primary);
color: var(--fs-text-on-action);
}
.modal-btn-primary:hover:not(:disabled) {
background: var(--color-action-primary-hover);
background: var(--fs-action-primary-hover);
}
.modal-btn-primary:disabled {
opacity: 0.5;
+40 -40
View File
@@ -830,7 +830,7 @@ useEditorGuards(dirty, save);
gap: 0.75rem;
flex-wrap: wrap;
padding-bottom: 0.5rem;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
}
/* .task-main is a flex column; without flex-shrink: 0, long body content
@@ -852,7 +852,7 @@ useEditorGuards(dirty, save);
.task-sidebar {
width: 280px;
flex-shrink: 0;
border-left: 1px solid var(--color-border);
border-left: 1px solid var(--fs-border-color);
overflow-y: auto;
display: flex;
flex-direction: column;
@@ -866,21 +866,21 @@ useEditorGuards(dirty, save);
background: none;
border: none;
cursor: pointer;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
font-size: 1.1rem;
line-height: 1;
padding: 0 0.2rem;
flex-shrink: 0;
}
.btn-clear-parent:hover { color: var(--color-danger); }
.btn-clear-parent:hover { color: var(--fs-error); }
.parent-dropdown {
position: absolute;
top: calc(100% + 4px);
left: 0;
right: 0;
background: var(--color-bg-card);
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
box-shadow: 0 4px 12px var(--color-shadow);
z-index: 50;
max-height: 200px;
@@ -890,21 +890,21 @@ useEditorGuards(dirty, save);
padding: 0.4rem 0.65rem;
font-size: 0.85rem;
cursor: pointer;
color: var(--color-text);
color: var(--fs-text-primary);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.parent-dropdown-item:hover { background: var(--color-bg-secondary); }
.parent-empty { color: var(--color-text-muted); cursor: default; }
.parent-dropdown-item:hover { background: var(--fs-surface-raised); }
.parent-empty { color: var(--fs-text-tertiary); cursor: default; }
.parent-empty:hover { background: none; }
/* Sub-tasks */
.subtasks-section {
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
padding: 0.5rem 0.65rem;
background: var(--color-bg-secondary);
background: var(--fs-surface-raised);
}
.subtasks-header {
display: flex;
@@ -915,23 +915,23 @@ useEditorGuards(dirty, save);
.subtasks-label {
font-size: 0.75rem;
font-weight: 500;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
text-transform: uppercase;
letter-spacing: 0.04em;
}
.subtask-checkbox { flex-shrink: 0; cursor: pointer; }
.subtask-title {
font-size: 0.83rem;
color: var(--color-text);
color: var(--fs-text-primary);
text-decoration: none;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.subtask-title:hover { color: var(--color-primary); }
.subtask-title.done { text-decoration: line-through; color: var(--color-text-muted); }
.subtasks-empty { font-size: 0.78rem; color: var(--color-text-muted); margin: 0; }
.subtask-title:hover { color: var(--fs-accent); }
.subtask-title.done { text-decoration: line-through; color: var(--fs-text-tertiary); }
.subtasks-empty { font-size: 0.78rem; color: var(--fs-text-tertiary); margin: 0; }
.subtask-add-row {
display: flex;
align-items: center;
@@ -941,19 +941,19 @@ useEditorGuards(dirty, save);
.subtask-input {
flex: 1;
padding: 0.25rem 0.4rem;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
background: var(--color-bg);
color: var(--color-text);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
background: var(--fs-surface-page);
color: var(--fs-text-primary);
font-size: 0.83rem;
font-family: inherit;
}
.subtask-input:focus { outline: none; border-color: var(--color-primary); }
.subtask-input:focus { outline: none; border-color: var(--fs-accent); }
.stream-preview {
border: 1px solid var(--color-input-border);
border-radius: var(--radius-sm);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
padding: 0.75rem;
background: var(--color-bg-card);
background: var(--fs-surface-raised);
min-height: 200px;
}
.main-diff {
@@ -963,9 +963,9 @@ useEditorGuards(dirty, save);
/* Systems multi-select (in sidebar) */
.sb-systems { display: flex; flex-direction: column; gap: 0.25rem; max-height: 160px; overflow-y: auto; }
.sb-system-opt { display: flex; align-items: center; gap: 0.45rem; font-size: 0.85rem; color: var(--color-text); cursor: pointer; }
.sb-system-opt input { accent-color: var(--color-primary); cursor: pointer; }
.sb-systems-empty { margin: 0; font-size: 0.8rem; color: var(--color-text-muted); }
.sb-system-opt { display: flex; align-items: center; gap: 0.45rem; font-size: 0.85rem; color: var(--fs-text-primary); cursor: pointer; }
.sb-system-opt input { accent-color: var(--fs-accent); cursor: pointer; }
.sb-systems-empty { margin: 0; font-size: 0.8rem; color: var(--fs-text-tertiary); }
/* Writing Assistant section (in sidebar) */
.assist-section {
@@ -976,7 +976,7 @@ useEditorGuards(dirty, save);
.assist-section-title {
font-size: 0.78rem;
font-weight: 500;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
text-transform: uppercase;
letter-spacing: 0.05em;
}
@@ -1007,11 +1007,11 @@ useEditorGuards(dirty, save);
font-size: 0.75rem;
}
.sb-ts-label {
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
flex-shrink: 0;
}
.sb-ts-value {
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
text-align: right;
}
@@ -1022,7 +1022,7 @@ useEditorGuards(dirty, save);
.task-sidebar {
width: 100%;
border-left: none;
border-top: 1px solid var(--color-border);
border-top: 1px solid var(--fs-border-color);
overflow-y: visible;
}
}
@@ -1035,13 +1035,13 @@ useEditorGuards(dirty, save);
margin: 0.5rem 0 0.25rem;
}
.task-goal-label {
font-family: var(--font-display);
font-family: var(--fs-font-display);
font-style: italic;
font-size: 0.78rem;
font-weight: 500;
letter-spacing: 0.04em;
text-transform: uppercase;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.task-goal-input {
width: 100%;
@@ -1051,14 +1051,14 @@ useEditorGuards(dirty, save);
font: inherit;
font-size: 0.95rem;
line-height: 1.4;
color: var(--color-text);
background: var(--color-input-bg);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
color: var(--fs-text-primary);
background: var(--fs-surface-page);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-lg);
}
.task-goal-input:focus {
outline: none;
border-color: var(--color-primary);
border-color: var(--fs-accent);
}
</style>
+42 -42
View File
@@ -475,7 +475,7 @@ const subTaskProgress = computed(() => {
gap: 0.5rem;
flex-wrap: wrap;
font-size: 0.83rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
margin: 0 0 0.75rem;
}
.meta-item {
@@ -494,10 +494,10 @@ const subTaskProgress = computed(() => {
}
.due-date {
font-size: 0.85rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
}
.due-date.overdue {
color: var(--color-overdue);
color: var(--fs-overdue);
font-weight: 500;
}
.task-meta-row {
@@ -508,10 +508,10 @@ const subTaskProgress = computed(() => {
}
.task-meta-item {
font-size: 0.78rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.task-meta-recurrence {
color: var(--color-primary);
color: var(--fs-accent);
font-weight: 500;
}
.tags {
@@ -524,7 +524,7 @@ const subTaskProgress = computed(() => {
/* Sub-tasks */
.subtasks {
margin-top: 2rem;
border-top: 1px solid var(--color-border);
border-top: 1px solid var(--fs-border-color);
padding-top: 1rem;
}
.subtasks-header {
@@ -540,21 +540,21 @@ const subTaskProgress = computed(() => {
}
.subtasks-progress {
font-size: 0.8rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.subtasks-pct {
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.subtasks-track {
height: 4px;
background: var(--color-bg-secondary);
background: var(--fs-surface-raised);
border-radius: 2px;
margin-bottom: 0.75rem;
overflow: hidden;
}
.subtasks-fill {
height: 100%;
background: var(--color-status-done);
background: var(--fs-status-done);
border-radius: 2px;
transition: width 0.3s ease;
}
@@ -571,10 +571,10 @@ const subTaskProgress = computed(() => {
align-items: center;
gap: 0.5rem;
padding: 0.3rem 0.5rem;
border-radius: var(--radius-sm);
border-radius: var(--fs-radius-sm);
}
.subtask-row:hover {
background: var(--color-bg-secondary);
background: var(--fs-surface-raised);
}
.sub-dot {
flex-shrink: 0;
@@ -592,21 +592,21 @@ const subTaskProgress = computed(() => {
}
.dot-todo {
background: transparent;
border: 2px solid var(--color-text-muted);
border: 2px solid var(--fs-text-tertiary);
}
.dot-in-progress {
background: var(--color-status-in-progress);
background: var(--fs-status-in-progress);
}
.dot-done {
background: var(--color-status-done);
background: var(--fs-status-done);
}
.dot-cancelled {
background: var(--color-text-muted);
background: var(--fs-text-tertiary);
}
.sub-title {
flex: 1;
font-size: 0.9rem;
color: var(--color-text);
color: var(--fs-text-primary);
text-decoration: none;
min-width: 0;
overflow: hidden;
@@ -614,21 +614,21 @@ const subTaskProgress = computed(() => {
white-space: nowrap;
}
.sub-title:hover {
color: var(--color-primary);
color: var(--fs-accent);
}
.sub-title.sub-done {
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
text-decoration: line-through;
}
.sub-due {
font-size: 0.75rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
flex-shrink: 0;
}
.backlinks {
margin-top: 2.5rem;
border-top: 1px solid var(--color-border);
border-top: 1px solid var(--fs-border-color);
padding-top: 1.25rem;
}
.backlinks-heading {
@@ -639,14 +639,14 @@ const subTaskProgress = computed(() => {
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
margin: 0 0 0.75rem;
}
.backlinks-count {
margin-left: 0.2rem;
font-size: 0.72rem;
background: var(--color-bg-secondary);
border: 1px solid var(--color-border);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: 999px;
padding: 0 0.4rem;
line-height: 1.4;
@@ -661,18 +661,18 @@ const subTaskProgress = computed(() => {
align-items: center;
gap: 0.6rem;
padding: 0.5rem 0.75rem;
border-radius: var(--radius-md);
background: var(--color-bg-card);
border: 1px solid var(--color-border);
border-radius: var(--fs-radius-lg);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
text-decoration: none;
color: var(--color-text);
color: var(--fs-text-primary);
transition: border-color 0.15s, box-shadow 0.15s;
font-size: 0.9rem;
}
.backlink-card:hover {
border-color: color-mix(in srgb, var(--color-primary) 50%, transparent);
border-color: color-mix(in srgb, var(--fs-accent) 50%, transparent);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
color: var(--color-primary);
color: var(--fs-accent);
}
.backlink-type-badge {
font-size: 0.68rem;
@@ -684,9 +684,9 @@ const subTaskProgress = computed(() => {
flex-shrink: 0;
}
.badge-note {
background: color-mix(in srgb, var(--color-primary) 12%, transparent);
color: var(--color-primary);
border: 1px solid color-mix(in srgb, var(--color-primary) 25%, transparent);
background: color-mix(in srgb, var(--fs-accent) 12%, transparent);
color: var(--fs-accent);
border: 1px solid color-mix(in srgb, var(--fs-accent) 25%, transparent);
}
.badge-task {
background: color-mix(in srgb, #f59e0b 12%, transparent);
@@ -716,12 +716,12 @@ const subTaskProgress = computed(() => {
.skel-meta,
.skel-badges,
.skel-line {
border-radius: var(--radius-sm);
border-radius: var(--fs-radius-sm);
background: linear-gradient(
90deg,
var(--color-bg-secondary) 25%,
color-mix(in srgb, var(--color-text-muted) 18%, var(--color-bg-secondary)) 50%,
var(--color-bg-secondary) 75%
var(--fs-surface-raised) 25%,
color-mix(in srgb, var(--fs-text-tertiary) 18%, var(--fs-surface-raised)) 50%,
var(--fs-surface-raised) 75%
);
background-size: 200% 100%;
animation: skel-shine 1.5s ease infinite;
@@ -733,7 +733,7 @@ const subTaskProgress = computed(() => {
}
.skel-btn { width: 70px; height: 32px; }
.skel-btn--wide { width: 90px; }
.skel-title { height: 2.2rem; width: 65%; border-radius: var(--radius-md); }
.skel-title { height: 2.2rem; width: 65%; border-radius: var(--fs-radius-lg); }
.skel-meta { height: 0.85rem; width: 45%; }
.skel-badges { height: 1.6rem; width: 30%; border-radius: 999px; }
.skel-line { height: 0.9rem; }
@@ -742,26 +742,26 @@ const subTaskProgress = computed(() => {
/* ── Goal block + auto-summary banner ─────────────────────────────────────── */
.task-goal-display {
border-left: 2px solid var(--color-border);
border-left: 2px solid var(--fs-border-color);
padding: 0.4rem 0 0.4rem 0.9rem;
margin: 0.75rem 0 1.25rem;
background: rgba(255, 255, 255, 0.02);
}
.goal-label {
font-family: var(--font-display);
font-family: var(--fs-font-display);
font-style: italic;
font-size: 0.78rem;
font-weight: 500;
letter-spacing: 0.04em;
text-transform: uppercase;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
margin: 0 0 0.25rem;
}
.goal-text {
margin: 0;
font-size: 0.95rem;
line-height: 1.45;
color: var(--color-text);
color: var(--fs-text-primary);
white-space: pre-wrap;
}
</style>
+3 -3
View File
@@ -68,7 +68,7 @@ onMounted(() => store.fetchTrash());
.batch-count { opacity: 0.6; font-weight: 400; font-size: 0.9em; margin-left: 0.35rem; }
.batch-meta { font-size: 0.82em; opacity: 0.6; margin-top: 0.25rem; }
.batch-actions { display: flex; gap: 0.5rem; flex-shrink: 0; }
.batch-actions button { border-radius: 6px; padding: 0.35rem 0.7rem; cursor: pointer; border: 1px solid var(--color-border); background: none; color: inherit; }
.btn-restore:hover { border-color: var(--color-action-primary); color: var(--color-action-primary); }
.btn-purge:hover { border-color: var(--color-action-destructive); color: var(--color-action-destructive); }
.batch-actions button { border-radius: 6px; padding: 0.35rem 0.7rem; cursor: pointer; border: 1px solid var(--fs-border-color); background: none; color: inherit; }
.btn-restore:hover { border-color: var(--fs-action-primary); color: var(--fs-action-primary); }
.btn-purge:hover { border-color: var(--fs-action-destructive); color: var(--fs-action-destructive); }
</style>
+29 -29
View File
@@ -297,9 +297,9 @@ function formatDate(iso: string): string {
margin: 0 0 1.5rem;
}
.settings-section {
background: var(--color-bg-card);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
background: var(--fs-surface-raised);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-lg);
padding: 1.25rem;
margin-bottom: 1.5rem;
}
@@ -317,16 +317,16 @@ function formatDate(iso: string): string {
.invite-input {
flex: 1;
padding: 0.5rem 0.75rem;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-sm);
font-size: 0.95rem;
background: var(--color-bg);
color: var(--color-text);
background: var(--fs-surface-page);
color: var(--fs-text-primary);
box-sizing: border-box;
}
.invite-input:focus {
outline: none;
border-color: var(--color-primary);
border-color: var(--fs-accent);
}
.invite-list {
margin-top: 1rem;
@@ -334,7 +334,7 @@ function formatDate(iso: string): string {
.invite-list h3 {
margin: 0 0 0.5rem;
font-size: 0.95rem;
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
}
/* Registration toggle */
@@ -352,33 +352,33 @@ function formatDate(iso: string): string {
font-size: 0.95rem;
}
.text-success {
color: var(--color-success);
color: var(--fs-success);
}
.text-muted {
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
.field-hint {
margin: 0.35rem 0 0;
font-size: 0.8rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
/* The one genuine override: 'close registration' must NOT read as the
primary action it sits on. Scoped, so it beats the shared variant. */
.btn-toggle-close {
background: var(--color-bg-secondary);
color: var(--color-text);
border: 1px solid var(--color-border);
background: var(--fs-surface-raised);
color: var(--fs-text-primary);
border: 1px solid var(--fs-border-color);
}
.btn-toggle-close:hover:not(:disabled) {
border-color: var(--color-warning);
color: var(--color-warning);
border-color: var(--fs-warning);
color: var(--fs-warning);
}
/* Users table */
.loading-msg,
.empty-msg {
text-align: center;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
font-size: 0.9rem;
padding: 1rem 0;
}
@@ -392,13 +392,13 @@ function formatDate(iso: string): string {
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
padding: 0.5rem 0.75rem;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
}
.users-table td {
padding: 0.65rem 0.75rem;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--fs-border-color);
font-size: 0.9rem;
}
.users-table tbody tr:last-child td {
@@ -408,10 +408,10 @@ function formatDate(iso: string): string {
font-weight: 600;
}
.cell-email {
color: var(--color-text-secondary);
color: var(--fs-text-secondary);
}
.cell-date {
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
font-size: 0.85rem;
}
.cell-actions {
@@ -426,21 +426,21 @@ function formatDate(iso: string): string {
text-transform: uppercase;
letter-spacing: 0.05em;
padding: 0.15rem 0.4rem;
border-radius: var(--radius-sm);
border-radius: var(--fs-radius-sm);
}
.role-admin {
color: var(--color-primary);
background: color-mix(in srgb, var(--color-primary) 15%, transparent);
color: var(--fs-accent);
background: color-mix(in srgb, var(--fs-accent) 15%, transparent);
}
.role-user {
color: var(--color-text-muted);
background: var(--color-bg-secondary);
color: var(--fs-text-tertiary);
background: var(--fs-surface-raised);
}
/* Action buttons */
.you-label {
font-size: 0.8rem;
color: var(--color-text-muted);
color: var(--fs-text-tertiary);
}
@media (max-width: 768px) {
+8 -3
View File
@@ -32,10 +32,15 @@ async def list_notes(
) -> dict:
"""List notes (non-task documents) stored in Scribe.
Optionally filter by a single tag (plain string, no # prefix) or a keyword
search against title and body. Results are ordered by last-updated descending.
Optionally filter by a single tag (plain string, no # prefix) or by
`search_text`, which matches on MEANING — the same semantic match every
search surface uses (#2462; keyword ILIKE is only the fallback when the
embedder is down). With `search_text`, results order by relevance; without
it, by last-updated descending. Reaches your records plus shared-project
records, like every other list.
Use search for semantic/meaning-based lookup instead of exact keyword search.
Prefer `search` for a pure lookup — it returns scores and reaches
everything readable; this adds the lifecycle filters on top.
Args:
project_id: Scope to one project. PASS THE ACTIVE PROJECT'S ID whenever a
+13
View File
@@ -24,6 +24,7 @@ from scribe.services import projects as projects_svc
from scribe.services import rulebooks as rulebooks_svc
from scribe.services import systems as systems_svc
from scribe.services import trash as trash_svc
from scribe.services.note_usage import record_surfaced
async def list_projects() -> dict:
@@ -94,6 +95,18 @@ async def enter_project(project_id: int) -> dict:
# agent when it writes — which it never was, and tagging stopped within
# three days of the feature landing (#2546's audit).
systems = await systems_svc.list_systems(uid, project_id)
# Probably the largest surfacing by volume, and it emitted nothing — so
# the pulls it caused floated unattributed and the surfaced:pulled ratio
# ran against a denominator missing its biggest contributor (#2477). An
# AMBIENT source: these are top-N-by-recency, not a ranked choice, and the
# readout counts them apart so dead-weight detection isn't poisoned by
# "recently updated in a project you opened".
record_surfaced(
user_id=uid,
note_ids=[int(t.id) for t in open_tasks] + [int(n.id) for n in recent_notes],
source="enter_project",
)
# A project need not have one, and most installs won't — null is ordinary
# here, not a missing prerequisite.
design_system = None
+12 -8
View File
@@ -4,12 +4,14 @@ from quart import Blueprint, jsonify, request
from scribe.auth import login_required, get_current_user_id
from scribe.services.access import owner_names_for
from scribe.services.embeddings import (
INTERACTIVE_SEARCH_THRESHOLD as _REST_SEARCH_THRESHOLD,
)
from scribe.services.embeddings import semantic_search_notes
from scribe.services.retrieval_telemetry import record_retrieval
# This route searches with a looser floor than the MCP tool default — it powers
# an interactive feed where loosely-related hits still have value.
_REST_SEARCH_THRESHOLD = 0.3
# The interactive floor lives in embeddings.py now, shared with Browse search
# and the list views' semantic `q` — one number, one rationale (#2463).
search_bp = Blueprint("search", __name__, url_prefix="/api/search")
@@ -34,22 +36,24 @@ async def search_route():
content_type = request.args.get("content_type", "all")
limit = min(request.args.get("limit", 10, type=int), 50)
is_task = _content_type_to_is_task(content_type)
# Same association filter the MCP tool takes (#33). The project filter this
# route is still missing is #2463's — it carries a default-scope UI decision
# this change must not preempt.
# Same association filters the MCP tool takes (#33). Optional, default
# global: this route has NO frontend consumer today (measured 2026-08-08 —
# the web UI searches through /api/knowledge), so it serves API callers,
# and an API caller states its scope explicitly.
system_id = request.args.get("system_id", type=int)
project_id = request.args.get("project_id", type=int)
t0 = time.perf_counter()
results = await semantic_search_notes(
uid, q, limit=limit, is_task=is_task, threshold=_REST_SEARCH_THRESHOLD,
system_id=system_id,
project_id=project_id, system_id=system_id,
# The user typed this, so it reaches everything they may read.
scope="read",
)
record_retrieval(
user_id=uid, source="rest_search", query=q,
threshold=_REST_SEARCH_THRESHOLD, limit=limit,
project_id=None, is_task=is_task, results=results,
project_id=project_id, is_task=is_task, results=results,
duration_ms=(time.perf_counter() - t0) * 1000.0,
)
owners = await owner_names_for(
+9
View File
@@ -31,6 +31,15 @@ logger = logging.getLogger(__name__)
# loosely-related results that pad the sidebar without adding real value.
_SIMILARITY_THRESHOLD = 0.45
# The floor for INTERACTIVE, human-facing feeds — REST /api/search, Browse
# search, and the list views' semantic `q`. Deliberately looser than the agent
# default above: a human scanning a result list gets value from loosely-related
# hits an agent would be misled by. One constant, because this number was
# written as `0.3` in two files with the reasoning attached to only one of
# them — the exact shape where a later tuner moves one and not the other
# (#2463 finding 3).
INTERACTIVE_SEARCH_THRESHOLD = 0.3
# Public alias so callers (and telemetry) can record the effective default
# threshold without reaching for the underscored name.
DEFAULT_SIMILARITY_THRESHOLD = _SIMILARITY_THRESHOLD
+22 -2
View File
@@ -396,17 +396,37 @@ async def _semantic_knowledge_search(
# case a semantic search exists to serve.
semantic_notes: list[Note] = []
try:
from scribe.services.embeddings import semantic_search_notes
from scribe.services.embeddings import (
INTERACTIVE_SEARCH_THRESHOLD,
semantic_search_notes,
)
is_task_filter = True if note_type in ("task", "plan") else (False if note_type else None)
import time as _time
_t0 = _time.perf_counter()
candidates = await semantic_search_notes(
user_id=user_id,
scope="read",
query=q,
limit=min(200, limit * 4),
threshold=0.3,
# The shared interactive floor — this was a bare `0.3` while
# routes/search.py had the same number as a commented constant, the
# exact pair where one moves and the other doesn't (#2463).
threshold=INTERACTIVE_SEARCH_THRESHOLD,
is_task=is_task_filter,
project_id=project_id,
)
# The human's MAIN search surface, and it logged nothing — so
# retrieval_logs claimed the web's search was /api/search, a narrower
# path with (measured) zero frontend consumers. Distinct source, so
# threshold tuning can include or exclude human queries deliberately
# rather than by accident (#2463).
from scribe.services.retrieval_telemetry import record_retrieval
record_retrieval(
user_id=user_id, source="browse_search", query=q,
threshold=INTERACTIVE_SEARCH_THRESHOLD, limit=min(200, limit * 4),
project_id=project_id, is_task=is_task_filter, results=candidates,
duration_ms=(_time.perf_counter() - _t0) * 1000.0,
)
for _score, note in candidates:
if note.deleted_at is not None:
continue
+43 -6
View File
@@ -26,7 +26,7 @@ from __future__ import annotations
import asyncio
import logging
from sqlalchemy import func, select
from sqlalchemy import case, func, select
from scribe.models import async_session
from scribe.models.note_usage import PULLED, SURFACED, NoteUsageEvent
@@ -96,14 +96,30 @@ def record_pulled(*, user_id: int | None, note_id: int, source: str) -> None:
_schedule(rows)
# Surfacings that are NOT a ranked choice. enter_project returns whatever the
# top-N-by-recency happen to be; the skill sync installs every Process the
# operator can reach. Counting those alongside auto-inject would make a note's
# surfaced_count dominated by "it was recently updated in a project you
# opened", and dead-weight detection would read that as popularity (#2477).
# They still matter — a pull that follows one must not float unattributed — so
# they land in their own bucket rather than not landing at all.
AMBIENT_SOURCES = ("enter_project", "process_skill_sync")
def empty_usage() -> dict:
"""The zero readout — what a note with no recorded events looks like.
Callers render this shape unconditionally, so a note predating the table
reads as "never surfaced, never pulled" rather than as a missing key.
`surfaced_count` is RANKED surfacings only — a scored surface chose this
record. `ambient_count` is the rest (see AMBIENT_SOURCES). The split is the
readout half of #2477: the "high surfaced, zero pulls → dead weight"
reading is only valid over surfacings that were choices.
"""
return {
"surfaced_count": 0,
"ambient_count": 0,
"pull_count": 0,
"last_surfaced_at": None,
"last_pulled_at": None,
@@ -132,9 +148,23 @@ async def usage_for_notes(note_ids: list[int]) -> dict[int, dict]:
NoteUsageEvent.event,
func.count().label("n"),
func.max(NoteUsageEvent.created_at).label("last_at"),
# Classified in SQL so the group count stays small: per
# note we get at most (surfaced-ranked, surfaced-ambient,
# pulled) rather than one row per distinct source.
case(
(NoteUsageEvent.source.in_(AMBIENT_SOURCES), True),
else_=False,
).label("ambient"),
)
.where(NoteUsageEvent.note_id.in_(ids))
.group_by(NoteUsageEvent.note_id, NoteUsageEvent.event)
.group_by(
NoteUsageEvent.note_id,
NoteUsageEvent.event,
case(
(NoteUsageEvent.source.in_(AMBIENT_SOURCES), True),
else_=False,
),
)
)
).all()
except Exception:
@@ -142,14 +172,21 @@ async def usage_for_notes(note_ids: list[int]) -> dict[int, dict]:
logger.debug("note usage readout failed", exc_info=True)
return out
for note_id, event, n, last_at in rows:
for note_id, event, n, last_at, ambient in rows:
slot = out.get(int(note_id))
if slot is None:
continue
if event == SURFACED:
if event == SURFACED and ambient:
slot["ambient_count"] = int(n)
elif event == SURFACED:
slot["surfaced_count"] = int(n)
slot["last_surfaced_at"] = last_at.isoformat() if last_at else None
elif event == PULLED:
slot["pull_count"] = int(n)
slot["last_pulled_at"] = last_at.isoformat() if last_at else None
# Pulls are pulls regardless of what surfaced the record — the
# question a pull answers ("did anyone ever open this?") doesn't
# depend on how it was found.
slot["pull_count"] = slot["pull_count"] + int(n)
latest = last_at.isoformat() if last_at else None
if latest and (slot["last_pulled_at"] or "") < latest:
slot["last_pulled_at"] = latest
return out
+59 -13
View File
@@ -188,10 +188,32 @@ async def list_notes(
limit: int = 50,
offset: int = 0,
) -> tuple[list[Note], int]:
"""Lifecycle-shaped listing. Two contracts worth knowing:
VISIBILITY is the shared browse clause (#47, #2462): the caller's own
records plus anything in a project they can reach — the same reach
query_knowledge has always had. Before this, list_notes was silently
owner-only, so a task in a shared project was invisible in list_tasks,
enter_project's open-task list and the web UI while the same project's
notes appeared. Browse, not read, per decision #2094: an ambient list must
never surface a record someone shared one-to-one — those stay search-only.
`q` is SEMANTIC (operator decision, 2026-08-06: "make it match") — the same
meaning-based match as Browse search, at the interactive floor. When `q` is
present, relevance ordering wins and `sort` is ignored; a query is a
relevance claim and sorting its results by date would shuffle the answer.
Falls back to ILIKE substring match only when the embedder is unavailable —
degraded but never empty. Superseded records are not demoted here: the
penalty reorders a top-k, and reordering a paginated, counted list would
make page boundaries lie. The search surfaces carry the demotion.
"""
from scribe.services.access import notes_visibility_clause
visible = notes_visibility_clause(user_id, "browse")
async with async_session() as session:
query = select(Note).where(Note.user_id == user_id, Note.deleted_at.is_(None))
query = select(Note).where(visible, Note.deleted_at.is_(None))
count_query = select(func.count(Note.id)).where(
Note.user_id == user_id, Note.deleted_at.is_(None)
visible, Note.deleted_at.is_(None)
)
# Filter by task vs note
@@ -202,14 +224,34 @@ async def list_notes(
query = query.where(Note.status.is_(None))
count_query = count_query.where(Note.status.is_(None))
semantic_order = None
if q:
terms = _strip_type_nouns(q)
for term in terms:
escaped_term = term.replace("\\", "\\\\").replace("%", "\\%").replace("_", "\\_")
pattern = f"%{escaped_term}%"
term_filter = or_(Note.title.ilike(pattern), Note.body.ilike(pattern))
query = query.where(term_filter)
count_query = count_query.where(term_filter)
query_vec = None
try:
from scribe.services.embeddings import get_embedding
query_vec = await get_embedding(q)
except Exception:
query_vec = None # embedder down → keyword fallback below
if query_vec is not None:
from scribe.models.embedding import NoteEmbedding
from scribe.services.embeddings import INTERACTIVE_SEARCH_THRESHOLD
distance = NoteEmbedding.embedding.cosine_distance(query_vec)
sem_filter = distance <= (1.0 - INTERACTIVE_SEARCH_THRESHOLD)
query = query.join(
NoteEmbedding, NoteEmbedding.note_id == Note.id
).where(sem_filter)
count_query = count_query.join(
NoteEmbedding, NoteEmbedding.note_id == Note.id
).where(sem_filter)
semantic_order = distance.asc()
else:
terms = _strip_type_nouns(q)
for term in terms:
escaped_term = term.replace("\\", "\\\\").replace("%", "\\%").replace("_", "\\_")
pattern = f"%{escaped_term}%"
term_filter = or_(Note.title.ilike(pattern), Note.body.ilike(pattern))
query = query.where(term_filter)
count_query = count_query.where(term_filter)
if tags:
for i, tag in enumerate(tags):
@@ -275,11 +317,15 @@ async def list_notes(
query = query.where(paused_filter)
count_query = count_query.where(paused_filter)
sort_col = getattr(Note, sort, Note.updated_at)
if order == "asc":
query = query.order_by(sort_col.asc())
if semantic_order is not None:
# A query is a relevance claim — see the docstring.
query = query.order_by(semantic_order)
else:
query = query.order_by(sort_col.desc())
sort_col = getattr(Note, sort, Note.updated_at)
if order == "asc":
query = query.order_by(sort_col.asc())
else:
query = query.order_by(sort_col.desc())
query = query.limit(limit).offset(offset)
+25
View File
@@ -243,6 +243,19 @@ async def build_process_manifest(user_id: int) -> dict:
entry["shared"] = True
entry["owner"] = it.get("owner")
procs.append(entry)
# The most consequential passive surface Scribe has (see SCOPE above), and
# it emitted nothing — a Process installed as a skill, matched on every
# relevant turn and never once opened, was indistinguishable from one never
# installed (#2477). The honest event is "installed on the operator's
# machine", which is a surfacing in effect: the skill description is in
# front of the model each session. AMBIENT source — installation is not a
# ranked choice — so it lands in ambient_count, not surfaced_count.
record_surfaced(
user_id=user_id,
note_ids=[int(p["id"]) for p in procs],
source="process_skill_sync",
)
return {"processes": procs, "total": len(procs)}
@@ -326,6 +339,7 @@ async def _reserve_slot_for_reuse(
return kept # reuse already represented; nothing to do
top_k = cfg["top_k"]
_t0 = time.perf_counter()
reuse = await semantic_search_notes(
user_id, query,
limit=1,
@@ -335,6 +349,17 @@ async def _reserve_slot_for_reuse(
note_type=_REUSE_KINDS,
scope="browse",
)
# A real semantic query competing for a menu slot — logged like the scored
# arm it displaces. Before this, the hit it PUSHED OUT was in
# retrieval_logs and the query that pushed it out was not, so the slot
# could never be evaluated against what it replaced (#2463; #1038 and
# #2085 are gated on this ledger being complete).
record_retrieval(
user_id=user_id, source="reuse_slot", query=query,
threshold=cfg["threshold"], limit=1, project_id=project_id,
is_task=None, results=reuse,
duration_ms=(time.perf_counter() - _t0) * 1000.0,
)
# Verify the kind rather than trusting the query that asked for it, and
# dedup on top of exclude_ids. This slot exists FOR reuse kinds — a slot
# silently spent on something else is worse than no slot, because the line
+11 -1
View File
@@ -113,7 +113,13 @@ async def test_usage_for_notes_splits_counts_by_event():
from datetime import datetime, timezone
ts = datetime(2026, 7, 28, tzinfo=timezone.utc)
rows = [(3, "surfaced", 9, ts), (3, "pulled", 2, ts)]
# Rows are (note_id, event, count, last_at, ambient) since #2477 split the
# readout. Ranked and ambient surfacings arrive as separate groups.
rows = [
(3, "surfaced", 9, ts, False),
(3, "surfaced", 40, ts, True),
(3, "pulled", 2, ts, False),
]
session = MagicMock()
session.execute = AsyncMock(
return_value=MagicMock(all=MagicMock(return_value=rows))
@@ -123,7 +129,11 @@ async def test_usage_for_notes_splits_counts_by_event():
ctx.__aexit__ = AsyncMock(return_value=False)
with patch.object(note_usage, "async_session", return_value=ctx):
out = await usage_for_notes([3])
# The dead-weight reading ("surfaced often, never pulled") is only valid
# over surfacings that were CHOICES. 40 enter_project appearances must not
# make a record look popular — they sit in ambient_count (#2477).
assert out[3]["surfaced_count"] == 9
assert out[3]["ambient_count"] == 40
assert out[3]["pull_count"] == 2
assert out[3]["last_pulled_at"] == ts.isoformat()
+43
View File
@@ -202,3 +202,46 @@ async def test_injected_menu_labels_the_record_kind():
assert "body" not in out["context"]
# The header can't claim they're all notes when the markers say otherwise.
assert "Scribe records" in lines[0]
def test_list_shaped_services_use_the_shared_visibility_clause():
"""Every service that LISTS notes must declare its reach through
notes_visibility_clause / browsable_notes_clause — never a bare owner
filter (#47, #2462).
Source inspection, because this is the shape no behavioural test catches:
an owner-only list returns correct-looking rows and simply omits the shared
ones, which is how list_notes shipped owner-only for months while
query_knowledge beside it was deliberately browse-scoped. A task in a
shared project was invisible in list_tasks, enter_project and the web UI
while the same project's notes appeared.
"""
import ast
import inspect
import textwrap
from scribe.services import knowledge, notes
for fn, label in ((notes.list_notes, "notes.list_notes"),
(knowledge.query_knowledge, "knowledge.query_knowledge")):
source = textwrap.dedent(inspect.getsource(fn))
assert (
"notes_visibility_clause" in source
or "browsable_notes_clause" in source
), (
f"{label} does not reference a shared visibility clause — a bare "
f"owner filter silently hides shared-project records (#2462)"
)
# And it must not ALSO carry a bare owner filter on the main query,
# which would quietly re-narrow whatever the clause granted.
tree = ast.parse(source)
for node in ast.walk(tree):
if (isinstance(node, ast.Compare)
and isinstance(node.left, ast.Attribute)
and node.left.attr == "user_id"
and isinstance(node.left.value, ast.Name)
and node.left.value.id == "Note"):
raise AssertionError(
f"{label} compares Note.user_id directly — reach must come "
f"from the shared clause, not a bare owner filter"
)
+6 -3
View File
@@ -104,9 +104,12 @@ async def test_build_autoinject_hint_titles_only_with_margin_gate():
assert "#33" not in out["context"]
# Title-first: no body text, ever.
assert "get_note(id)" in out["context"]
# Telemetry fired with the auto_inject source and the full candidate set.
rec.assert_called_once()
assert rec.call_args.kwargs["source"] == "auto_inject"
# Telemetry fired for BOTH retrievals this path runs: the scored menu and
# the reuse-slot query competing against it. The slot's query used to be
# the one unlogged retrieval on this path — the hit it displaced was in
# retrieval_logs, the query that displaced it was not (#2463).
sources = [c.kwargs["source"] for c in rec.call_args_list]
assert sources == ["auto_inject", "reuse_slot"]
@pytest.mark.asyncio