ruvnet-brain 4.0.1 → 4.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -0
- package/README.md +4 -4
- package/bin/install.mjs +303 -24
- package/console/CONTRACT.md +172 -0
- package/console/activity.js +753 -0
- package/console/app.js +4189 -0
- package/console/architecture.html +1221 -0
- package/console/assets/depth-1.webp +0 -0
- package/console/assets/depth-2.webp +0 -0
- package/console/assets/depth-3.webp +0 -0
- package/console/assets/harness-vs-plain.svg +259 -0
- package/console/assets/hero.webp +0 -0
- package/console/assets/memory.webp +0 -0
- package/console/assets/metaharness.svg +247 -0
- package/console/index.html +777 -0
- package/console/install-architecture.html +162 -0
- package/console/install-mockup.html +543 -0
- package/console/style.css +2144 -0
- package/console/tips.css +926 -0
- package/console/tips.html +858 -0
- package/console/tips.js +128 -0
- package/docs/RELEASE-NOTES-4.0.md +88 -0
- package/kb/model-requirements.mjs +37 -6
- package/keys/ruvnet-brain-signing.pub.pem +3 -0
- package/package.json +8 -22
- package/plugin/.claude-plugin/marketplace.json +1 -0
- package/plugin/.claude-plugin/plugin.json +2 -3
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/commands/brain-console.md +2 -2
- package/plugin/commands/configure.md +3 -2
- package/plugin/commands/rvbc.md +4 -3
- package/plugin/commands/rvcb.md +2 -2
- package/plugin/commands/whats-new.md +6 -6
- package/plugin/docs/RELEASE-NOTES-4.0.md +88 -0
- package/plugin/hooks/hooks.json +1 -2
- package/plugin/mcp/managed-cli-interface.mjs +47 -4
- package/plugin/mcp/server.mjs +90 -32
- package/plugin/scripts/detach.mjs +14 -0
- package/plugin/scripts/first-session-worker.mjs +38 -0
- package/plugin/scripts/ground-ruvnet.sh +16 -6
- package/plugin/scripts/hook-shim.mjs +34 -29
- package/plugin/scripts/learn-capture.sh +22 -3
- package/plugin/scripts/learn-flush.mjs +21 -4
- package/plugin/scripts/runtime-preferences.mjs +269 -0
- package/plugin/scripts/session-start-core.mjs +503 -0
- package/plugin/scripts/session-start.sh +3 -858
- package/plugin/scripts/whats-new.mjs +42 -0
- package/plugin/skills/brain-console/SKILL.md +4 -2
- package/plugin/skills/release-proof/SKILL.md +98 -0
- package/plugin/skills/release-proof/agents/openai.yaml +4 -0
- package/plugin/skills/release-proof/references/receipt-contract.md +44 -0
- package/plugin/skills/release-proof/scripts/release-proof.mjs +286 -0
- package/plugin/skills/ruvnet-brain/PLAYBOOK.md +5 -1
- package/plugin/skills/ruvnet-brain/SKILL.md +22 -7
- package/plugin/skills/rvbc/SKILL.md +9 -6
- package/plugin/skills/whats-new/SKILL.md +4 -4
- package/scripts/adr-backfill.mjs +107 -0
- package/scripts/advocacy-outcomes.mjs +808 -0
- package/scripts/agentdb-context.mjs +216 -0
- package/scripts/agentdb-fleet-doctor.mjs +101 -0
- package/scripts/ascii-drift.mjs +236 -0
- package/scripts/behavioral-l1-l4.mjs +210 -0
- package/scripts/brain-capability-check.mjs +72 -0
- package/scripts/brain-grade-groundtruth.mjs +100 -0
- package/scripts/brain-latency-50.mjs +227 -0
- package/scripts/brain-novice-50.mjs +189 -0
- package/scripts/brain-stamp.mjs +94 -0
- package/scripts/brain-state.mjs +212 -0
- package/scripts/build-bundle.mjs +531 -0
- package/scripts/build-concepts.mjs +132 -0
- package/scripts/build-l2.mjs +71 -0
- package/scripts/build-primer.mjs +73 -0
- package/scripts/build-symbols.mjs +68 -0
- package/scripts/calibrate-router.mjs +97 -0
- package/scripts/capability-audit.mjs +321 -0
- package/scripts/capability-registry.mjs +876 -0
- package/scripts/check-indexation.mjs +108 -0
- package/scripts/check-legibility.mjs +189 -0
- package/scripts/ci/build-fixture-kb.mjs +67 -0
- package/scripts/ci/learning-replay-codex-adapter.mjs +62 -0
- package/scripts/ci/learning-replay-recorder.mjs +59 -0
- package/scripts/ci/mutate-hook-timeout.mjs +70 -0
- package/scripts/ci/stranger-fixture-stage.mjs +17 -0
- package/scripts/ci/stranger-scenario.mjs +228 -0
- package/scripts/ci/stranger-timeout.mjs +25 -0
- package/scripts/ci-verdict.mjs +29 -0
- package/scripts/claims-verify.mjs +710 -0
- package/scripts/clear-claude-tmp.sh +31 -0
- package/scripts/console-engine.mjs +434 -0
- package/scripts/console-engine.test.mjs +125 -0
- package/scripts/corpus-qa.mjs +250 -0
- package/scripts/correction-detect-embed.mjs +346 -0
- package/scripts/correction-detect-measure.mjs +270 -0
- package/scripts/correction-detect.mjs +686 -0
- package/scripts/count-chunks.mjs +54 -0
- package/scripts/described-questions.json +30 -0
- package/scripts/design-grade.mjs +58 -0
- package/scripts/dev-plugin-link.sh +105 -0
- package/scripts/distill-project.mjs +200 -0
- package/scripts/doc-currency.mjs +801 -0
- package/scripts/eval-brain.mjs +244 -0
- package/scripts/fix-metaharness-memretrieve.mjs +121 -0
- package/scripts/fix-workstream.mjs +291 -0
- package/scripts/full-hints.mjs +87 -0
- package/scripts/gate.sh +39 -0
- package/scripts/gates.mjs +146 -0
- package/scripts/gen-console-images.mjs +54 -0
- package/scripts/gen-images.mjs +47 -0
- package/scripts/git-clone-refresh.mjs +52 -0
- package/scripts/git-hooks/pre-push +126 -0
- package/scripts/goal-match.mjs +398 -0
- package/scripts/goldie-research.mjs +223 -0
- package/scripts/goldie-weekly.sh +67 -0
- package/scripts/health-repair.mjs +237 -0
- package/scripts/helix-scenario-questions.json +10 -0
- package/scripts/ingest-gists.mjs +230 -0
- package/scripts/ingest-meeting.mjs +115 -0
- package/scripts/ingest-repo.mjs +79 -0
- package/scripts/install-npx-witness.sh +49 -0
- package/scripts/issue-fix.mjs +558 -0
- package/scripts/issue-watch.mjs +276 -0
- package/scripts/issue4-close-note.md +31 -0
- package/scripts/key-canary.mjs +91 -0
- package/scripts/latency-to-surface.mjs +233 -0
- package/scripts/learning-enable.mjs +380 -0
- package/scripts/learning-replay.mjs +1570 -0
- package/scripts/learnings.mjs +62 -0
- package/scripts/lesson-gate.mjs +680 -0
- package/scripts/lesson-lifecycle.mjs +449 -0
- package/scripts/lesson-promote.mjs +262 -0
- package/scripts/lesson-ratify.mjs +98 -0
- package/scripts/lesson-seed.mjs +252 -0
- package/scripts/lesson-store.mjs +447 -0
- package/scripts/loop-checkpoint.mjs +86 -0
- package/scripts/memdb-health.sh +14 -0
- package/scripts/memory-doctor.mjs +326 -0
- package/scripts/model-catalog.mjs +79 -0
- package/scripts/nightly-controller.mjs +66 -0
- package/scripts/nightly-gists.sh +72 -0
- package/scripts/nightly-wrapper.sh +172 -0
- package/scripts/notify.sh +12 -0
- package/scripts/npx-witness.sh +56 -0
- package/scripts/onboarding-console.mjs +2922 -0
- package/scripts/private-fence.mjs +69 -0
- package/scripts/proactivity-metrics.mjs +118 -0
- package/scripts/proof-questions.json +56 -0
- package/scripts/protected-release-invocation.mjs +76 -0
- package/scripts/prove.mjs +95 -0
- package/scripts/proxy/claude-proxied.sh +57 -0
- package/scripts/proxy/proxy-revert.sh +59 -0
- package/scripts/proxy/proxy-up.sh +60 -0
- package/scripts/proxy/proxy-verify.mjs +142 -0
- package/scripts/publication-receipt.mjs +307 -0
- package/scripts/published-surface-probe.mjs +241 -0
- package/scripts/qe/card-lane-gate.mjs +162 -0
- package/scripts/qe/session-start-gate.mjs +229 -0
- package/scripts/qe/ux-suite.mjs +323 -0
- package/scripts/reconcile-project.mjs +0 -0
- package/scripts/record-lesson.mjs +113 -0
- package/scripts/refresh-model-catalog.mjs +99 -0
- package/scripts/release-authority.mjs +93 -0
- package/scripts/release-proof.mjs +9 -0
- package/scripts/release-vector.mjs +281 -0
- package/scripts/release.mjs +439 -0
- package/scripts/remedy-registry.mjs +247 -0
- package/scripts/rerank-cap-eval.mjs +265 -0
- package/scripts/rerank-cap-warm-ab.mjs +129 -0
- package/scripts/route-cheap.mjs +20 -15
- package/scripts/router-utilization.mjs +182 -0
- package/scripts/routing-flywheel.mjs +596 -0
- package/scripts/rvf-generation.mjs +104 -0
- package/scripts/rvf-index-audit.mjs +138 -0
- package/scripts/self-update.mjs +296 -0
- package/scripts/selfcheck.mjs +7 -1
- package/scripts/sign-bundle.mjs +69 -0
- package/scripts/signal-watch.mjs +171 -0
- package/scripts/stabilization-receipt.mjs +108 -0
- package/scripts/stack-sync.mjs +469 -0
- package/scripts/stamp-existing-rvf-generations.mjs +53 -0
- package/scripts/stamp-sweep.mjs +144 -0
- package/scripts/status-honesty.mjs +102 -0
- package/scripts/sync-version.mjs +217 -0
- package/scripts/token-report.mjs +102 -0
- package/scripts/top100-benchmark.mjs +479 -0
- package/scripts/top100-corpus.mjs +112 -0
- package/scripts/top100-semantic-assertions.mjs +449 -0
- package/scripts/update-apply.mjs +9 -0
- package/scripts/upgrade-notice.mjs +14 -0
- package/scripts/verify-bundle.mjs +51 -0
- package/scripts/verify-channels.mjs +184 -0
- package/scripts/verify-model-catalog.mjs +104 -0
- package/scripts/verify-nightly-close-issue4.sh +31 -0
- package/scripts/version.mjs +40 -0
- package/scripts/wired-check.mjs +867 -0
- package/plugin/scripts/finalize-token-meter.mjs +0 -25
|
@@ -0,0 +1,2144 @@
|
|
|
1
|
+
/* ============================================================================
|
|
2
|
+
RUVNET BRAIN — ONBOARDING CONSOLE
|
|
3
|
+
----------------------------------------------------------------------------
|
|
4
|
+
A console in the "Amber Substrate" brand family (explainer/theme.css):
|
|
5
|
+
graphite substrate lit by an amber mind, cyan signal, green grounding, and
|
|
6
|
+
the amber → gold → cyan → green spectrum as the signature.
|
|
7
|
+
|
|
8
|
+
Semantics carried by color, everywhere on this page:
|
|
9
|
+
cyan = observed (mirror/explain — what we SAW)
|
|
10
|
+
amber = the mind advising / the action you take
|
|
11
|
+
green = grounded, measured, reversible
|
|
12
|
+
red = broken only (never "you chose wrong")
|
|
13
|
+
|
|
14
|
+
Fully offline: system font stacks only. Light + dark, both first-class.
|
|
15
|
+
============================================================================ */
|
|
16
|
+
|
|
17
|
+
/* ============================== 1 · TOKENS ============================== */
|
|
18
|
+
|
|
19
|
+
:root {
|
|
20
|
+
/* ---- dark (the brand's home) ---- */
|
|
21
|
+
color-scheme: dark;
|
|
22
|
+
|
|
23
|
+
--bg: #0a0c10;
|
|
24
|
+
--bg-2: #0e1116;
|
|
25
|
+
--surface: #13171e;
|
|
26
|
+
--surface-2: #181d26;
|
|
27
|
+
--ridge: #2a3140;
|
|
28
|
+
|
|
29
|
+
--ink: #ece8dc;
|
|
30
|
+
--ink-2: #c3c2b6;
|
|
31
|
+
--muted: #8f94a1;
|
|
32
|
+
--faint: #5a5f6e;
|
|
33
|
+
--on-accent: #0a0c10;
|
|
34
|
+
|
|
35
|
+
--amber: #f0a830; --amber-text: #f0b04a;
|
|
36
|
+
--cyan: #5ad6ff; --cyan-text: #5ad6ff;
|
|
37
|
+
--green: #5fd38a; --green-text: #5fd38a;
|
|
38
|
+
--red: #ff6b5e; --red-text: #ff8a7e;
|
|
39
|
+
--warn: #f0b65a; --warn-text: #f0b65a;
|
|
40
|
+
|
|
41
|
+
--spectrum: linear-gradient(96deg, #f0a830 0%, #ffce6a 24%, #5ad6ff 58%, #5fd38a 100%);
|
|
42
|
+
|
|
43
|
+
--shadow: 0 18px 42px -24px rgba(0, 0, 0, 0.65);
|
|
44
|
+
--shadow-deep: 0 30px 70px -34px rgba(0, 0, 0, 0.8);
|
|
45
|
+
|
|
46
|
+
/* type */
|
|
47
|
+
--display: "Iowan Old Style", "Palatino Nova", Palatino, "Book Antiqua", Georgia, "Times New Roman", serif;
|
|
48
|
+
--sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
49
|
+
--mono: ui-monospace, "SF Mono", "Cascadia Code", Menlo, Consolas, "Liberation Mono", monospace;
|
|
50
|
+
|
|
51
|
+
--ease: cubic-bezier(0.22, 0.61, 0.36, 1);
|
|
52
|
+
--radius: 16px;
|
|
53
|
+
--radius-s: 10px;
|
|
54
|
+
--maxw: 1080px;
|
|
55
|
+
--gutter: clamp(1.1rem, 4vw, 2.6rem);
|
|
56
|
+
|
|
57
|
+
/* fluid type (360 → 1440) */
|
|
58
|
+
--fs--2: clamp(0.685rem, 0.66rem + 0.12vw, 0.76rem);
|
|
59
|
+
--fs--1: clamp(0.815rem, 0.79rem + 0.14vw, 0.885rem);
|
|
60
|
+
--fs-0: clamp(0.94rem, 0.91rem + 0.15vw, 1rem);
|
|
61
|
+
--fs-1: clamp(1.06rem, 1.0rem + 0.3vw, 1.19rem);
|
|
62
|
+
--fs-2: clamp(1.24rem, 1.12rem + 0.6vw, 1.5rem);
|
|
63
|
+
--fs-3: clamp(1.85rem, 1.4rem + 2.3vw, 2.95rem);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
:root[data-theme="light"] {
|
|
67
|
+
/* ---- light: the daylight sibling — warm paper from the brand's own ink ---- */
|
|
68
|
+
color-scheme: light;
|
|
69
|
+
|
|
70
|
+
--bg: #f1efe8;
|
|
71
|
+
--bg-2: #e9e6dd;
|
|
72
|
+
--surface: #fbfaf6;
|
|
73
|
+
--surface-2: #f2efe8;
|
|
74
|
+
--ridge: #d9d5c9;
|
|
75
|
+
|
|
76
|
+
--ink: #20242e;
|
|
77
|
+
--ink-2: #3d4353;
|
|
78
|
+
--muted: #575d6e;
|
|
79
|
+
--faint: #878c99;
|
|
80
|
+
--on-accent: #241a06;
|
|
81
|
+
|
|
82
|
+
--amber: #e09614; --amber-text: #8f5c05;
|
|
83
|
+
--cyan: #2ba6cf; --cyan-text: #0a6d8f;
|
|
84
|
+
--green: #3aa768; --green-text: #1e7a45;
|
|
85
|
+
--red: #e05b4b; --red-text: #b03225;
|
|
86
|
+
--warn: #d99a2b; --warn-text: #8a5c06;
|
|
87
|
+
|
|
88
|
+
--spectrum: linear-gradient(96deg, #c47d08 0%, #d9a12e 24%, #0e87ad 58%, #20824d 100%);
|
|
89
|
+
|
|
90
|
+
--shadow: 0 16px 36px -24px rgba(60, 50, 20, 0.35);
|
|
91
|
+
--shadow-deep: 0 26px 60px -30px rgba(60, 50, 20, 0.45);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/* derived — both themes */
|
|
95
|
+
:root {
|
|
96
|
+
--hair: color-mix(in srgb, var(--ridge) 78%, transparent);
|
|
97
|
+
--hair-strong: color-mix(in srgb, var(--ridge) 100%, transparent);
|
|
98
|
+
--line: color-mix(in srgb, var(--amber) 22%, transparent);
|
|
99
|
+
--fill: color-mix(in srgb, var(--amber) 9%, transparent);
|
|
100
|
+
--fill-cyan: color-mix(in srgb, var(--cyan) 9%, transparent);
|
|
101
|
+
--fill-green: color-mix(in srgb, var(--green) 9%, transparent);
|
|
102
|
+
|
|
103
|
+
--illo-stroke: color-mix(in srgb, var(--ink) 52%, transparent);
|
|
104
|
+
--illo-faint: color-mix(in srgb, var(--ink) 24%, transparent);
|
|
105
|
+
--illo-plate: color-mix(in srgb, var(--ink) 5%, transparent);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/* ============================== 2 · BASE ============================== */
|
|
109
|
+
|
|
110
|
+
*, *::before, *::after { box-sizing: border-box; }
|
|
111
|
+
|
|
112
|
+
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
|
|
113
|
+
@supports (interpolate-size: allow-keywords) {
|
|
114
|
+
:root { interpolate-size: allow-keywords; }
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
body {
|
|
118
|
+
margin: 0;
|
|
119
|
+
background: var(--bg);
|
|
120
|
+
color: var(--ink);
|
|
121
|
+
font-family: var(--sans);
|
|
122
|
+
font-size: var(--fs-0);
|
|
123
|
+
line-height: 1.62;
|
|
124
|
+
-webkit-font-smoothing: antialiased;
|
|
125
|
+
text-rendering: optimizeLegibility;
|
|
126
|
+
/* Substrate: the two brand tints + a whisper of dot-grid texture (4% ink at 26px pitch —
|
|
127
|
+
structure you feel more than see; text sits on cards, so legibility pays nothing). */
|
|
128
|
+
background-image:
|
|
129
|
+
radial-gradient(color-mix(in srgb, var(--ink) 4.5%, transparent) 1px, transparent 1.5px),
|
|
130
|
+
radial-gradient(1000px 560px at 82% -6%, color-mix(in srgb, var(--amber) 9%, transparent), transparent 62%),
|
|
131
|
+
radial-gradient(820px 640px at -8% 4%, color-mix(in srgb, var(--cyan) 7%, transparent), transparent 56%),
|
|
132
|
+
linear-gradient(180deg, var(--bg) 0%, var(--bg-2) 100%);
|
|
133
|
+
background-size: 26px 26px, auto, auto, auto;
|
|
134
|
+
background-attachment: fixed;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
img, svg, video { max-width: 100%; height: auto; }
|
|
138
|
+
|
|
139
|
+
a { color: var(--cyan-text); text-decoration: none; }
|
|
140
|
+
a:hover { color: var(--amber-text); }
|
|
141
|
+
|
|
142
|
+
code {
|
|
143
|
+
font-family: var(--mono); font-size: 0.86em;
|
|
144
|
+
color: var(--cyan-text); background: var(--fill-cyan);
|
|
145
|
+
border: 1px solid color-mix(in srgb, var(--cyan) 26%, transparent);
|
|
146
|
+
border-radius: 6px; padding: 0.08em 0.42em;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.mono { font-family: var(--mono); }
|
|
150
|
+
|
|
151
|
+
:focus-visible {
|
|
152
|
+
outline: 2px solid var(--cyan);
|
|
153
|
+
outline-offset: 2px;
|
|
154
|
+
border-radius: 6px;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
::selection { background: color-mix(in srgb, var(--amber) 30%, transparent); color: var(--ink); }
|
|
158
|
+
|
|
159
|
+
.visually-hidden {
|
|
160
|
+
position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px;
|
|
161
|
+
overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.skip-link {
|
|
165
|
+
position: absolute; left: 0; top: 0; z-index: 100;
|
|
166
|
+
transform: translateY(-130%);
|
|
167
|
+
background: var(--amber); color: var(--on-accent);
|
|
168
|
+
font-family: var(--mono); font-size: var(--fs--1); font-weight: 600;
|
|
169
|
+
padding: 10px 16px; border-radius: 0 0 var(--radius-s) 0;
|
|
170
|
+
transition: transform 0.18s var(--ease);
|
|
171
|
+
}
|
|
172
|
+
.skip-link:focus { transform: translateY(0); }
|
|
173
|
+
|
|
174
|
+
.wrap { width: 100%; max-width: var(--maxw); margin-inline: auto; padding-inline: var(--gutter); }
|
|
175
|
+
|
|
176
|
+
h1, h2, h3 {
|
|
177
|
+
font-family: var(--display);
|
|
178
|
+
font-weight: 600;
|
|
179
|
+
letter-spacing: -0.012em;
|
|
180
|
+
line-height: 1.08;
|
|
181
|
+
color: var(--ink);
|
|
182
|
+
margin: 0 0 0.4em;
|
|
183
|
+
text-wrap: balance;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
p { margin: 0 0 0.9rem; color: var(--ink-2); max-width: 70ch; text-wrap: pretty; }
|
|
187
|
+
p:last-child { margin-bottom: 0; }
|
|
188
|
+
|
|
189
|
+
.eyebrow {
|
|
190
|
+
font-family: var(--mono); font-size: var(--fs--2);
|
|
191
|
+
letter-spacing: 0.26em; text-transform: uppercase;
|
|
192
|
+
color: var(--cyan-text); margin: 0 0 14px;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.muted { color: var(--muted); }
|
|
196
|
+
|
|
197
|
+
/* ============================== 3 · HEADER ============================== */
|
|
198
|
+
|
|
199
|
+
.head {
|
|
200
|
+
position: sticky; top: 0; z-index: 50;
|
|
201
|
+
background: color-mix(in srgb, var(--bg) 82%, transparent);
|
|
202
|
+
backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
|
|
203
|
+
}
|
|
204
|
+
.head-inner {
|
|
205
|
+
display: flex; align-items: center; justify-content: space-between;
|
|
206
|
+
height: 58px; gap: 16px;
|
|
207
|
+
}
|
|
208
|
+
.spectrum-edge { height: 2px; background: var(--spectrum); opacity: 0.9; }
|
|
209
|
+
|
|
210
|
+
.brand { display: inline-flex; align-items: center; gap: 11px; min-width: 0; }
|
|
211
|
+
.brand .mark { width: 28px; height: 28px; flex: none; }
|
|
212
|
+
/* The mark keeps its own dark plate in BOTH themes (like the favicon and the hero art):
|
|
213
|
+
the amber circuit-brain is drawn for that substrate, so the colors are literals, not vars. */
|
|
214
|
+
.brand .mark .mk-plate { fill: #0b0d12; stroke: #2c3850; stroke-width: 1.5; }
|
|
215
|
+
.brand .mark .mk-brain { fill: none; stroke: #f0a830; stroke-width: 3.4; stroke-linejoin: round; }
|
|
216
|
+
.brand .mark .mk-branch { fill: none; stroke: #f0a830; stroke-width: 2.4; stroke-linecap: round; opacity: 0.9; }
|
|
217
|
+
.brand .mark .n1 { fill: #f4b13a; }
|
|
218
|
+
.brand .mark .n2 { fill: #5ad6ff; }
|
|
219
|
+
.brand .mark .n3 { fill: #5fd38a; }
|
|
220
|
+
.brand-text {
|
|
221
|
+
font-family: var(--display); font-weight: 600; font-size: 1.02rem;
|
|
222
|
+
letter-spacing: -0.01em; color: var(--ink); white-space: nowrap;
|
|
223
|
+
overflow: hidden; text-overflow: ellipsis;
|
|
224
|
+
}
|
|
225
|
+
.brand-sub {
|
|
226
|
+
font-family: var(--mono); font-size: 11px; font-weight: 500;
|
|
227
|
+
letter-spacing: 0.2em; text-transform: uppercase; color: var(--muted);
|
|
228
|
+
margin-left: 8px;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.head-right { display: inline-flex; align-items: center; gap: 10px; }
|
|
232
|
+
.host-chip {
|
|
233
|
+
font-size: 12.5px; color: var(--ink-2);
|
|
234
|
+
border: 1px solid var(--hair); border-radius: 100px; padding: 4px 11px;
|
|
235
|
+
white-space: nowrap;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/* Header version chip + update gong (owner, 2026-07-24). The chip is quiet chrome; the gong is
|
|
239
|
+
deliberately the loudest thing in the header — it only exists when a newer release is KNOWN. */
|
|
240
|
+
.ver-chip {
|
|
241
|
+
font-size: 11.5px; color: var(--ink-2);
|
|
242
|
+
border: 1px solid var(--hair); border-radius: 100px; padding: 3px 9px;
|
|
243
|
+
margin-left: 8px; white-space: nowrap;
|
|
244
|
+
}
|
|
245
|
+
.update-gong {
|
|
246
|
+
font-size: 11.5px; font-weight: 600; cursor: pointer; white-space: nowrap;
|
|
247
|
+
color: #7c3f00; background: rgba(217, 119, 6, .14);
|
|
248
|
+
border: 1px solid rgba(217, 119, 6, .55); border-radius: 100px; padding: 3px 10px;
|
|
249
|
+
margin-left: 6px; animation: gong-pulse 2.2s ease-in-out infinite;
|
|
250
|
+
}
|
|
251
|
+
:root[data-theme="dark"] .update-gong { color: #fbbf24; background: rgba(217, 119, 6, .18); }
|
|
252
|
+
.update-gong:hover { animation-play-state: paused; }
|
|
253
|
+
@keyframes gong-pulse {
|
|
254
|
+
0%, 100% { box-shadow: 0 0 0 0 rgba(217, 119, 6, .38); }
|
|
255
|
+
50% { box-shadow: 0 0 0 7px rgba(217, 119, 6, 0); }
|
|
256
|
+
}
|
|
257
|
+
@media (prefers-reduced-motion: reduce) { .update-gong { animation: none; } }
|
|
258
|
+
|
|
259
|
+
.theme-toggle {
|
|
260
|
+
width: 36px; height: 36px; border-radius: 10px;
|
|
261
|
+
border: 1px solid var(--hair-strong); background: transparent;
|
|
262
|
+
display: grid; place-items: center; cursor: pointer;
|
|
263
|
+
color: var(--ink-2);
|
|
264
|
+
transition: border-color 0.18s var(--ease), background 0.18s var(--ease), transform 0.15s var(--ease);
|
|
265
|
+
}
|
|
266
|
+
.theme-toggle:hover { border-color: var(--amber); color: var(--amber-text); background: var(--fill); }
|
|
267
|
+
.theme-toggle:active { transform: scale(0.94); }
|
|
268
|
+
.theme-toggle svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; }
|
|
269
|
+
:root[data-theme="dark"] .ic-moon { display: none; }
|
|
270
|
+
:root[data-theme="light"] .ic-sun { display: none; }
|
|
271
|
+
|
|
272
|
+
/* ============================== 4 · HERO ============================== */
|
|
273
|
+
|
|
274
|
+
.intro { padding: clamp(2.2rem, 5vw, 4rem) 0 clamp(1rem, 2.5vw, 1.6rem); }
|
|
275
|
+
|
|
276
|
+
.intro-grid { display: grid; grid-template-columns: 1fr; gap: clamp(1.6rem, 4vw, 3rem); align-items: center; }
|
|
277
|
+
@media (min-width: 62em) { .intro-grid { grid-template-columns: 1.08fr 0.92fr; } }
|
|
278
|
+
|
|
279
|
+
h1 { font-size: var(--fs-3); }
|
|
280
|
+
h1 em {
|
|
281
|
+
font-style: italic;
|
|
282
|
+
background: var(--spectrum);
|
|
283
|
+
-webkit-background-clip: text; background-clip: text;
|
|
284
|
+
color: transparent;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.lede { font-size: var(--fs-1); line-height: 1.55; color: var(--ink-2); max-width: 56ch; }
|
|
288
|
+
|
|
289
|
+
.motto { margin: 1.2rem 0 0; font-size: 12.5px; letter-spacing: 0.05em; display: flex; flex-wrap: wrap; gap: 6px 10px; align-items: baseline; }
|
|
290
|
+
.motto .m { text-transform: uppercase; font-weight: 600; letter-spacing: 0.16em; }
|
|
291
|
+
.motto .m-mirror { color: var(--cyan-text); }
|
|
292
|
+
.motto .m-rec { color: var(--amber-text); }
|
|
293
|
+
.motto .m-undo { color: var(--green-text); }
|
|
294
|
+
.motto .sep { color: var(--faint); }
|
|
295
|
+
.motto .m-note { color: var(--ink-2); font-style: italic; letter-spacing: 0.02em; text-transform: lowercase; }
|
|
296
|
+
|
|
297
|
+
.meta-row {
|
|
298
|
+
display: flex; flex-wrap: wrap; gap: 8px 20px; margin-top: 1.2rem;
|
|
299
|
+
font-size: 13px; letter-spacing: 0.04em; color: var(--ink-2);
|
|
300
|
+
}
|
|
301
|
+
.meta-row b { color: var(--cyan-text); font-weight: 500; }
|
|
302
|
+
|
|
303
|
+
/* hero art — a dark art plate in BOTH themes (photography stays photography) */
|
|
304
|
+
.hero-art {
|
|
305
|
+
margin: 0; position: relative; overflow: hidden;
|
|
306
|
+
border-radius: var(--radius); border: 1px solid var(--ridge);
|
|
307
|
+
background: #0b0d12; box-shadow: var(--shadow-deep);
|
|
308
|
+
aspect-ratio: 640 / 420;
|
|
309
|
+
}
|
|
310
|
+
.hero-art .hero-scene { position: absolute; inset: 0; width: 100%; height: 100%; }
|
|
311
|
+
.hero-art .hero-img {
|
|
312
|
+
position: absolute; inset: 0; width: 100%; height: 100%;
|
|
313
|
+
object-fit: cover; display: block;
|
|
314
|
+
}
|
|
315
|
+
.hero-cap {
|
|
316
|
+
position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
|
|
317
|
+
margin: 0; padding: 7px 14px;
|
|
318
|
+
font-size: 12px; letter-spacing: 0.12em; text-transform: uppercase;
|
|
319
|
+
color: #c0c7d6; background: rgba(8, 10, 14, 0.72);
|
|
320
|
+
backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
|
|
321
|
+
border-top: 1px solid rgba(90, 214, 255, 0.14);
|
|
322
|
+
}
|
|
323
|
+
.hs-glow { animation: hs-pulse 3.4s var(--ease) infinite; transform-origin: center; }
|
|
324
|
+
.hs-glow.g2 { animation-delay: 1.1s; }
|
|
325
|
+
.hs-glow.g3 { animation-delay: 2.2s; }
|
|
326
|
+
.hs-ring { animation: hs-ring 3.4s var(--ease) infinite; }
|
|
327
|
+
@keyframes hs-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.45; } }
|
|
328
|
+
@keyframes hs-ring { 0%, 100% { opacity: 0.35; } 50% { opacity: 0.08; } }
|
|
329
|
+
|
|
330
|
+
/* the "we looked at your computer" ribbon */
|
|
331
|
+
.found-strip {
|
|
332
|
+
margin-top: clamp(1.4rem, 3vw, 2rem);
|
|
333
|
+
padding: 14px 18px; border-radius: 14px;
|
|
334
|
+
border: 1px solid var(--line);
|
|
335
|
+
background: linear-gradient(120deg, var(--fill), var(--fill-cyan));
|
|
336
|
+
font-size: var(--fs--1); color: var(--ink-2); line-height: 1.6;
|
|
337
|
+
}
|
|
338
|
+
.found-strip::before {
|
|
339
|
+
content: "✦"; color: var(--amber-text); margin-right: 10px; font-size: 0.9em;
|
|
340
|
+
}
|
|
341
|
+
.found-strip b { color: var(--ink); font-weight: 650; font-variant-numeric: tabular-nums; }
|
|
342
|
+
.found-strip .fs-path { font-family: var(--mono); font-size: 0.92em; color: var(--cyan-text); }
|
|
343
|
+
|
|
344
|
+
/* ============================== 5 · CARDS ============================== */
|
|
345
|
+
|
|
346
|
+
main { padding-bottom: clamp(2rem, 5vw, 4rem); }
|
|
347
|
+
|
|
348
|
+
.card {
|
|
349
|
+
background: linear-gradient(180deg, var(--surface) 0%, color-mix(in srgb, var(--surface) 55%, var(--bg-2)) 100%);
|
|
350
|
+
border: 1px solid var(--ridge);
|
|
351
|
+
border-radius: var(--radius);
|
|
352
|
+
box-shadow: var(--shadow);
|
|
353
|
+
margin: 0 0 clamp(14px, 2vw, 20px);
|
|
354
|
+
overflow: hidden;
|
|
355
|
+
}
|
|
356
|
+
.card[open] { border-color: var(--line); box-shadow: var(--shadow-deep); }
|
|
357
|
+
|
|
358
|
+
/* staggered load-in */
|
|
359
|
+
.intro { animation: rise 0.55s var(--ease) both; }
|
|
360
|
+
.card { animation: rise 0.55s var(--ease) both; }
|
|
361
|
+
.card:nth-of-type(1) { animation-delay: 0.06s; }
|
|
362
|
+
.card:nth-of-type(2) { animation-delay: 0.12s; }
|
|
363
|
+
.card:nth-of-type(3) { animation-delay: 0.18s; }
|
|
364
|
+
.card:nth-of-type(4) { animation-delay: 0.24s; }
|
|
365
|
+
.card:nth-of-type(5) { animation-delay: 0.30s; }
|
|
366
|
+
.card:nth-of-type(6) { animation-delay: 0.36s; }
|
|
367
|
+
@keyframes rise { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
|
|
368
|
+
|
|
369
|
+
.card > summary {
|
|
370
|
+
list-style: none; cursor: pointer; user-select: none;
|
|
371
|
+
display: flex; align-items: center; gap: 16px;
|
|
372
|
+
padding: clamp(16px, 2.6vw, 22px) clamp(16px, 3vw, 26px);
|
|
373
|
+
transition: background 0.2s var(--ease);
|
|
374
|
+
}
|
|
375
|
+
.card > summary::-webkit-details-marker { display: none; }
|
|
376
|
+
.card > summary:hover { background: var(--fill); }
|
|
377
|
+
|
|
378
|
+
.card-head { flex: 1 1 auto; min-width: 0; }
|
|
379
|
+
.card-head h2 { font-size: var(--fs-2); margin: 2px 0 0; }
|
|
380
|
+
.card-head .q {
|
|
381
|
+
display: block; margin-top: 4px;
|
|
382
|
+
font-size: var(--fs--1); color: var(--ink-2); line-height: 1.45;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/* Stage chips — the color semantics worn as a pill (dot + tint), matching the card's rail.
|
|
386
|
+
cyan observes · green proves · amber acts. Named once in the legend above the cards. */
|
|
387
|
+
.stage {
|
|
388
|
+
display: inline-flex; align-items: center; gap: 6px;
|
|
389
|
+
font-family: var(--mono); font-size: 10.5px; font-weight: 600;
|
|
390
|
+
letter-spacing: 0.2em; text-transform: uppercase;
|
|
391
|
+
padding: 2.5px 10px 2.5px 8px; border-radius: 100px; border: 1px solid;
|
|
392
|
+
}
|
|
393
|
+
.stage::before { content: ""; flex: none; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
|
|
394
|
+
.st-mirror { color: var(--cyan-text); border-color: color-mix(in srgb, var(--cyan) 30%, transparent); background: color-mix(in srgb, var(--cyan) 8%, transparent); }
|
|
395
|
+
.st-rec { color: var(--amber-text); border-color: color-mix(in srgb, var(--amber) 32%, transparent); background: color-mix(in srgb, var(--amber) 8%, transparent); }
|
|
396
|
+
.st-prove { color: var(--green-text); border-color: color-mix(in srgb, var(--green) 30%, transparent); background: color-mix(in srgb, var(--green) 8%, transparent); }
|
|
397
|
+
|
|
398
|
+
/* The stage rail: a 3px color spine down each card's left edge (clipped to the card's own
|
|
399
|
+
radius by its overflow:hidden). Same three meanings as the chips — visible at a glance
|
|
400
|
+
even when every card is collapsed. */
|
|
401
|
+
.card { position: relative; }
|
|
402
|
+
.card::before {
|
|
403
|
+
content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px; z-index: 1;
|
|
404
|
+
pointer-events: none;
|
|
405
|
+
}
|
|
406
|
+
.rail-mirror::before { background: color-mix(in srgb, var(--cyan) 64%, transparent); }
|
|
407
|
+
.rail-prove::before { background: color-mix(in srgb, var(--green) 64%, transparent); }
|
|
408
|
+
.rail-act::before { background: color-mix(in srgb, var(--amber) 66%, transparent); }
|
|
409
|
+
|
|
410
|
+
/* Card identity icons — one 24-grid line glyph per card, tinted by its stage. */
|
|
411
|
+
.card-ic {
|
|
412
|
+
flex: none; width: 34px; height: 34px; border-radius: 10px;
|
|
413
|
+
display: grid; place-items: center;
|
|
414
|
+
border: 1px solid;
|
|
415
|
+
}
|
|
416
|
+
.card-ic svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
|
|
417
|
+
.ic-mirror { color: var(--cyan-text); border-color: color-mix(in srgb, var(--cyan) 22%, transparent); background: color-mix(in srgb, var(--cyan) 8%, transparent); }
|
|
418
|
+
.ic-prove { color: var(--green-text); border-color: color-mix(in srgb, var(--green) 22%, transparent); background: color-mix(in srgb, var(--green) 8%, transparent); }
|
|
419
|
+
.ic-act { color: var(--amber-text); border-color: color-mix(in srgb, var(--amber) 24%, transparent); background: color-mix(in srgb, var(--amber) 8%, transparent); }
|
|
420
|
+
|
|
421
|
+
/* The one-line legend that names the color system (static semantics, above the first card). */
|
|
422
|
+
.stage-legend {
|
|
423
|
+
display: flex; flex-wrap: wrap; align-items: center; gap: 5px 16px;
|
|
424
|
+
margin: clamp(1rem, 2.5vw, 1.6rem) 0 14px;
|
|
425
|
+
font-size: 11px; letter-spacing: 0.09em; text-transform: uppercase; color: var(--muted);
|
|
426
|
+
max-width: none;
|
|
427
|
+
}
|
|
428
|
+
.stage-legend .lg-cap { color: var(--faint); letter-spacing: 0.2em; }
|
|
429
|
+
.stage-legend .lg { display: inline-flex; align-items: center; gap: 7px; white-space: nowrap; }
|
|
430
|
+
.stage-legend .lg-dot { width: 7px; height: 7px; border-radius: 50%; display: inline-block; }
|
|
431
|
+
.stage-legend .d-cyan { background: var(--cyan); }
|
|
432
|
+
.stage-legend .d-green { background: var(--green); }
|
|
433
|
+
.stage-legend .d-amber { background: var(--amber); }
|
|
434
|
+
|
|
435
|
+
.chips {
|
|
436
|
+
flex: 0 0 auto; display: flex; flex-wrap: wrap; gap: 6px;
|
|
437
|
+
justify-content: flex-end; max-width: 46%;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
.chev {
|
|
441
|
+
flex: 0 0 auto; width: 26px; height: 26px; border-radius: 50%;
|
|
442
|
+
display: grid; place-items: center;
|
|
443
|
+
border: 1px solid var(--hair-strong); color: var(--amber-text);
|
|
444
|
+
font-size: 14px; line-height: 1;
|
|
445
|
+
transition: transform 0.28s var(--ease), background 0.2s var(--ease);
|
|
446
|
+
}
|
|
447
|
+
.card[open] .chev { transform: rotate(90deg); background: var(--fill); }
|
|
448
|
+
|
|
449
|
+
/* animated expand/collapse (progressive enhancement) */
|
|
450
|
+
.card::details-content {
|
|
451
|
+
opacity: 0; block-size: 0; overflow-y: clip;
|
|
452
|
+
transition: content-visibility 0.4s allow-discrete,
|
|
453
|
+
opacity 0.32s var(--ease),
|
|
454
|
+
block-size 0.4s var(--ease);
|
|
455
|
+
}
|
|
456
|
+
.card[open]::details-content { opacity: 1; block-size: auto; }
|
|
457
|
+
|
|
458
|
+
.card .body {
|
|
459
|
+
padding: 6px clamp(16px, 3vw, 26px) clamp(20px, 3vw, 28px);
|
|
460
|
+
border-top: 1px solid var(--hair);
|
|
461
|
+
}
|
|
462
|
+
.card .body > *:first-child { margin-top: 16px; }
|
|
463
|
+
|
|
464
|
+
/* body layout with a spot illustration (illo is FIRST in DOM for the mobile
|
|
465
|
+
float; the desktop grid re-places it on the right via `order`) */
|
|
466
|
+
/* Spot illustrations removed (the decorative doodle stole the width the data needs).
|
|
467
|
+
Section bodies are full-width now; the table / dashboard gets every pixel. */
|
|
468
|
+
.illo-box { display: none; }
|
|
469
|
+
.with-illo { display: block; }
|
|
470
|
+
.with-illo > .sect-main { min-width: 0; }
|
|
471
|
+
|
|
472
|
+
/* ---- grouped family list: one row per tool, sub-packages roll up inside ---- */
|
|
473
|
+
.fam-list { margin-top: 14px; border: 1px solid var(--hair); border-radius: 12px; overflow: hidden; background: color-mix(in srgb, var(--ink) 2%, transparent); }
|
|
474
|
+
.fam { border-bottom: 1px solid var(--hair); }
|
|
475
|
+
.fam:last-child { border-bottom: 0; }
|
|
476
|
+
.fam-sum { display: grid; grid-template-columns: minmax(120px, 1.1fr) minmax(150px, 2fr) auto auto; align-items: center; gap: 14px; padding: 13px 16px; cursor: pointer; list-style: none; }
|
|
477
|
+
.fam-sum::-webkit-details-marker { display: none; }
|
|
478
|
+
.fam-sum:hover { background: color-mix(in srgb, var(--ink) 3%, transparent); }
|
|
479
|
+
.fam-name { font-weight: 650; color: var(--ink); }
|
|
480
|
+
.fam-what { color: var(--ink-2); font-size: var(--fs--1); }
|
|
481
|
+
.fam-status { display: inline-flex; align-items: center; gap: 8px; justify-content: flex-end; }
|
|
482
|
+
.fam-count { font-family: var(--mono); font-size: 12px; color: var(--muted); white-space: nowrap; font-variant-numeric: tabular-nums; }
|
|
483
|
+
.fam-chev { color: var(--faint); transition: transform 0.15s ease; justify-self: end; }
|
|
484
|
+
.fam[open] .fam-chev { transform: rotate(90deg); }
|
|
485
|
+
.fam-body { padding: 0 16px 14px; }
|
|
486
|
+
@media (max-width: 40em) {
|
|
487
|
+
.fam-sum { grid-template-columns: 1fr auto; gap: 4px 10px; }
|
|
488
|
+
.fam-what { grid-column: 1 / -1; order: 3; }
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/* ---- MetaHarness pitch + enable ---- */
|
|
492
|
+
.mh-pitch { margin-top: 16px; }
|
|
493
|
+
.mh-lead { color: var(--ink-2); line-height: 1.55; max-width: 66ch; }
|
|
494
|
+
.mh-cta { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 12px; margin-top: 10px; }
|
|
495
|
+
.mh-enable { font: inherit; font-weight: 600; font-size: var(--fs--1); padding: 9px 16px; border-radius: 10px; cursor: pointer; color: var(--green-text); border: 1px solid color-mix(in srgb, var(--green) 45%, transparent); background: color-mix(in srgb, var(--green) 16%, transparent); }
|
|
496
|
+
.mh-enable:hover { background: color-mix(in srgb, var(--green) 24%, transparent); }
|
|
497
|
+
.mh-enable:disabled { opacity: 0.6; cursor: default; }
|
|
498
|
+
.mh-enable-note { font-size: var(--fs--1); color: var(--green-text); }
|
|
499
|
+
|
|
500
|
+
/* ---- router profiles panel (collapsed by default; the buckets it routes into) ---- */
|
|
501
|
+
.mh-profiles { margin-top: 16px; border: 1px solid var(--hair); border-radius: 12px; overflow: hidden; background: color-mix(in srgb, var(--ink) 2%, transparent); }
|
|
502
|
+
.rp-summary { display: flex; align-items: baseline; gap: 12px; padding: 13px 16px; cursor: pointer; list-style: none; }
|
|
503
|
+
.rp-summary::-webkit-details-marker { display: none; }
|
|
504
|
+
.rp-summary:hover { background: color-mix(in srgb, var(--ink) 3%, transparent); }
|
|
505
|
+
.rp-sum-t { font-weight: 600; color: var(--ink); }
|
|
506
|
+
.rp-sum-s { font-size: var(--fs--1); color: var(--ink-2); }
|
|
507
|
+
.rp-chev { margin-left: auto; color: var(--faint); transition: transform 0.15s ease; }
|
|
508
|
+
.mh-profiles[open] .rp-chev { transform: rotate(90deg); }
|
|
509
|
+
.rp-body { position: relative; padding: 6px 16px 16px; overflow: hidden; }
|
|
510
|
+
.rp-bg { position: absolute; top: -8px; right: -14px; width: 260px; max-width: 42%; pointer-events: none; }
|
|
511
|
+
.rp-bg svg { width: 100%; height: auto; display: block; }
|
|
512
|
+
.rp-grid { position: relative; display: grid; grid-template-columns: 1fr; gap: 20px; }
|
|
513
|
+
@media (min-width: 52em) { .rp-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 28px; } }
|
|
514
|
+
.rp-head { margin-bottom: 8px; }
|
|
515
|
+
.rp-name { font-weight: 650; color: var(--ink); }
|
|
516
|
+
/* Dev/Prod headers are click-to-learn: a real button, styled as the header it was */
|
|
517
|
+
.rp-name-btn {
|
|
518
|
+
display: inline-flex; align-items: center; gap: 7px;
|
|
519
|
+
font: inherit; font-weight: 650; color: var(--ink);
|
|
520
|
+
background: none; border: 0; padding: 0; cursor: pointer;
|
|
521
|
+
}
|
|
522
|
+
.rp-name-btn:hover .rp-name { color: var(--amber-text); }
|
|
523
|
+
.rp-obj { display: block; font-size: var(--fs--1); color: var(--ink-2); margin-top: 3px; max-width: 44ch; line-height: 1.45; }
|
|
524
|
+
.rp-tb { font-size: var(--fs--1); width: 100%; }
|
|
525
|
+
.rp-tb th, .rp-tb td { padding: 8px 10px; }
|
|
526
|
+
.rp-band { font-family: var(--mono); font-size: 11.5px; color: var(--cyan-text); text-transform: uppercase; letter-spacing: 0.05em; white-space: nowrap; }
|
|
527
|
+
.rp-model { overflow-wrap: anywhere; }
|
|
528
|
+
.rp-tb td.num, .rp-tb .cell-dim { white-space: nowrap; }
|
|
529
|
+
.rp-why { font-size: 13px; color: var(--ink-2); margin-top: 3px; line-height: 1.45; max-width: 42ch; }
|
|
530
|
+
.rp-esc { display: block; font-size: 13px; color: var(--warn-text); font-weight: 600; margin-top: 2px; }
|
|
531
|
+
.rp-foot { position: relative; margin-top: 14px; }
|
|
532
|
+
.rp-getkey { color: var(--cyan-text); font-weight: 600; }
|
|
533
|
+
|
|
534
|
+
/* Your-house badge — makes the routing feel like it's about YOU, not a generic table */
|
|
535
|
+
.rp-house { position: relative; display: flex; align-items: baseline; gap: 8px 10px; flex-wrap: wrap; margin: 2px 0 16px; padding: 9px 13px; border-radius: 10px; background: color-mix(in srgb, var(--cyan) 8%, transparent); border: 1px solid color-mix(in srgb, var(--cyan) 22%, transparent); }
|
|
536
|
+
.rp-house-tag { font-family: var(--mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--cyan-text); }
|
|
537
|
+
.rp-house-name { color: var(--ink); font-weight: 650; }
|
|
538
|
+
.rp-house-src { font-size: 13px; color: var(--ink-2); }
|
|
539
|
+
.rp-split { position: relative; margin: -6px 0 16px; font-size: var(--fs--1); color: var(--ink-2); line-height: 1.5; max-width: 66ch; }
|
|
540
|
+
.rp-split b { color: var(--ink); font-weight: 600; }
|
|
541
|
+
|
|
542
|
+
/* ---- ongoing utilization: how many tasks per bucket + saved vs the frontier ---- */
|
|
543
|
+
.mh-dist { margin-top: 18px; }
|
|
544
|
+
.dist-lead { font-size: var(--fs--1); color: var(--ink); margin: 0 0 12px; line-height: 1.55; max-width: 62ch; }
|
|
545
|
+
.dist-lead b { color: var(--ink); font-weight: 650; }
|
|
546
|
+
/* The ladder line: how to read the bucket order (WP2c) */
|
|
547
|
+
.dist-ladder { font-size: 13.5px; color: var(--ink-2); margin: 0 0 10px; line-height: 1.5; max-width: 70ch; }
|
|
548
|
+
.dist-ladder::before { content: "↓ "; color: var(--cyan-text); }
|
|
549
|
+
.dist-grid { display: flex; flex-direction: column; border: 1px solid var(--hair); border-radius: 12px; overflow: hidden; }
|
|
550
|
+
.dist-row { display: grid; grid-template-columns: 118px minmax(120px, 1.1fr) minmax(0, 1.3fr) 68px; align-items: center; gap: 12px; padding: 10px 14px; }
|
|
551
|
+
.dist-row + .dist-row { border-top: 1px solid var(--hair); }
|
|
552
|
+
|
|
553
|
+
/* Router decisions — their own stacked layout: model + attribution + time on one line, the plain
|
|
554
|
+
reason underneath. Long model names must never collide with prose (2026-07-16). */
|
|
555
|
+
.dec-row { padding: 10px 14px; }
|
|
556
|
+
.dec-row + .dec-row { border-top: 1px solid var(--hair); }
|
|
557
|
+
.dec-top { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
|
|
558
|
+
.dec-model { font-size: 0.98rem; }
|
|
559
|
+
.dec-when { margin-left: auto; font-size: 0.82rem; }
|
|
560
|
+
.dec-why { margin-top: 3px; font-size: 0.9rem; line-height: 1.45; max-width: 72ch; }
|
|
561
|
+
.dist-head { background: color-mix(in srgb, var(--ink) 3%, transparent); padding-top: 8px; padding-bottom: 8px; }
|
|
562
|
+
.dist-head > div { font-family: var(--mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted); }
|
|
563
|
+
.dist-head .dist-saved { text-align: right; }
|
|
564
|
+
.dist-row.is-empty { opacity: 0.65; }
|
|
565
|
+
.dist-band { font-family: var(--mono); font-size: 12px; text-transform: uppercase; letter-spacing: 0.05em; font-weight: 600; white-space: nowrap; }
|
|
566
|
+
.dist-esc { font-family: var(--sans); font-size: 13px; font-weight: 600; color: var(--warn-text); text-transform: none; letter-spacing: 0; white-space: normal; line-height: 1.3; margin-top: 2px; }
|
|
567
|
+
.dist-band.b-mech { color: var(--green-text); }
|
|
568
|
+
.dist-band.b-cheap { color: var(--cyan-text); }
|
|
569
|
+
.dist-band.b-mid { color: var(--warn-text); }
|
|
570
|
+
.dist-band.b-front { color: var(--red-text); }
|
|
571
|
+
.dist-track { position: relative; height: 24px; border-radius: 6px; background: color-mix(in srgb, var(--ink) 5%, transparent); overflow: hidden; display: flex; align-items: center; }
|
|
572
|
+
.dist-fill { position: absolute; left: 0; top: 0; bottom: 0; border-radius: 6px; opacity: 0.38; min-width: 2px; transition: width 0.4s ease; }
|
|
573
|
+
.dist-fill.b-mech { background: var(--green); }
|
|
574
|
+
.dist-fill.b-cheap { background: var(--cyan); }
|
|
575
|
+
.dist-fill.b-mid { background: var(--warn); }
|
|
576
|
+
.dist-fill.b-front { background: var(--red); }
|
|
577
|
+
.dist-count { position: relative; z-index: 1; padding-left: 10px; font-family: var(--mono); font-size: 12px; color: var(--ink); font-variant-numeric: tabular-nums; }
|
|
578
|
+
.dist-models { font-size: 13px; color: var(--ink-2); overflow-wrap: anywhere; }
|
|
579
|
+
.dist-saved { font-family: var(--mono); font-size: 13px; text-align: right; color: var(--green-text); white-space: nowrap; font-variant-numeric: tabular-nums; }
|
|
580
|
+
@media (max-width: 40em) {
|
|
581
|
+
.dist-row { grid-template-columns: 92px 1fr 60px; }
|
|
582
|
+
.dist-models { display: none; }
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
/* full receipt detail, collapsed under the distribution */
|
|
586
|
+
.mh-receipts { margin-top: 16px; border: 1px solid var(--hair); border-radius: 12px; overflow: hidden; background: color-mix(in srgb, var(--ink) 2%, transparent); }
|
|
587
|
+
.mh-receipts > .scroll-x { padding: 0 14px 14px; }
|
|
588
|
+
.mh-receipts[open] .rp-chev { transform: rotate(90deg); }
|
|
589
|
+
|
|
590
|
+
/* Learning strip — visible face of the recursive learning loop (ADR-0017); compact by design */
|
|
591
|
+
.learn-strip { margin: 14px 0 4px; padding: 12px 14px; border-radius: 12px; border: 1px solid color-mix(in srgb, var(--cyan) 24%, transparent); background: linear-gradient(180deg, color-mix(in srgb, var(--cyan) 7%, transparent), color-mix(in srgb, var(--green) 4%, transparent)); }
|
|
592
|
+
.learn-head { display: flex; align-items: center; gap: 11px; }
|
|
593
|
+
.learn-spark { font-size: 18px; color: var(--cyan-text); line-height: 1; }
|
|
594
|
+
.learn-title { font-weight: 650; color: var(--ink); }
|
|
595
|
+
.learn-sub { font-size: var(--fs--1); color: var(--ink-2); }
|
|
596
|
+
.learn-sub b { color: var(--ink); font-weight: 600; font-variant-numeric: tabular-nums; }
|
|
597
|
+
.learn-recent { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
|
|
598
|
+
.learn-recent-lab { font-family: var(--mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); margin-right: 2px; }
|
|
599
|
+
.learn-chip { font-family: var(--mono); font-size: 12px; color: var(--ink-2); padding: 2px 8px; border-radius: 6px; background: color-mix(in srgb, var(--ink) 5%, transparent); border: 1px solid var(--hair); white-space: nowrap; }
|
|
600
|
+
.learn-foot { margin-top: 10px; }
|
|
601
|
+
|
|
602
|
+
/* ============================== 6 · CHIPS ============================== */
|
|
603
|
+
|
|
604
|
+
.chip {
|
|
605
|
+
display: inline-flex; align-items: center; gap: 6px;
|
|
606
|
+
font-family: var(--mono); font-size: 12.5px; font-weight: 500;
|
|
607
|
+
letter-spacing: 0.03em; white-space: nowrap;
|
|
608
|
+
padding: 3px 9px; border-radius: 100px;
|
|
609
|
+
border: 1px solid var(--hair-strong);
|
|
610
|
+
color: var(--muted); background: transparent;
|
|
611
|
+
font-variant-numeric: tabular-nums;
|
|
612
|
+
}
|
|
613
|
+
.tone-green { color: var(--green-text); border-color: color-mix(in srgb, var(--green) 34%, transparent); background: color-mix(in srgb, var(--green) 10%, transparent); }
|
|
614
|
+
.tone-warn { color: var(--warn-text); border-color: color-mix(in srgb, var(--warn) 36%, transparent); background: color-mix(in srgb, var(--warn) 10%, transparent); }
|
|
615
|
+
.tone-red { color: var(--red-text); border-color: color-mix(in srgb, var(--red) 36%, transparent); background: color-mix(in srgb, var(--red) 10%, transparent); }
|
|
616
|
+
.tone-cyan { color: var(--cyan-text); border-color: color-mix(in srgb, var(--cyan) 34%, transparent); background: color-mix(in srgb, var(--cyan) 9%, transparent); }
|
|
617
|
+
.tone-amber { color: var(--amber-text); border-color: color-mix(in srgb, var(--amber) 36%, transparent); background: color-mix(in srgb, var(--amber) 10%, transparent); }
|
|
618
|
+
.tone-grey { color: var(--muted); }
|
|
619
|
+
.tone-wait { color: var(--muted); border-style: dashed; }
|
|
620
|
+
.tone-nt { color: var(--muted); border-style: dashed; background: transparent; }
|
|
621
|
+
|
|
622
|
+
/* ============================== 7 · TABLES ============================== */
|
|
623
|
+
|
|
624
|
+
.scroll-x {
|
|
625
|
+
overflow-x: auto; border: 1px solid var(--hair); border-radius: 12px;
|
|
626
|
+
background: color-mix(in srgb, var(--ink) 2%, transparent);
|
|
627
|
+
}
|
|
628
|
+
.scroll-y { max-height: 380px; overflow-y: auto; }
|
|
629
|
+
|
|
630
|
+
table.tb { width: 100%; border-collapse: collapse; font-size: var(--fs--1); }
|
|
631
|
+
.tb th, .tb td { text-align: left; padding: 10px 14px; border-bottom: 1px solid var(--hair); vertical-align: top; }
|
|
632
|
+
.tb thead th {
|
|
633
|
+
font-family: var(--mono); font-size: 11.5px; font-weight: 600;
|
|
634
|
+
letter-spacing: 0.1em; text-transform: uppercase; color: var(--muted);
|
|
635
|
+
background: color-mix(in srgb, var(--ink) 4%, transparent);
|
|
636
|
+
position: sticky; top: 0; z-index: 1;
|
|
637
|
+
}
|
|
638
|
+
.tb tbody tr:last-child td { border-bottom: 0; }
|
|
639
|
+
.tb tbody tr { transition: background 0.15s var(--ease); }
|
|
640
|
+
.tb tbody tr:hover { background: var(--fill); }
|
|
641
|
+
.tb td.cell-name { font-family: var(--mono); font-size: 0.86rem; color: var(--ink); white-space: nowrap; }
|
|
642
|
+
.tb td.cell-mono { font-family: var(--mono); font-size: 0.82rem; color: var(--ink-2); white-space: nowrap; font-variant-numeric: tabular-nums; }
|
|
643
|
+
.tb td.cell-dim { color: var(--muted); }
|
|
644
|
+
.tb .num { font-variant-numeric: tabular-nums; }
|
|
645
|
+
/* ISSUE #22 — a small pill marking a tool installed via the Claude Code plugin marketplace. */
|
|
646
|
+
.tb .src-tag { margin-left: .4em; padding: .04em .4em; border-radius: 4px; font-size: .68rem;
|
|
647
|
+
font-family: var(--sans, inherit); letter-spacing: .02em; text-transform: uppercase;
|
|
648
|
+
color: var(--muted); background: var(--chip-bg, rgba(127,127,127,.14)); vertical-align: middle; }
|
|
649
|
+
|
|
650
|
+
/* ============================== 8 · SKELETON ============================== */
|
|
651
|
+
|
|
652
|
+
.skeleton { padding: 6px 0 2px; }
|
|
653
|
+
.sk-bar {
|
|
654
|
+
height: 13px; border-radius: 7px; margin-bottom: 13px;
|
|
655
|
+
background: linear-gradient(90deg,
|
|
656
|
+
color-mix(in srgb, var(--ink) 6%, transparent) 25%,
|
|
657
|
+
color-mix(in srgb, var(--ink) 13%, transparent) 50%,
|
|
658
|
+
color-mix(in srgb, var(--ink) 6%, transparent) 75%);
|
|
659
|
+
background-size: 200% 100%;
|
|
660
|
+
animation: shimmer 1.5s linear infinite;
|
|
661
|
+
}
|
|
662
|
+
.w35 { width: 35%; } .w40 { width: 40%; } .w45 { width: 45%; } .w50 { width: 50%; }
|
|
663
|
+
.w60 { width: 60%; } .w65 { width: 65%; } .w70 { width: 70%; } .w75 { width: 75%; }
|
|
664
|
+
.w80 { width: 80%; } .w85 { width: 85%; } .w88 { width: 88%; } .w90 { width: 90%; }
|
|
665
|
+
@keyframes shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }
|
|
666
|
+
|
|
667
|
+
.loading-note, .pending-note {
|
|
668
|
+
display: flex; align-items: flex-start; gap: 9px;
|
|
669
|
+
font-size: 13.5px; color: var(--ink-2); line-height: 1.55;
|
|
670
|
+
max-width: 76ch;
|
|
671
|
+
}
|
|
672
|
+
.loading-note::before, .pending-note::before { margin-top: 0.5em; }
|
|
673
|
+
.loading-note::before, .pending-note::before {
|
|
674
|
+
content: ""; flex: none; width: 7px; height: 7px; border-radius: 50%;
|
|
675
|
+
background: var(--cyan); animation: pulse-dot 1.6s var(--ease) infinite;
|
|
676
|
+
}
|
|
677
|
+
@keyframes pulse-dot { 0%, 100% { opacity: 1; } 50% { opacity: 0.25; } }
|
|
678
|
+
|
|
679
|
+
/* ============================== 9 · LEADS & DRILL-DOWNS ============================== */
|
|
680
|
+
|
|
681
|
+
.lead-stat { font-size: var(--fs-1); color: var(--ink-2); line-height: 1.5; max-width: none; }
|
|
682
|
+
.lead-stat b { color: var(--ink); font-weight: 700; font-variant-numeric: tabular-nums; }
|
|
683
|
+
|
|
684
|
+
.count-row { display: flex; flex-wrap: wrap; gap: 8px; margin: 4px 0 14px; }
|
|
685
|
+
|
|
686
|
+
/* Load-bearing trust statements — legible first (13.5px, ink-2), mono only for data. */
|
|
687
|
+
.fineprint {
|
|
688
|
+
font-family: var(--sans); font-size: 13.5px; color: var(--ink-2);
|
|
689
|
+
line-height: 1.55; max-width: none;
|
|
690
|
+
}
|
|
691
|
+
.fineprint b { color: var(--ink); }
|
|
692
|
+
|
|
693
|
+
/* nested drill-down (peeling back a layer) */
|
|
694
|
+
details.sub {
|
|
695
|
+
margin: 12px 0 0; border: 1px solid var(--hair); border-radius: 12px;
|
|
696
|
+
background: color-mix(in srgb, var(--ink) 2%, transparent);
|
|
697
|
+
overflow: hidden;
|
|
698
|
+
}
|
|
699
|
+
details.sub > summary {
|
|
700
|
+
list-style: none; cursor: pointer; user-select: none;
|
|
701
|
+
display: flex; align-items: center; gap: 10px;
|
|
702
|
+
padding: 11px 16px;
|
|
703
|
+
font-family: var(--mono); font-size: 12px; color: var(--cyan-text);
|
|
704
|
+
letter-spacing: 0.03em;
|
|
705
|
+
transition: background 0.18s var(--ease);
|
|
706
|
+
}
|
|
707
|
+
details.sub > summary::-webkit-details-marker { display: none; }
|
|
708
|
+
details.sub > summary:hover { background: var(--fill-cyan); }
|
|
709
|
+
details.sub > summary::before {
|
|
710
|
+
content: "›"; color: var(--amber-text); font-size: 14px;
|
|
711
|
+
transition: transform 0.25s var(--ease);
|
|
712
|
+
}
|
|
713
|
+
details.sub[open] > summary::before { transform: rotate(90deg); }
|
|
714
|
+
details.sub .sub-body { padding: 0 14px 14px; }
|
|
715
|
+
details.sub .sub-body > *:first-child { margin-top: 4px; }
|
|
716
|
+
|
|
717
|
+
/* ============================== 10 · SHADOW COPIES PANEL ============================== */
|
|
718
|
+
|
|
719
|
+
.shadows {
|
|
720
|
+
margin-top: 22px; padding: 16px 18px;
|
|
721
|
+
border: 1.5px dashed color-mix(in srgb, var(--cyan) 42%, transparent);
|
|
722
|
+
border-radius: 14px;
|
|
723
|
+
background: var(--fill-cyan);
|
|
724
|
+
}
|
|
725
|
+
.shadows-title {
|
|
726
|
+
display: flex; align-items: baseline; gap: 10px; margin: 0 0 4px;
|
|
727
|
+
font-family: var(--display); font-weight: 600; font-size: var(--fs-1); color: var(--ink);
|
|
728
|
+
}
|
|
729
|
+
.shadows-sub { font-size: var(--fs--1); color: var(--ink-2); margin-bottom: 12px; max-width: none; }
|
|
730
|
+
.shadow-row {
|
|
731
|
+
display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 14px;
|
|
732
|
+
padding: 9px 0; border-top: 1px dashed var(--hair);
|
|
733
|
+
}
|
|
734
|
+
.shadow-row:first-of-type { border-top: 0; }
|
|
735
|
+
.shadow-name { font-family: var(--mono); font-size: 0.86rem; color: var(--ink); }
|
|
736
|
+
.shadow-vers { font-family: var(--mono); font-size: 0.8rem; color: var(--muted); font-variant-numeric: tabular-nums; }
|
|
737
|
+
.shadow-vers b { color: var(--cyan-text); font-weight: 600; }
|
|
738
|
+
.shadow-dir {
|
|
739
|
+
flex-basis: 100%; font-family: var(--mono); font-size: 11.5px; color: var(--muted);
|
|
740
|
+
overflow-x: auto; white-space: nowrap; scrollbar-width: thin; padding-bottom: 2px;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
/* ============================== 11 · RECOMMENDATION CARDS ============================== */
|
|
744
|
+
|
|
745
|
+
.rec {
|
|
746
|
+
border: 1px solid var(--hair-strong); border-radius: var(--radius);
|
|
747
|
+
padding: clamp(16px, 2.4vw, 22px);
|
|
748
|
+
margin: 0 0 16px;
|
|
749
|
+
background: color-mix(in srgb, var(--ink) 2%, transparent);
|
|
750
|
+
transition: border-color 0.25s var(--ease), box-shadow 0.25s var(--ease);
|
|
751
|
+
}
|
|
752
|
+
.rec-top { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
|
|
753
|
+
.rec-top h3 { font-size: var(--fs-1); margin: 0; flex: 1 1 auto; min-width: 200px; }
|
|
754
|
+
.rec .rationale { margin: 8px 0 0; color: var(--ink-2); max-width: 64ch; }
|
|
755
|
+
|
|
756
|
+
/* the machine-touch banner — warm and plain, impossible to miss */
|
|
757
|
+
.impact-banner {
|
|
758
|
+
display: flex; gap: 14px; align-items: flex-start;
|
|
759
|
+
margin: 14px 0 0; padding: 14px 16px;
|
|
760
|
+
border: 1px solid color-mix(in srgb, var(--amber) 38%, transparent);
|
|
761
|
+
border-left: 3px solid var(--amber);
|
|
762
|
+
border-radius: 12px;
|
|
763
|
+
background: linear-gradient(120deg,
|
|
764
|
+
color-mix(in srgb, var(--amber) 11%, transparent),
|
|
765
|
+
color-mix(in srgb, var(--amber) 5%, transparent));
|
|
766
|
+
}
|
|
767
|
+
.impact-icon {
|
|
768
|
+
flex: none; width: 34px; height: 34px; border-radius: 10px;
|
|
769
|
+
display: grid; place-items: center;
|
|
770
|
+
background: color-mix(in srgb, var(--amber) 18%, transparent);
|
|
771
|
+
}
|
|
772
|
+
.impact-icon svg { width: 19px; height: 19px; fill: none; stroke: var(--amber-text); stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }
|
|
773
|
+
.impact-text { min-width: 0; }
|
|
774
|
+
.impact-title {
|
|
775
|
+
margin: 0 0 3px; font-weight: 700; color: var(--ink); font-size: var(--fs-0);
|
|
776
|
+
}
|
|
777
|
+
.impact-plain { margin: 0; font-size: var(--fs--1); color: var(--ink-2); line-height: 1.55; max-width: 62ch; }
|
|
778
|
+
.impact-rev {
|
|
779
|
+
display: inline-block; margin-top: 7px;
|
|
780
|
+
font-family: var(--mono); font-size: 12px; letter-spacing: 0.08em;
|
|
781
|
+
text-transform: uppercase; color: var(--green-text);
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
/* the calm counterpart for settings-only actions */
|
|
785
|
+
.impact-note {
|
|
786
|
+
display: flex; align-items: center; gap: 9px; margin: 12px 0 0;
|
|
787
|
+
font-size: var(--fs--1); color: var(--muted); max-width: none;
|
|
788
|
+
}
|
|
789
|
+
.impact-note::before {
|
|
790
|
+
content: ""; flex: none; width: 7px; height: 7px; border-radius: 50%; background: var(--green);
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
/* evidence / cost / change / undo */
|
|
794
|
+
.rec-facts { margin-top: 16px; border-top: 1px solid var(--hair); }
|
|
795
|
+
.fact {
|
|
796
|
+
display: grid; grid-template-columns: 90px minmax(0, 1fr);
|
|
797
|
+
gap: 4px 16px; padding: 11px 0; border-bottom: 1px dashed var(--hair);
|
|
798
|
+
align-items: baseline;
|
|
799
|
+
}
|
|
800
|
+
.fact:last-child { border-bottom: 0; }
|
|
801
|
+
.fact .k {
|
|
802
|
+
font-family: var(--mono); font-size: 11.5px; font-weight: 600;
|
|
803
|
+
letter-spacing: 0.14em; text-transform: uppercase;
|
|
804
|
+
}
|
|
805
|
+
.k-evidence { color: var(--cyan-text); }
|
|
806
|
+
.k-cost { color: var(--warn-text); }
|
|
807
|
+
.k-change { color: var(--muted); }
|
|
808
|
+
.k-undo { color: var(--green-text); }
|
|
809
|
+
.fact .v { font-size: var(--fs--1); color: var(--ink-2); min-width: 0; }
|
|
810
|
+
.fact .v p { max-width: none; }
|
|
811
|
+
|
|
812
|
+
.evidence-list { list-style: none; margin: 0; padding: 0; }
|
|
813
|
+
.evidence-list li { margin: 0 0 6px; padding-left: 14px; position: relative; }
|
|
814
|
+
.evidence-list li:last-child { margin-bottom: 0; }
|
|
815
|
+
.evidence-list li::before {
|
|
816
|
+
content: ""; position: absolute; left: 0; top: 0.52em;
|
|
817
|
+
width: 6px; height: 6px; border-radius: 50%; background: var(--cyan);
|
|
818
|
+
}
|
|
819
|
+
.evidence-list .src { font-family: var(--mono); font-size: 12px; color: var(--muted); }
|
|
820
|
+
|
|
821
|
+
.cost-row { display: flex; flex-wrap: wrap; gap: 6px 18px; }
|
|
822
|
+
.cost-item { font-family: var(--mono); font-size: 12.5px; color: var(--ink-2); font-variant-numeric: tabular-nums; }
|
|
823
|
+
.cost-item .ck { color: var(--muted); margin-right: 5px; text-transform: uppercase; letter-spacing: 0.06em; font-size: 11px; }
|
|
824
|
+
.risk-low { color: var(--green-text); }
|
|
825
|
+
.risk-medium { color: var(--warn-text); }
|
|
826
|
+
.risk-high { color: var(--red-text); }
|
|
827
|
+
|
|
828
|
+
/* actions */
|
|
829
|
+
.rec-actions { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin-top: 16px; }
|
|
830
|
+
|
|
831
|
+
.btn {
|
|
832
|
+
display: inline-flex; align-items: center; justify-content: center; gap: 8px;
|
|
833
|
+
font-family: var(--sans); font-weight: 600; font-size: 0.9rem; letter-spacing: 0.005em;
|
|
834
|
+
padding: 9px 18px; border-radius: 10px; border: 1px solid transparent;
|
|
835
|
+
cursor: pointer; white-space: nowrap;
|
|
836
|
+
transition: transform 0.14s var(--ease), filter 0.16s var(--ease),
|
|
837
|
+
background 0.18s var(--ease), border-color 0.18s var(--ease), box-shadow 0.2s var(--ease);
|
|
838
|
+
}
|
|
839
|
+
.btn:active { transform: scale(0.97); }
|
|
840
|
+
.btn[disabled] { opacity: 0.55; cursor: default; transform: none; }
|
|
841
|
+
|
|
842
|
+
.btn-apply {
|
|
843
|
+
background: var(--amber); color: var(--on-accent);
|
|
844
|
+
box-shadow: 0 10px 22px -12px color-mix(in srgb, var(--amber) 65%, transparent);
|
|
845
|
+
}
|
|
846
|
+
.btn-apply:hover:not([disabled]) { filter: brightness(1.07); transform: translateY(-1px); }
|
|
847
|
+
|
|
848
|
+
.btn-ghost { background: transparent; border-color: var(--hair-strong); color: var(--ink-2); }
|
|
849
|
+
.btn-ghost:hover:not([disabled]) { border-color: var(--amber); color: var(--ink); background: var(--fill); }
|
|
850
|
+
|
|
851
|
+
.btn-undo { background: transparent; border-color: color-mix(in srgb, var(--green) 45%, transparent); color: var(--green-text); }
|
|
852
|
+
.btn-undo:hover:not([disabled]) { background: var(--fill-green); }
|
|
853
|
+
|
|
854
|
+
.btn-sm { padding: 5px 12px; font-size: 0.84rem; border-radius: 8px; }
|
|
855
|
+
|
|
856
|
+
/* confirm step */
|
|
857
|
+
.confirm {
|
|
858
|
+
flex-basis: 100%;
|
|
859
|
+
border: 1px solid color-mix(in srgb, var(--amber) 36%, transparent);
|
|
860
|
+
border-radius: 12px; padding: 14px 16px;
|
|
861
|
+
background: color-mix(in srgb, var(--amber) 7%, transparent);
|
|
862
|
+
animation: rise 0.25s var(--ease) both;
|
|
863
|
+
}
|
|
864
|
+
.confirm-q { margin: 0 0 4px; font-weight: 700; color: var(--ink); font-size: var(--fs-0); max-width: none; }
|
|
865
|
+
.confirm-detail { margin: 0 0 12px; font-size: var(--fs--1); color: var(--ink-2); max-width: 62ch; }
|
|
866
|
+
.confirm-btns { display: flex; flex-wrap: wrap; gap: 10px; }
|
|
867
|
+
|
|
868
|
+
/* applied — the success moment */
|
|
869
|
+
.applied {
|
|
870
|
+
flex-basis: 100%;
|
|
871
|
+
border: 1px solid color-mix(in srgb, var(--green) 36%, transparent);
|
|
872
|
+
border-radius: 12px; padding: 15px 16px;
|
|
873
|
+
background: var(--fill-green);
|
|
874
|
+
animation: rise 0.3s var(--ease) both;
|
|
875
|
+
}
|
|
876
|
+
.applied-head { display: flex; align-items: center; gap: 11px; }
|
|
877
|
+
.applied-badge { flex: none; width: 30px; height: 30px; }
|
|
878
|
+
.applied-badge circle {
|
|
879
|
+
fill: none; stroke: var(--green); stroke-width: 2;
|
|
880
|
+
stroke-dasharray: 88; stroke-dashoffset: 88;
|
|
881
|
+
animation: draw 0.55s var(--ease) forwards;
|
|
882
|
+
}
|
|
883
|
+
.applied-badge path {
|
|
884
|
+
fill: none; stroke: var(--green); stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round;
|
|
885
|
+
stroke-dasharray: 26; stroke-dashoffset: 26;
|
|
886
|
+
animation: draw 0.4s 0.4s var(--ease) forwards;
|
|
887
|
+
}
|
|
888
|
+
@keyframes draw { to { stroke-dashoffset: 0; } }
|
|
889
|
+
.applied-title { margin: 0; font-weight: 700; color: var(--green-text); max-width: none; }
|
|
890
|
+
.applied-sub { margin: 2px 0 0; font-size: var(--fs--1); color: var(--ink-2); max-width: none; }
|
|
891
|
+
.applied .log {
|
|
892
|
+
font-family: var(--mono); font-size: 11.5px; line-height: 1.6; color: var(--ink-2);
|
|
893
|
+
background: color-mix(in srgb, var(--ink) 5%, transparent);
|
|
894
|
+
border: 1px solid var(--hair); border-radius: 8px;
|
|
895
|
+
padding: 10px 12px; margin: 12px 0; max-height: 190px; overflow: auto; white-space: pre-wrap;
|
|
896
|
+
}
|
|
897
|
+
.applied-btns { display: flex; gap: 10px; margin-top: 10px; }
|
|
898
|
+
|
|
899
|
+
.rec.is-applied {
|
|
900
|
+
border-color: color-mix(in srgb, var(--green) 45%, transparent);
|
|
901
|
+
animation: settle 1.1s var(--ease);
|
|
902
|
+
}
|
|
903
|
+
@keyframes settle {
|
|
904
|
+
0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--green) 38%, transparent); }
|
|
905
|
+
100% { box-shadow: 0 0 0 16px transparent; }
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
.reverted {
|
|
909
|
+
margin: 0 0 10px; font-size: var(--fs--1); color: var(--ink-2); max-width: none;
|
|
910
|
+
display: flex; align-items: center; gap: 9px;
|
|
911
|
+
}
|
|
912
|
+
.reverted::before { content: "↩"; color: var(--green-text); font-size: 1.05em; }
|
|
913
|
+
|
|
914
|
+
/* world moved */
|
|
915
|
+
.world-moved {
|
|
916
|
+
flex-basis: 100%;
|
|
917
|
+
border: 1px solid color-mix(in srgb, var(--cyan) 36%, transparent);
|
|
918
|
+
border-radius: 12px; padding: 14px 16px;
|
|
919
|
+
background: var(--fill-cyan);
|
|
920
|
+
}
|
|
921
|
+
.world-moved p { margin: 0 0 10px; font-size: var(--fs--1); color: var(--ink-2); max-width: 62ch; }
|
|
922
|
+
|
|
923
|
+
/* status line + errors */
|
|
924
|
+
.rec-status { margin: 10px 0 0; font-size: var(--fs--1); max-width: none; }
|
|
925
|
+
.rec-status[data-tone="error"] { color: var(--red-text); }
|
|
926
|
+
.rec-status[data-tone="ok"] { color: var(--green-text); }
|
|
927
|
+
|
|
928
|
+
/* skipped */
|
|
929
|
+
.rec.is-skipped > *:not(.skipped-row) { display: none; }
|
|
930
|
+
.rec.is-skipped { padding: 12px 18px; background: transparent; border-style: dashed; }
|
|
931
|
+
.skipped-row {
|
|
932
|
+
display: flex; align-items: center; justify-content: space-between; gap: 12px;
|
|
933
|
+
color: var(--muted); font-size: var(--fs--1);
|
|
934
|
+
}
|
|
935
|
+
.skipped-row .sk-title { font-family: var(--mono); font-size: 0.82rem; }
|
|
936
|
+
|
|
937
|
+
.severity-note { margin-top: 4px; }
|
|
938
|
+
|
|
939
|
+
/* empty recommendation state */
|
|
940
|
+
.recs-empty {
|
|
941
|
+
border: 1.5px dashed var(--hair-strong); border-radius: 14px;
|
|
942
|
+
padding: clamp(20px, 3vw, 30px); text-align: left;
|
|
943
|
+
}
|
|
944
|
+
.recs-empty .lead { font-family: var(--display); font-size: var(--fs-1); color: var(--ink); margin: 0 0 6px; }
|
|
945
|
+
.recs-empty p { color: var(--ink-2); font-size: var(--fs--1); max-width: 58ch; }
|
|
946
|
+
|
|
947
|
+
/* ============================== 12 · MEMORY ============================== */
|
|
948
|
+
|
|
949
|
+
.memory-top { display: grid; grid-template-columns: 1fr; gap: 20px 34px; align-items: center; }
|
|
950
|
+
@media (min-width: 44em) { .memory-top { grid-template-columns: auto minmax(0, 1fr); } }
|
|
951
|
+
|
|
952
|
+
.dial-wrap { width: 172px; margin-inline: auto; }
|
|
953
|
+
@media (min-width: 44em) { .dial-wrap { margin-inline: 0; } }
|
|
954
|
+
.dial { width: 100%; height: auto; display: block; }
|
|
955
|
+
.dial-track { fill: none; stroke: color-mix(in srgb, var(--ink) 11%, transparent); stroke-width: 10; stroke-linecap: round; }
|
|
956
|
+
.dial-value { fill: none; stroke-width: 10; stroke-linecap: round; transition: stroke-dasharray 1.1s var(--ease); }
|
|
957
|
+
.dial-num { font-family: var(--display); font-weight: 600; font-size: 34px; fill: var(--ink); }
|
|
958
|
+
.dial-sub { font-family: var(--mono); font-size: 9.5px; letter-spacing: 0.18em; fill: var(--muted); text-transform: uppercase; }
|
|
959
|
+
|
|
960
|
+
.mem-summary h3 { font-size: var(--fs-1); margin-bottom: 4px; }
|
|
961
|
+
.mem-summary .mem-line { color: var(--ink-2); max-width: 56ch; }
|
|
962
|
+
.mem-summary .fineprint { margin-top: 8px; }
|
|
963
|
+
|
|
964
|
+
.dims { margin-top: 20px; border-top: 1px solid var(--hair); }
|
|
965
|
+
.dim {
|
|
966
|
+
display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
|
|
967
|
+
gap: 3px 14px; align-items: baseline;
|
|
968
|
+
padding: 12px 0; border-bottom: 1px dashed var(--hair);
|
|
969
|
+
}
|
|
970
|
+
.dim:last-child { border-bottom: 0; }
|
|
971
|
+
.dim .chip { align-self: center; }
|
|
972
|
+
.dim-name { font-weight: 650; color: var(--ink); font-size: var(--fs--1); }
|
|
973
|
+
.dim-detail { grid-column: 2; font-size: var(--fs--1); color: var(--ink-2); }
|
|
974
|
+
.dim-ded {
|
|
975
|
+
grid-row: 1 / span 2; grid-column: 3; align-self: center;
|
|
976
|
+
font-family: var(--mono); font-size: 0.9rem; font-variant-numeric: tabular-nums;
|
|
977
|
+
color: var(--faint);
|
|
978
|
+
}
|
|
979
|
+
.dim-ded.has-ded { color: var(--warn-text); font-weight: 600; }
|
|
980
|
+
.dim.dim-nt { opacity: 0.66; }
|
|
981
|
+
|
|
982
|
+
/* ============================== 13 · SAVINGS ============================== */
|
|
983
|
+
|
|
984
|
+
.totals-strip { display: flex; flex-wrap: wrap; gap: 12px; margin-bottom: 16px; }
|
|
985
|
+
.total-tile {
|
|
986
|
+
flex: 1 1 130px; min-width: 130px;
|
|
987
|
+
border: 1px solid var(--hair); border-radius: 12px;
|
|
988
|
+
padding: 13px 16px 11px;
|
|
989
|
+
background: color-mix(in srgb, var(--ink) 2.5%, transparent);
|
|
990
|
+
}
|
|
991
|
+
.total-num {
|
|
992
|
+
font-family: var(--display); font-weight: 600; font-size: 1.55rem;
|
|
993
|
+
color: var(--ink); line-height: 1.1; font-variant-numeric: tabular-nums;
|
|
994
|
+
}
|
|
995
|
+
.total-lab {
|
|
996
|
+
font-family: var(--mono); font-size: 11.5px; letter-spacing: 0.1em;
|
|
997
|
+
text-transform: uppercase; color: var(--ink-2); margin-top: 3px;
|
|
998
|
+
}
|
|
999
|
+
.total-tile.t-green .total-num { color: var(--green-text); }
|
|
1000
|
+
|
|
1001
|
+
.savings-note { margin: 10px 0 0; }
|
|
1002
|
+
|
|
1003
|
+
.empty {
|
|
1004
|
+
border: 1.5px dashed var(--hair-strong); border-radius: 14px;
|
|
1005
|
+
padding: clamp(20px, 3vw, 30px);
|
|
1006
|
+
background: color-mix(in srgb, var(--ink) 1.5%, transparent);
|
|
1007
|
+
}
|
|
1008
|
+
.empty-lead { font-family: var(--display); font-size: var(--fs-1); color: var(--ink); margin: 0 0 6px; }
|
|
1009
|
+
.empty p { color: var(--ink-2); font-size: var(--fs--1); max-width: 58ch; }
|
|
1010
|
+
|
|
1011
|
+
/* ============================== 14 · SETTINGS ============================== */
|
|
1012
|
+
|
|
1013
|
+
.settings-form { margin-top: 4px; }
|
|
1014
|
+
.field {
|
|
1015
|
+
display: grid; grid-template-columns: minmax(0, 1fr); gap: 8px;
|
|
1016
|
+
padding: 15px 0; border-bottom: 1px dashed var(--hair);
|
|
1017
|
+
}
|
|
1018
|
+
@media (min-width: 48em) { .field { grid-template-columns: 280px minmax(0, 1fr); gap: 6px 28px; align-items: start; } }
|
|
1019
|
+
.field-label { font-weight: 650; color: var(--ink); font-size: var(--fs-0); }
|
|
1020
|
+
.field-help { font-size: var(--fs--1); color: var(--ink-2); margin: 2px 0 0; max-width: 40ch; }
|
|
1021
|
+
.field-ctl { display: flex; align-items: center; min-height: 34px; flex-wrap: wrap; gap: 8px; }
|
|
1022
|
+
|
|
1023
|
+
/* "Not chosen yet" — a control sitting on a RECOMMENDATION rather than on a stored answer. A switch
|
|
1024
|
+
or radio group has to render somewhere, and rendering it silently on the default let the page state
|
|
1025
|
+
a setting the user had never chosen. This note is the difference between the two, and it is text
|
|
1026
|
+
rather than colour so it survives greyscale and a screen reader. */
|
|
1027
|
+
.field-unset {
|
|
1028
|
+
font-size: var(--fs--1); color: var(--ink-2); max-width: 44ch;
|
|
1029
|
+
padding: 2px 8px; border-left: 2px dashed color-mix(in srgb, var(--ink) 28%, transparent);
|
|
1030
|
+
}
|
|
1031
|
+
.field-unset b { color: var(--ink); font-weight: 600; }
|
|
1032
|
+
|
|
1033
|
+
.text-input {
|
|
1034
|
+
width: 100%; max-width: 380px;
|
|
1035
|
+
font-family: var(--mono); font-size: 0.88rem; color: var(--ink);
|
|
1036
|
+
background: color-mix(in srgb, var(--ink) 4%, transparent);
|
|
1037
|
+
border: 1px solid var(--hair-strong); border-radius: 10px;
|
|
1038
|
+
padding: 9px 12px;
|
|
1039
|
+
transition: border-color 0.18s var(--ease), background 0.18s var(--ease);
|
|
1040
|
+
}
|
|
1041
|
+
.text-input:focus { outline: none; border-color: var(--cyan); background: var(--surface); }
|
|
1042
|
+
.text-input::placeholder { color: var(--faint); }
|
|
1043
|
+
|
|
1044
|
+
/* toggle */
|
|
1045
|
+
.switch { position: relative; display: inline-block; width: 46px; height: 26px; flex: none; }
|
|
1046
|
+
.switch input { position: absolute; inset: 0; opacity: 0; margin: 0; cursor: pointer; }
|
|
1047
|
+
.switch .track {
|
|
1048
|
+
position: absolute; inset: 0; border-radius: 100px;
|
|
1049
|
+
background: color-mix(in srgb, var(--ink) 14%, transparent);
|
|
1050
|
+
border: 1px solid var(--hair-strong);
|
|
1051
|
+
transition: background 0.2s var(--ease), border-color 0.2s var(--ease);
|
|
1052
|
+
pointer-events: none;
|
|
1053
|
+
}
|
|
1054
|
+
.switch .track::after {
|
|
1055
|
+
content: ""; position: absolute; top: 2px; left: 2px;
|
|
1056
|
+
width: 20px; height: 20px; border-radius: 50%;
|
|
1057
|
+
background: var(--surface);
|
|
1058
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.35);
|
|
1059
|
+
transition: transform 0.22s var(--ease);
|
|
1060
|
+
}
|
|
1061
|
+
.switch input:checked + .track { background: var(--green); border-color: transparent; }
|
|
1062
|
+
.switch input:checked + .track::after { transform: translateX(20px); background: #fdfdf9; }
|
|
1063
|
+
.switch input:focus-visible + .track { outline: 2px solid var(--cyan); outline-offset: 2px; }
|
|
1064
|
+
|
|
1065
|
+
/* segmented control */
|
|
1066
|
+
.seg { display: inline-flex; border: 1px solid var(--hair-strong); border-radius: 10px; overflow: hidden; background: color-mix(in srgb, var(--ink) 3%, transparent); }
|
|
1067
|
+
.seg label { position: relative; }
|
|
1068
|
+
.seg input { position: absolute; inset: 0; opacity: 0; margin: 0; cursor: pointer; }
|
|
1069
|
+
.seg .seg-lab {
|
|
1070
|
+
display: block; padding: 7px 16px; cursor: pointer;
|
|
1071
|
+
font-family: var(--mono); font-size: 0.84rem; color: var(--ink-2); letter-spacing: 0.02em;
|
|
1072
|
+
border-left: 1px solid var(--hair);
|
|
1073
|
+
transition: background 0.18s var(--ease), color 0.18s var(--ease);
|
|
1074
|
+
}
|
|
1075
|
+
.seg label:first-child .seg-lab { border-left: 0; }
|
|
1076
|
+
.seg input:checked + .seg-lab { background: var(--fill); color: var(--amber-text); font-weight: 700; }
|
|
1077
|
+
.seg input:focus-visible + .seg-lab { outline: 2px solid var(--cyan); outline-offset: -2px; }
|
|
1078
|
+
|
|
1079
|
+
/* secret */
|
|
1080
|
+
.secret-set-row, .secret-input-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
|
|
1081
|
+
.secret-set { letter-spacing: 0.14em; }
|
|
1082
|
+
|
|
1083
|
+
.save-row { display: flex; flex-wrap: wrap; align-items: center; gap: 14px 20px; margin-top: 20px; }
|
|
1084
|
+
.save-note { font-size: 13.5px; color: var(--ink-2); max-width: 56ch; line-height: 1.6; }
|
|
1085
|
+
.save-note code { font-size: 0.92em; }
|
|
1086
|
+
|
|
1087
|
+
.form-note { margin-top: 14px; border-radius: 12px; padding: 13px 16px; font-size: var(--fs--1); max-width: none; }
|
|
1088
|
+
.form-note.n-ok {
|
|
1089
|
+
border: 1px solid color-mix(in srgb, var(--green) 36%, transparent);
|
|
1090
|
+
background: var(--fill-green); color: var(--ink-2);
|
|
1091
|
+
display: flex; align-items: flex-start; gap: 11px; flex-wrap: wrap;
|
|
1092
|
+
}
|
|
1093
|
+
.form-note.n-err {
|
|
1094
|
+
border: 1px solid color-mix(in srgb, var(--red) 36%, transparent);
|
|
1095
|
+
background: color-mix(in srgb, var(--red) 8%, transparent); color: var(--ink-2);
|
|
1096
|
+
}
|
|
1097
|
+
.form-note .fn-body { flex: 1 1 260px; min-width: 0; }
|
|
1098
|
+
.form-note .fn-body b { color: var(--green-text); }
|
|
1099
|
+
.form-note .fn-path { font-family: var(--mono); font-size: 0.86em; color: var(--muted); overflow-wrap: anywhere; }
|
|
1100
|
+
|
|
1101
|
+
/* ============================== 15 · ERRORS & BANNERS ============================== */
|
|
1102
|
+
|
|
1103
|
+
.banner-error, .inline-error {
|
|
1104
|
+
border: 1px solid color-mix(in srgb, var(--red) 38%, transparent);
|
|
1105
|
+
border-left: 3px solid var(--red);
|
|
1106
|
+
border-radius: 12px;
|
|
1107
|
+
background: color-mix(in srgb, var(--red) 7%, transparent);
|
|
1108
|
+
padding: 14px 16px; margin: 16px 0 0;
|
|
1109
|
+
}
|
|
1110
|
+
.inline-error { margin: 16px 0 4px; }
|
|
1111
|
+
.ie-title { margin: 0 0 3px; font-weight: 700; color: var(--ink); max-width: none; }
|
|
1112
|
+
.ie-msg { margin: 0 0 10px; font-size: var(--fs--1); color: var(--ink-2); font-family: var(--mono); max-width: none; overflow-wrap: anywhere; }
|
|
1113
|
+
.banner-error p { margin: 0 0 8px; max-width: none; }
|
|
1114
|
+
.banner-error p:last-child, .inline-error > :last-child { margin-bottom: 0; }
|
|
1115
|
+
|
|
1116
|
+
/* ============================== 16 · FOOTER ============================== */
|
|
1117
|
+
|
|
1118
|
+
.foot { border-top: 1px solid var(--hair); padding: clamp(1.6rem, 3vw, 2.4rem) 0 clamp(2.2rem, 4vw, 3rem); }
|
|
1119
|
+
.foot-inner { display: flex; flex-wrap: wrap; gap: 8px 26px; align-items: baseline; justify-content: space-between; }
|
|
1120
|
+
.foot-line { margin: 0; font-size: var(--fs--1); color: var(--ink-2); max-width: none; }
|
|
1121
|
+
.foot-meta { margin: 0; font-size: 12px; color: var(--muted); letter-spacing: 0.03em; }
|
|
1122
|
+
|
|
1123
|
+
/* ============================== 17 · RESPONSIVE ============================== */
|
|
1124
|
+
|
|
1125
|
+
@media (max-width: 40em) {
|
|
1126
|
+
.card > summary { flex-wrap: wrap; }
|
|
1127
|
+
.chips { max-width: none; width: 100%; order: 4; justify-content: flex-start; margin-top: 2px; }
|
|
1128
|
+
.chev { order: 3; }
|
|
1129
|
+
.brand-sub { display: none; }
|
|
1130
|
+
/* the machine readout only — chrome. The tips door no longer shares this class
|
|
1131
|
+
(it once did, which made tips.html unreachable on phones — see THE TIPS DOOR below). */
|
|
1132
|
+
.host-chip { display: none; }
|
|
1133
|
+
/* Pre-existing header overflow, caught while verifying this pass at 375px (confirmed present on
|
|
1134
|
+
the unmodified file too, so unrelated to the card-grouping work above): the update-gong's full
|
|
1135
|
+
sentence ("update available · vX.Y.Z-dev — click to update") is `white-space: nowrap` with no
|
|
1136
|
+
width cap, so on a narrow phone it pushes the whole header wider than the viewport and forces a
|
|
1137
|
+
page-wide horizontal scrollbar. Cap + ellipsis keeps the click target and the full text in the
|
|
1138
|
+
title tooltip; nothing about the update claim is hidden, only its overflow. */
|
|
1139
|
+
.update-gong { max-width: 46vw; overflow: hidden; text-overflow: ellipsis; }
|
|
1140
|
+
.fact { grid-template-columns: minmax(0, 1fr); gap: 3px; }
|
|
1141
|
+
.dim { grid-template-columns: auto minmax(0, 1fr); }
|
|
1142
|
+
.dim-ded { grid-row: auto; grid-column: 2; }
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
/* ============================== 18 · MOTION & FORCED COLORS ============================== */
|
|
1146
|
+
|
|
1147
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1148
|
+
html { scroll-behavior: auto; }
|
|
1149
|
+
*, *::before, *::after {
|
|
1150
|
+
animation-duration: 0.001ms !important;
|
|
1151
|
+
animation-iteration-count: 1 !important;
|
|
1152
|
+
transition-duration: 0.001ms !important;
|
|
1153
|
+
}
|
|
1154
|
+
.btn:hover, .btn:active, .theme-toggle:active { transform: none !important; }
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
@media (forced-colors: active) {
|
|
1158
|
+
.chip, .btn, .card, .rec, .impact-banner, .applied, .confirm { border: 1px solid CanvasText; }
|
|
1159
|
+
.spectrum-edge, .sk-bar { forced-color-adjust: none; }
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
/* ── in-row remedies + attention flash (v3.1: no status without a remedy) ───── */
|
|
1163
|
+
.btn-fix {
|
|
1164
|
+
margin-left: 8px; padding: 3px 10px; border-radius: 999px;
|
|
1165
|
+
border: 1px solid color-mix(in srgb, var(--amber) 55%, transparent);
|
|
1166
|
+
background: color-mix(in srgb, var(--amber) 14%, transparent);
|
|
1167
|
+
color: var(--amber-text); font: 600 12.5px/1.4 var(--sans);
|
|
1168
|
+
cursor: pointer; white-space: nowrap; vertical-align: middle;
|
|
1169
|
+
}
|
|
1170
|
+
.btn-fix:hover { background: color-mix(in srgb, var(--amber) 26%, transparent); }
|
|
1171
|
+
.rec-flash { animation: recflash 2.4s var(--ease); }
|
|
1172
|
+
@keyframes recflash {
|
|
1173
|
+
0%, 55% { box-shadow: 0 0 0 3px color-mix(in srgb, var(--amber) 70%, transparent); }
|
|
1174
|
+
100% { box-shadow: 0 0 0 0 transparent; }
|
|
1175
|
+
}
|
|
1176
|
+
.loading-note .elapsed { color: var(--ink); font-weight: 600; }
|
|
1177
|
+
|
|
1178
|
+
/* ============================== 19 · UX-HARDENING (legible-first pass) ============================== */
|
|
1179
|
+
|
|
1180
|
+
/* WP5 — page-level standby line: private / local / built for you. Fades on first hydration. */
|
|
1181
|
+
.standby-note {
|
|
1182
|
+
display: flex; align-items: flex-start; gap: 10px;
|
|
1183
|
+
margin: 14px 0 0; font-size: 14.5px; color: var(--ink-2); line-height: 1.6;
|
|
1184
|
+
max-width: 80ch; transition: opacity 0.6s var(--ease);
|
|
1185
|
+
}
|
|
1186
|
+
.standby-note::before {
|
|
1187
|
+
content: ""; flex: none; width: 8px; height: 8px; border-radius: 50%;
|
|
1188
|
+
margin-top: 0.5em; background: var(--cyan); animation: pulse-dot 1.6s var(--ease) infinite;
|
|
1189
|
+
}
|
|
1190
|
+
.standby-note.gone { opacity: 0; }
|
|
1191
|
+
|
|
1192
|
+
/* WP2a — provenance badge: the trust statement, worn openly next to the numbers */
|
|
1193
|
+
.prov-badge {
|
|
1194
|
+
display: inline-flex; align-items: center; gap: 9px;
|
|
1195
|
+
margin: 2px 0 14px; padding: 8px 14px; border-radius: 100px;
|
|
1196
|
+
border: 1px solid color-mix(in srgb, var(--green) 38%, transparent);
|
|
1197
|
+
background: color-mix(in srgb, var(--green) 8%, transparent);
|
|
1198
|
+
font-size: 13.5px; color: var(--ink-2); line-height: 1.45;
|
|
1199
|
+
}
|
|
1200
|
+
.prov-badge b { color: var(--ink); font-variant-numeric: tabular-nums; }
|
|
1201
|
+
.prov-dot { flex: none; width: 9px; height: 9px; border-radius: 50%; background: var(--green);
|
|
1202
|
+
box-shadow: 0 0 0 3px color-mix(in srgb, var(--green) 22%, transparent); }
|
|
1203
|
+
|
|
1204
|
+
/* Plan block (issue #24) — two plainly-labelled boxes replace the old flat "provider chips" row:
|
|
1205
|
+
YOUR PLAN (the one cost choice, with a real per-provider key checklist) and OPENROUTER (a separate
|
|
1206
|
+
switch). Replaces the former .prov-strip / .prov-chip rules, which nothing else used. */
|
|
1207
|
+
.plan-group { display: grid; gap: 10px; margin: 14px 0 2px; }
|
|
1208
|
+
.plan-box {
|
|
1209
|
+
padding: 12px 14px; border-radius: 12px;
|
|
1210
|
+
border: 1px solid var(--hair); background: color-mix(in srgb, var(--ink) 2%, transparent);
|
|
1211
|
+
}
|
|
1212
|
+
.plan-label {
|
|
1213
|
+
display: block; font-size: 10.5px; font-weight: 700; letter-spacing: 0.18em;
|
|
1214
|
+
text-transform: uppercase; color: var(--muted); margin-bottom: 7px;
|
|
1215
|
+
}
|
|
1216
|
+
.plan-head { display: flex; align-items: center; gap: 9px; }
|
|
1217
|
+
.plan-dot { flex: none; width: 9px; height: 9px; border-radius: 50%; background: var(--faint); }
|
|
1218
|
+
.plan-dot.is-house { background: var(--green); box-shadow: 0 0 0 3px color-mix(in srgb, var(--green) 18%, transparent); }
|
|
1219
|
+
.plan-dot.is-lane.on { background: var(--cyan); box-shadow: 0 0 0 3px color-mix(in srgb, var(--cyan) 18%, transparent); }
|
|
1220
|
+
.plan-dot.is-lane.off { background: var(--faint); }
|
|
1221
|
+
.plan-name { font: 650 15px/1.3 var(--sans); color: var(--ink); letter-spacing: -0.01em; }
|
|
1222
|
+
.plan-action {
|
|
1223
|
+
margin-left: auto; font: 600 12px/1 var(--sans); color: var(--ink-2);
|
|
1224
|
+
padding: 5px 11px; border-radius: 100px; cursor: pointer;
|
|
1225
|
+
border: 1px solid var(--hair-strong); background: transparent;
|
|
1226
|
+
transition: border-color 0.18s var(--ease), color 0.18s var(--ease), background 0.18s var(--ease);
|
|
1227
|
+
}
|
|
1228
|
+
.plan-action:hover { border-color: var(--amber); color: var(--ink); background: var(--fill); }
|
|
1229
|
+
.plan-sub { margin: 6px 0 0; font-size: 12.5px; line-height: 1.5; color: var(--ink-2); max-width: none; }
|
|
1230
|
+
.plan-keys {
|
|
1231
|
+
display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px;
|
|
1232
|
+
margin-top: 10px; padding-top: 9px; border-top: 1px solid var(--hair); font-size: 12px;
|
|
1233
|
+
}
|
|
1234
|
+
.plan-keys-lab { color: var(--muted); font-weight: 600; }
|
|
1235
|
+
.plan-key { display: inline-flex; align-items: center; gap: 4px; color: var(--ink-2); }
|
|
1236
|
+
.plan-key-mark { font-weight: 700; }
|
|
1237
|
+
.plan-key.yes .plan-key-mark { color: var(--green-text); }
|
|
1238
|
+
.plan-key.no, .plan-key.no .plan-key-mark { color: var(--faint); }
|
|
1239
|
+
|
|
1240
|
+
/* WP2b — first-run empty state: confident, designed, not an apology */
|
|
1241
|
+
.mh-empty {
|
|
1242
|
+
margin-top: 16px; padding: clamp(20px, 3vw, 28px);
|
|
1243
|
+
border: 1px solid var(--hair-strong); border-left: 3px solid var(--amber);
|
|
1244
|
+
border-radius: 14px;
|
|
1245
|
+
background: linear-gradient(120deg, color-mix(in srgb, var(--amber) 6%, transparent), color-mix(in srgb, var(--green) 4%, transparent));
|
|
1246
|
+
}
|
|
1247
|
+
.mh-empty-title { font-family: var(--display); font-size: var(--fs-2); color: var(--ink); margin: 0 0 8px; }
|
|
1248
|
+
.mh-empty-body { font-size: var(--fs-0); color: var(--ink-2); line-height: 1.6; max-width: 62ch; margin: 0; }
|
|
1249
|
+
.mh-empty-body b { color: var(--ink); }
|
|
1250
|
+
|
|
1251
|
+
/* WP3/WP4/WP6 — the ⓘ click-to-learn affordance + one shared popover */
|
|
1252
|
+
.info-btn {
|
|
1253
|
+
display: inline-grid; place-items: center; flex: none;
|
|
1254
|
+
width: 19px; height: 19px; border-radius: 50%; margin-left: 7px;
|
|
1255
|
+
vertical-align: text-bottom;
|
|
1256
|
+
border: 1px solid color-mix(in srgb, var(--cyan) 45%, transparent);
|
|
1257
|
+
background: color-mix(in srgb, var(--cyan) 9%, transparent);
|
|
1258
|
+
color: var(--cyan-text); font: 600 12px/1 var(--display); font-style: italic;
|
|
1259
|
+
cursor: pointer; transition: background 0.18s var(--ease), border-color 0.18s var(--ease);
|
|
1260
|
+
}
|
|
1261
|
+
.info-btn:hover { background: color-mix(in srgb, var(--cyan) 20%, transparent); border-color: var(--cyan); }
|
|
1262
|
+
.info-pop {
|
|
1263
|
+
position: fixed; z-index: 90; max-width: 360px; min-width: 240px;
|
|
1264
|
+
padding: 15px 17px; border-radius: 12px;
|
|
1265
|
+
border: 1px solid var(--ridge); background: var(--surface);
|
|
1266
|
+
box-shadow: var(--shadow-deep);
|
|
1267
|
+
animation: rise 0.18s var(--ease) both;
|
|
1268
|
+
}
|
|
1269
|
+
.info-pop .ip-title {
|
|
1270
|
+
font-family: var(--display); font-weight: 600; font-size: 15px;
|
|
1271
|
+
color: var(--ink); margin: 0 0 8px; max-width: none;
|
|
1272
|
+
}
|
|
1273
|
+
.info-pop .ip-beat { margin: 0 0 9px; font-size: 13.5px; color: var(--ink-2); line-height: 1.55; max-width: none; }
|
|
1274
|
+
.info-pop .ip-beat:last-child { margin-bottom: 0; }
|
|
1275
|
+
.info-pop .ip-k {
|
|
1276
|
+
display: block; font-family: var(--mono); font-size: 11px; font-weight: 600;
|
|
1277
|
+
letter-spacing: 0.1em; text-transform: uppercase; color: var(--cyan-text); margin-bottom: 1px;
|
|
1278
|
+
}
|
|
1279
|
+
.info-pop .ip-close {
|
|
1280
|
+
position: absolute; top: 8px; right: 8px;
|
|
1281
|
+
width: 24px; height: 24px; border-radius: 8px; border: 0; cursor: pointer;
|
|
1282
|
+
background: transparent; color: var(--muted); font-size: 15px; line-height: 1;
|
|
1283
|
+
}
|
|
1284
|
+
.info-pop .ip-close:hover { background: var(--fill); color: var(--ink); }
|
|
1285
|
+
|
|
1286
|
+
/* settings rows are jump-targets for the provider chips (rec-flash lands on them) */
|
|
1287
|
+
.field { border-radius: 10px; }
|
|
1288
|
+
.field.rec-flash { padding-left: 10px; padding-right: 10px; }
|
|
1289
|
+
|
|
1290
|
+
/* How it's wired — the four launch lanes as one proportional bar + legend (2026-07-16).
|
|
1291
|
+
Lane colors: global = grounded green (one verifiable path), npx = amber (can drift),
|
|
1292
|
+
MCP = cyan (observed/live), plugin = neutral. */
|
|
1293
|
+
.wire-bar { display: flex; height: 18px; border-radius: 9px; overflow: hidden; margin: 10px 0 14px; border: 1px solid var(--hair); }
|
|
1294
|
+
.wire-seg { display: block; min-width: 6px; }
|
|
1295
|
+
.w-global { background: var(--green, #5fd38a); }
|
|
1296
|
+
.w-npx { background: var(--amber, #f0a830); }
|
|
1297
|
+
.w-mcp { background: var(--cyan, #5ad6ff); }
|
|
1298
|
+
.w-plugin { background: var(--muted, #9aa1ad); }
|
|
1299
|
+
.wire-lanes { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 8px 18px; margin-bottom: 14px; }
|
|
1300
|
+
.wire-lane { display: grid; grid-template-columns: 10px auto auto; grid-template-rows: auto auto; align-items: baseline; column-gap: 8px; }
|
|
1301
|
+
.wire-lane.is-empty { opacity: 0.55; }
|
|
1302
|
+
.wire-dot { width: 10px; height: 10px; border-radius: 50%; align-self: center; }
|
|
1303
|
+
.wire-n { font-size: 1.15rem; }
|
|
1304
|
+
.wire-lab { font-family: var(--mono, ui-monospace, monospace); font-size: 0.82rem; }
|
|
1305
|
+
.wire-meaning { grid-column: 2 / -1; font-size: 0.85rem; line-height: 1.4; }
|
|
1306
|
+
|
|
1307
|
+
/* ============================== 20 · TRUST & PROVENANCE (v3.3 preview) ============================== */
|
|
1308
|
+
|
|
1309
|
+
/* Four rows: signature (real today) · SBOM (honest empty) · channel (real) · advisor (preview).
|
|
1310
|
+
Same grammar as the rest of the page: status chip, plain-words value, mono only for data. */
|
|
1311
|
+
.trust-list { margin-top: 16px; border: 1px solid var(--hair); border-radius: 12px; overflow: hidden; background: color-mix(in srgb, var(--ink) 2%, transparent); }
|
|
1312
|
+
.trust-row { display: grid; grid-template-columns: minmax(150px, 0.9fr) minmax(0, 2.1fr) auto; gap: 6px 16px; padding: 14px 16px; align-items: start; }
|
|
1313
|
+
.trust-row + .trust-row { border-top: 1px solid var(--hair); }
|
|
1314
|
+
.trust-row.is-coming { background: color-mix(in srgb, var(--ink) 1.5%, transparent); }
|
|
1315
|
+
.trust-name { font-weight: 650; color: var(--ink); font-size: var(--fs--1); display: inline-flex; align-items: center; }
|
|
1316
|
+
.trust-val { min-width: 0; font-size: var(--fs--1); color: var(--ink-2); line-height: 1.55; }
|
|
1317
|
+
.trust-val p { max-width: none; margin: 0 0 4px; font-size: inherit; }
|
|
1318
|
+
.trust-val p:last-child { margin-bottom: 0; }
|
|
1319
|
+
.trust-hash {
|
|
1320
|
+
display: block; font-family: var(--mono); font-size: 11.5px; letter-spacing: 0.02em;
|
|
1321
|
+
color: var(--green-text); overflow-wrap: anywhere; line-height: 1.5;
|
|
1322
|
+
padding: 6px 9px; border-radius: 8px; margin: 4px 0;
|
|
1323
|
+
background: color-mix(in srgb, var(--green) 7%, transparent);
|
|
1324
|
+
border: 1px solid color-mix(in srgb, var(--green) 22%, transparent);
|
|
1325
|
+
}
|
|
1326
|
+
.trust-src { font-family: var(--mono); font-size: 11px; color: var(--muted); overflow-wrap: anywhere; }
|
|
1327
|
+
.trust-status { justify-self: end; display: inline-flex; flex-direction: column; align-items: flex-end; gap: 6px; }
|
|
1328
|
+
|
|
1329
|
+
/* "coming" chip — dashed like every honest not-yet state on this page */
|
|
1330
|
+
.chip.tone-coming { color: var(--muted); border-style: dashed; background: transparent; }
|
|
1331
|
+
|
|
1332
|
+
/* Advisor Mode preview switch: a real segmented control, deliberately inert — the preview
|
|
1333
|
+
tag says so before anyone clicks. */
|
|
1334
|
+
.adv-seg { display: inline-flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 2px; }
|
|
1335
|
+
.adv-opt {
|
|
1336
|
+
display: inline-flex; align-items: center; gap: 7px;
|
|
1337
|
+
font: 500 13px/1.4 var(--sans); padding: 6px 13px; border-radius: 100px;
|
|
1338
|
+
border: 1px dashed var(--hair-strong); background: transparent; color: var(--ink-2);
|
|
1339
|
+
cursor: pointer; transition: border-color 0.18s var(--ease), background 0.18s var(--ease);
|
|
1340
|
+
}
|
|
1341
|
+
.adv-opt .pc-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--faint); flex: none; }
|
|
1342
|
+
.adv-opt.on {
|
|
1343
|
+
border-style: solid; color: var(--ink);
|
|
1344
|
+
border-color: color-mix(in srgb, var(--green) 40%, transparent);
|
|
1345
|
+
background: color-mix(in srgb, var(--green) 9%, transparent);
|
|
1346
|
+
}
|
|
1347
|
+
.adv-opt.on .pc-dot { background: var(--green); }
|
|
1348
|
+
.adv-opt:hover { border-color: var(--amber); background: var(--fill); }
|
|
1349
|
+
.preview-tag {
|
|
1350
|
+
font-family: var(--mono); font-size: 10px; font-weight: 600; letter-spacing: 0.14em;
|
|
1351
|
+
text-transform: uppercase; color: var(--warn-text);
|
|
1352
|
+
border: 1px dashed color-mix(in srgb, var(--warn) 45%, transparent);
|
|
1353
|
+
border-radius: 100px; padding: 2px 8px;
|
|
1354
|
+
}
|
|
1355
|
+
.adv-note { margin-top: 8px; font-size: 13px; color: var(--muted); max-width: 60ch; }
|
|
1356
|
+
|
|
1357
|
+
@media (max-width: 40em) {
|
|
1358
|
+
.trust-row { grid-template-columns: minmax(0, 1fr) auto; }
|
|
1359
|
+
.trust-val { grid-column: 1 / -1; order: 3; }
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
/* Stack card: version on the family row (problem rows show installed -> target inline). */
|
|
1363
|
+
.fam-ver { font-family: var(--mono, ui-monospace, monospace); font-size: 0.8rem; color: var(--muted, #9aa1ad); margin-right: 8px; }
|
|
1364
|
+
.fam-ver.is-behind { color: var(--amber, #f0a830); font-weight: 600; }
|
|
1365
|
+
.shadows-ok { font-size: 0.9rem; color: var(--muted, #9aa1ad); margin: 8px 0 4px; }
|
|
1366
|
+
|
|
1367
|
+
/* ── What caught Claude — the catch ledger ────────────────────────────────────────────────────────
|
|
1368
|
+
A catch is a sentence (who stopped what, and why), not a table row. The wiring card's .wire-lane
|
|
1369
|
+
grid was built for counts and flings a gate name away from its subject across a dead gap, so this
|
|
1370
|
+
flows as text and wraps like text. */
|
|
1371
|
+
.gate-catches { list-style: none; margin: 10px 0 0; padding: 0; display: grid; gap: 8px; }
|
|
1372
|
+
.gate-catches li {
|
|
1373
|
+
font-size: var(--step--1); line-height: 1.5; padding: 9px 12px;
|
|
1374
|
+
border: 1px solid var(--line); border-radius: 9px; background: var(--fill);
|
|
1375
|
+
}
|
|
1376
|
+
.gate-catches li b { color: var(--ink); }
|
|
1377
|
+
|
|
1378
|
+
/* ============ 13b · SAVINGS — distribution redesign (appended 2026-07-17) ============
|
|
1379
|
+
Verdict-first replacement for the four-box distribution table: money headline,
|
|
1380
|
+
ONE continuous stacked bar, frontier-at-zero stated as a feature. New dv-* classes
|
|
1381
|
+
only — the old .dist-* rules above are intentionally untouched (concurrent session). */
|
|
1382
|
+
.dv-wrap { margin-top: 20px; }
|
|
1383
|
+
|
|
1384
|
+
.dv-hero-num {
|
|
1385
|
+
font-family: var(--display); font-weight: 600; font-size: var(--fs-3);
|
|
1386
|
+
color: var(--green-text); line-height: 1.05; letter-spacing: -0.01em;
|
|
1387
|
+
font-variant-numeric: tabular-nums;
|
|
1388
|
+
}
|
|
1389
|
+
.dv-hero-word { font-size: 0.52em; color: var(--ink); font-weight: 600; margin-left: 0.14em; }
|
|
1390
|
+
.dv-hero-sub { margin: 6px 0 0; font-size: var(--fs-0); color: var(--ink-2); line-height: 1.5; }
|
|
1391
|
+
.dv-hero-sub b { color: var(--ink); font-weight: 650; font-variant-numeric: tabular-nums; }
|
|
1392
|
+
.dv-hero-math { margin: 3px 0 0; font-size: 13px; color: var(--muted); line-height: 1.5; }
|
|
1393
|
+
|
|
1394
|
+
.dv-bar {
|
|
1395
|
+
display: flex; gap: 2px; height: 28px; margin: 16px 0 12px;
|
|
1396
|
+
border-radius: 8px; overflow: hidden;
|
|
1397
|
+
}
|
|
1398
|
+
.dv-seg {
|
|
1399
|
+
position: relative; min-width: 6px; overflow: hidden;
|
|
1400
|
+
display: flex; align-items: center; justify-content: center;
|
|
1401
|
+
}
|
|
1402
|
+
.dv-seg.b-mech { background: var(--green); }
|
|
1403
|
+
.dv-seg.b-cheap { background: var(--cyan); }
|
|
1404
|
+
.dv-seg.b-mid { background: var(--warn); }
|
|
1405
|
+
.dv-seg.b-front { background: var(--red); }
|
|
1406
|
+
.dv-seg-lab {
|
|
1407
|
+
font-family: var(--mono); font-size: 11px; font-weight: 600;
|
|
1408
|
+
letter-spacing: 0.05em; text-transform: uppercase; white-space: nowrap;
|
|
1409
|
+
color: var(--on-accent);
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
.dv-legend { display: flex; flex-direction: column; gap: 7px; }
|
|
1413
|
+
.dv-leg-row {
|
|
1414
|
+
display: grid; grid-template-columns: 12px 88px minmax(0, 1fr) auto;
|
|
1415
|
+
gap: 10px; align-items: baseline;
|
|
1416
|
+
}
|
|
1417
|
+
.dv-dot { width: 10px; height: 10px; border-radius: 3px; align-self: center; }
|
|
1418
|
+
.dv-dot.b-mech { background: var(--green); }
|
|
1419
|
+
.dv-dot.b-cheap { background: var(--cyan); }
|
|
1420
|
+
.dv-dot.b-mid { background: var(--warn); }
|
|
1421
|
+
.dv-dot.b-front { background: var(--red); }
|
|
1422
|
+
.dv-leg-band {
|
|
1423
|
+
font-family: var(--mono); font-size: 11.5px; font-weight: 600;
|
|
1424
|
+
text-transform: uppercase; letter-spacing: 0.05em; white-space: nowrap;
|
|
1425
|
+
}
|
|
1426
|
+
.dv-leg-band.b-mech { color: var(--green-text); }
|
|
1427
|
+
.dv-leg-band.b-cheap { color: var(--cyan-text); }
|
|
1428
|
+
.dv-leg-band.b-mid { color: var(--warn-text); }
|
|
1429
|
+
.dv-leg-band.b-front { color: var(--red-text); }
|
|
1430
|
+
.dv-leg-meta { font-size: 13px; color: var(--ink-2); overflow-wrap: anywhere; }
|
|
1431
|
+
.dv-leg-meta b { color: var(--ink); font-weight: 650; }
|
|
1432
|
+
.dv-leg-saved {
|
|
1433
|
+
font-family: var(--mono); font-size: 12.5px; color: var(--green-text);
|
|
1434
|
+
text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums;
|
|
1435
|
+
}
|
|
1436
|
+
.dv-check {
|
|
1437
|
+
color: var(--green-text); font-weight: 700; font-size: 13px;
|
|
1438
|
+
line-height: 1; align-self: center; text-align: center;
|
|
1439
|
+
}
|
|
1440
|
+
.dv-wrap .fineprint { margin-top: 12px; }
|
|
1441
|
+
|
|
1442
|
+
@media (max-width: 560px) {
|
|
1443
|
+
.dv-leg-row { grid-template-columns: 12px 74px minmax(0, 1fr); }
|
|
1444
|
+
.dv-leg-saved { grid-column: 3; text-align: left; }
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
/* ============================== APPENDED · WIRING VERDICT (2026-07-17) ==============================
|
|
1448
|
+
The wiring card now leads with the ANSWER ("can anything here silently run stale?") instead of a
|
|
1449
|
+
census. Banner speaks in the house's .impact-banner voice; the lane counts collapse into a quiet
|
|
1450
|
+
legend patterned on .dv-leg-row. Append-only block — a concurrent session owns the rules above;
|
|
1451
|
+
.wire-bar/.wire-lanes above are superseded by these, not edited. */
|
|
1452
|
+
.wire-verdict {
|
|
1453
|
+
display: flex; gap: 14px; align-items: flex-start;
|
|
1454
|
+
margin: 2px 0 0; padding: 15px 17px;
|
|
1455
|
+
border: 1px solid color-mix(in srgb, var(--green) 36%, transparent);
|
|
1456
|
+
border-left: 3px solid var(--green);
|
|
1457
|
+
border-radius: 12px;
|
|
1458
|
+
background: linear-gradient(120deg,
|
|
1459
|
+
color-mix(in srgb, var(--green) 10%, transparent),
|
|
1460
|
+
color-mix(in srgb, var(--green) 4%, transparent));
|
|
1461
|
+
}
|
|
1462
|
+
.wire-verdict.is-drift {
|
|
1463
|
+
border-color: color-mix(in srgb, var(--amber) 40%, transparent);
|
|
1464
|
+
border-left-color: var(--amber);
|
|
1465
|
+
background: linear-gradient(120deg,
|
|
1466
|
+
color-mix(in srgb, var(--amber) 11%, transparent),
|
|
1467
|
+
color-mix(in srgb, var(--amber) 5%, transparent));
|
|
1468
|
+
}
|
|
1469
|
+
.wv-icon {
|
|
1470
|
+
flex: none; width: 34px; height: 34px; border-radius: 10px;
|
|
1471
|
+
display: grid; place-items: center; margin-top: 1px;
|
|
1472
|
+
background: color-mix(in srgb, var(--green) 16%, transparent);
|
|
1473
|
+
}
|
|
1474
|
+
.wire-verdict.is-drift .wv-icon { background: color-mix(in srgb, var(--amber) 18%, transparent); }
|
|
1475
|
+
.wv-icon svg {
|
|
1476
|
+
width: 19px; height: 19px; fill: none; stroke: var(--green-text);
|
|
1477
|
+
stroke-width: 2; stroke-linecap: round; stroke-linejoin: round;
|
|
1478
|
+
}
|
|
1479
|
+
.wire-verdict.is-drift .wv-icon svg { stroke: var(--amber-text); }
|
|
1480
|
+
.wv-text { min-width: 0; }
|
|
1481
|
+
.wv-title {
|
|
1482
|
+
margin: 0 0 4px; font-family: var(--display); font-weight: 700;
|
|
1483
|
+
font-size: var(--fs-1); line-height: 1.35; color: var(--ink);
|
|
1484
|
+
max-width: none; text-wrap: balance;
|
|
1485
|
+
}
|
|
1486
|
+
.wv-sub { margin: 0; font-size: var(--fs--1); color: var(--ink-2); line-height: 1.55; max-width: 72ch; }
|
|
1487
|
+
.wv-sub b { color: var(--ink); font-weight: 700; font-variant-numeric: tabular-nums; }
|
|
1488
|
+
|
|
1489
|
+
/* drift sites — each offender is a sentence-row (who · where · what it launches) */
|
|
1490
|
+
.wv-sites { list-style: none; margin: 12px 0 0; padding: 0; }
|
|
1491
|
+
.wv-sites li {
|
|
1492
|
+
display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px;
|
|
1493
|
+
padding: 8px 0 0; margin-top: 8px;
|
|
1494
|
+
border-top: 1px dashed color-mix(in srgb, var(--amber) 30%, transparent);
|
|
1495
|
+
font-size: 13.5px; color: var(--ink-2);
|
|
1496
|
+
}
|
|
1497
|
+
.wv-sites .site-where { font-family: var(--mono); font-size: 0.82rem; color: var(--ink); }
|
|
1498
|
+
.wv-sites .site-spec { font-family: var(--mono); font-size: 0.8rem; color: var(--muted); overflow-wrap: anywhere; }
|
|
1499
|
+
|
|
1500
|
+
/* subordinate lane legend — one quiet line per lane in use; zero-lanes are omitted, not excused */
|
|
1501
|
+
.wire-legend { margin: 14px 0 2px; display: grid; gap: 7px; }
|
|
1502
|
+
.wire-leg-row {
|
|
1503
|
+
display: grid; grid-template-columns: 10px auto auto minmax(0, 1fr);
|
|
1504
|
+
align-items: baseline; column-gap: 10px;
|
|
1505
|
+
}
|
|
1506
|
+
.wire-leg-row .wire-dot { align-self: center; }
|
|
1507
|
+
.wire-leg-n { font-family: var(--mono); font-size: 0.88rem; font-variant-numeric: tabular-nums; color: var(--ink); }
|
|
1508
|
+
.wire-leg-lab { font-family: var(--mono); font-size: 0.8rem; color: var(--ink-2); white-space: nowrap; }
|
|
1509
|
+
.wire-leg-meaning { font-size: 0.85rem; line-height: 1.45; }
|
|
1510
|
+
@media (max-width: 560px) {
|
|
1511
|
+
.wire-leg-row { grid-template-columns: 10px auto minmax(0, 1fr); }
|
|
1512
|
+
.wire-leg-meaning { grid-column: 2 / -1; }
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1515
|
+
/* ── MetaHarness, explained where the decision is made ────────────────────────────────────────────
|
|
1516
|
+
The card asks you to switch on a word you have never seen. Seven lines of prose is not how anyone
|
|
1517
|
+
learns a new word, so the diagram carries it and gets room rather than being squeezed beside text. */
|
|
1518
|
+
.mh-diagram {
|
|
1519
|
+
margin: 12px 0 14px; padding: 12px; border: 1px solid var(--line);
|
|
1520
|
+
border-radius: 12px; background: var(--fill); overflow-x: auto;
|
|
1521
|
+
}
|
|
1522
|
+
.mh-diagram img { display: block; width: 100%; height: auto; max-width: 900px; margin-inline: auto; }
|
|
1523
|
+
|
|
1524
|
+
/* ============================== APPENDED · THE TIPS DOOR (2026-07-17) ==============================
|
|
1525
|
+
Root-cause fix for an invisible destination. The header's tips link had borrowed .host-chip —
|
|
1526
|
+
the machine-readout's class — so a navigation DESTINATION was dressed as chrome, and the mobile
|
|
1527
|
+
rule that rightly hides the readout took the only door to tips.html with it. Two changes:
|
|
1528
|
+
(1) the header link owns its identity now (.tips-link, a link that looks like one);
|
|
1529
|
+
(2) the hero's right column leads with a real CTA card (.tips-cta) in the dead space above the
|
|
1530
|
+
art — the primary door at every width. Glyph = the tips page's own metaphor, inside out:
|
|
1531
|
+
solid cyan always-on · dashed amber say-it · dotted green name-it. */
|
|
1532
|
+
|
|
1533
|
+
/* the small header door — secondary now, but a link at last, not a readout */
|
|
1534
|
+
.tips-link {
|
|
1535
|
+
font-size: 12.5px; font-weight: 500; letter-spacing: 0.03em;
|
|
1536
|
+
color: var(--cyan-text); white-space: nowrap;
|
|
1537
|
+
border: 1px solid color-mix(in srgb, var(--cyan) 34%, transparent);
|
|
1538
|
+
background: color-mix(in srgb, var(--cyan) 8%, transparent);
|
|
1539
|
+
border-radius: 100px; padding: 4px 11px;
|
|
1540
|
+
transition: color 0.18s var(--ease), border-color 0.18s var(--ease), background 0.18s var(--ease);
|
|
1541
|
+
}
|
|
1542
|
+
.tips-link:hover { color: var(--amber-text); border-color: var(--amber); background: var(--fill); }
|
|
1543
|
+
|
|
1544
|
+
/* hero right column: door on top, art below — together they fill the height the copy sets */
|
|
1545
|
+
.intro-side { display: grid; gap: clamp(14px, 2vw, 18px); align-content: center; min-width: 0; }
|
|
1546
|
+
|
|
1547
|
+
/* The machine meta-row is a grid sibling of the copy: same seat on desktop (left column,
|
|
1548
|
+
under the motto), but on phones it yields its ~3 rows to the door and trails the art —
|
|
1549
|
+
chrome should never stand between the reader and the only CTA on the page. */
|
|
1550
|
+
@media (min-width: 62em) {
|
|
1551
|
+
.intro-grid { grid-template-rows: auto auto; row-gap: 1.2rem; }
|
|
1552
|
+
.intro-copy { grid-row: 1; grid-column: 1; }
|
|
1553
|
+
.intro-grid > .meta-row { grid-row: 2; grid-column: 1; align-self: start; margin-top: 0; }
|
|
1554
|
+
.intro-side { grid-row: 1 / span 2; grid-column: 2; }
|
|
1555
|
+
}
|
|
1556
|
+
@media (max-width: 61.99em) {
|
|
1557
|
+
.intro-grid > .meta-row { order: 3; margin-top: 0; }
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1560
|
+
/* the big door — a real surface with the house spectrum worn as its top edge */
|
|
1561
|
+
.tips-cta {
|
|
1562
|
+
position: relative; display: flex; align-items: center; gap: clamp(14px, 2vw, 18px);
|
|
1563
|
+
padding: clamp(15px, 2.2vw, 19px) clamp(15px, 2.4vw, 21px);
|
|
1564
|
+
border: 1px solid color-mix(in srgb, var(--amber) 36%, transparent);
|
|
1565
|
+
border-radius: var(--radius);
|
|
1566
|
+
background: linear-gradient(120deg,
|
|
1567
|
+
color-mix(in srgb, var(--amber) 9%, var(--surface)),
|
|
1568
|
+
color-mix(in srgb, var(--cyan) 6%, var(--surface)));
|
|
1569
|
+
box-shadow: var(--shadow);
|
|
1570
|
+
transition: border-color 0.2s var(--ease), box-shadow 0.22s var(--ease), transform 0.18s var(--ease);
|
|
1571
|
+
}
|
|
1572
|
+
.tips-cta::before {
|
|
1573
|
+
content: ""; position: absolute; left: 0; right: 0; top: 0; height: 3px;
|
|
1574
|
+
background: var(--spectrum); border-radius: var(--radius) var(--radius) 0 0;
|
|
1575
|
+
}
|
|
1576
|
+
.tips-cta:hover { border-color: var(--amber); box-shadow: var(--shadow-deep); transform: translateY(-2px); }
|
|
1577
|
+
.tips-cta:focus-visible { outline: 2px solid var(--cyan); outline-offset: 3px; }
|
|
1578
|
+
.tips-cta:hover .tc-arrow { transform: translateX(4px); }
|
|
1579
|
+
|
|
1580
|
+
.tc-glyph {
|
|
1581
|
+
flex: none; width: 62px; height: 62px; border-radius: 14px;
|
|
1582
|
+
display: grid; place-items: center;
|
|
1583
|
+
background: color-mix(in srgb, var(--amber) 10%, transparent);
|
|
1584
|
+
border: 1px solid color-mix(in srgb, var(--amber) 26%, transparent);
|
|
1585
|
+
}
|
|
1586
|
+
.tc-glyph svg { width: 46px; height: 46px; display: block; }
|
|
1587
|
+
.tc-glyph line { fill: none; stroke-linecap: round; }
|
|
1588
|
+
.tc-r1 { stroke: var(--cyan); stroke-width: 2.6; }
|
|
1589
|
+
.tc-r2 { stroke: var(--amber); stroke-width: 2.2; stroke-dasharray: 4 4.6; }
|
|
1590
|
+
.tc-r3 { stroke: var(--green); stroke-width: 2.2; stroke-dasharray: 1.6 6.4; opacity: 0.9; }
|
|
1591
|
+
.tc-caret { fill: var(--amber); }
|
|
1592
|
+
|
|
1593
|
+
.tc-text { min-width: 0; display: grid; gap: 3px; }
|
|
1594
|
+
.tc-kicker {
|
|
1595
|
+
font-size: 10.5px; font-weight: 600; letter-spacing: 0.2em; text-transform: uppercase;
|
|
1596
|
+
color: var(--amber-text);
|
|
1597
|
+
}
|
|
1598
|
+
.tc-title {
|
|
1599
|
+
font-family: var(--display); font-weight: 650; font-size: var(--fs-2);
|
|
1600
|
+
line-height: 1.18; color: var(--ink); text-wrap: balance;
|
|
1601
|
+
}
|
|
1602
|
+
.tc-arrow { display: inline-block; color: var(--amber-text); transition: transform 0.18s var(--ease); }
|
|
1603
|
+
.tc-sub { font-size: var(--fs--1); color: var(--ink-2); line-height: 1.5; max-width: 46ch; }
|
|
1604
|
+
|
|
1605
|
+
/* the three depths, named right on the door (same order + colors as tips.html's rings) */
|
|
1606
|
+
.tc-depths {
|
|
1607
|
+
display: flex; flex-wrap: wrap; gap: 4px 14px; margin-top: 4px;
|
|
1608
|
+
font-size: 11px; letter-spacing: 0.07em; text-transform: uppercase; color: var(--ink-2);
|
|
1609
|
+
}
|
|
1610
|
+
.td { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
|
|
1611
|
+
.td-dot { flex: none; width: 7px; height: 7px; border-radius: 50%; }
|
|
1612
|
+
.dd-1 { background: var(--cyan); }
|
|
1613
|
+
.dd-2 { background: var(--amber); }
|
|
1614
|
+
.dd-3 { background: var(--green); }
|
|
1615
|
+
|
|
1616
|
+
/* the header door never disappears: on phones its label compresses ("tips →") instead of
|
|
1617
|
+
vanishing — the sticky header keeps a door above the fold at every width and every scroll,
|
|
1618
|
+
which is the true cure for the bug that hid tips.html on phones. */
|
|
1619
|
+
.tl-short { display: none; }
|
|
1620
|
+
@media (max-width: 40em) {
|
|
1621
|
+
.tl-long { display: none; }
|
|
1622
|
+
.tl-short { display: inline; }
|
|
1623
|
+
.tc-glyph { width: 54px; height: 54px; }
|
|
1624
|
+
.tc-glyph svg { width: 40px; height: 40px; }
|
|
1625
|
+
}
|
|
1626
|
+
|
|
1627
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1628
|
+
.tips-cta:hover, .tips-cta:hover .tc-arrow { transform: none; }
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1631
|
+
/* ============================== APPENDED · WHAT'S ON, WHAT'S OFF (2026-07-22) ==============================
|
|
1632
|
+
Owner: "a ton of people don't know what is or isn't turned on because it's very much a black box."
|
|
1633
|
+
|
|
1634
|
+
THE ONE RULE THIS BLOCK EXISTS TO ENFORCE: "not checked" must never be mistakable for "off".
|
|
1635
|
+
Colour alone cannot carry that — amber and grey collapse into each other in greyscale, in bright
|
|
1636
|
+
sun, and for a red/green-deficient reader, and the moment they collapse the console is lying about
|
|
1637
|
+
what it knows. So the third state is separated in a second, non-colour channel: its rail is DASHED
|
|
1638
|
+
where the other two are solid, and its chip is the page's existing dashed `.tone-nt`. Squint, print
|
|
1639
|
+
it, or drop the saturation to zero and the three are still three. */
|
|
1640
|
+
|
|
1641
|
+
.cap-list {
|
|
1642
|
+
margin-top: 14px; border: 1px solid var(--hair); border-radius: 12px; overflow: hidden;
|
|
1643
|
+
background: color-mix(in srgb, var(--ink) 2%, transparent);
|
|
1644
|
+
}
|
|
1645
|
+
/* Same three-column grammar as .trust-row (name · plain words · status) — deliberately its own
|
|
1646
|
+
class, because the trust card is free to change shape without silently reshaping this one.
|
|
1647
|
+
That exact borrowing is what once hid the tips door on phones. */
|
|
1648
|
+
.cap-row {
|
|
1649
|
+
display: grid; grid-template-columns: minmax(150px, 0.9fr) minmax(0, 2.1fr) auto;
|
|
1650
|
+
gap: 6px 16px; padding: 14px 16px; align-items: start;
|
|
1651
|
+
border-left: 3px solid transparent;
|
|
1652
|
+
}
|
|
1653
|
+
.cap-row + .cap-row { border-top: 1px solid var(--hair); }
|
|
1654
|
+
.cap-row.is-on { border-left-color: var(--green); }
|
|
1655
|
+
.cap-row.is-off { border-left-color: var(--amber); background: color-mix(in srgb, var(--amber) 4%, transparent); }
|
|
1656
|
+
.cap-row.is-unknown { border-left-color: var(--hair-strong); border-left-style: dashed; }
|
|
1657
|
+
/* SOLID, like on/off — because `absent` is a MEASURED answer ("we looked, it isn't here"), not an
|
|
1658
|
+
unanswered question. The dashed edge is reserved for unknown and has to keep meaning only that;
|
|
1659
|
+
giving absent the same treatment would restate visually the exact conflation the state was added
|
|
1660
|
+
to end. Grey rather than amber: nothing is wrong, there is simply nothing installed. */
|
|
1661
|
+
.cap-row.is-absent { border-left-color: var(--hair-strong); }
|
|
1662
|
+
|
|
1663
|
+
.cap-name { font-weight: 650; color: var(--ink); font-size: var(--fs--1); display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
|
|
1664
|
+
.cap-scope {
|
|
1665
|
+
font-family: var(--mono); font-size: 10px; font-weight: 600; letter-spacing: 0.1em;
|
|
1666
|
+
text-transform: uppercase; color: var(--muted);
|
|
1667
|
+
border: 1px solid var(--hair); border-radius: 100px; padding: 1px 7px;
|
|
1668
|
+
}
|
|
1669
|
+
.cap-val { min-width: 0; font-size: var(--fs--1); color: var(--ink-2); line-height: 1.55; }
|
|
1670
|
+
.cap-buys { max-width: 62ch; margin: 0; font-size: inherit; }
|
|
1671
|
+
|
|
1672
|
+
/* Evidence sits UNDER the claim and looks subordinate to it — it is the receipt, not the headline. */
|
|
1673
|
+
.cap-ev { list-style: none; margin: 7px 0 0; padding: 0; display: grid; gap: 4px; }
|
|
1674
|
+
.cap-ev li {
|
|
1675
|
+
position: relative; padding-left: 15px;
|
|
1676
|
+
font-size: 12.5px; line-height: 1.5; color: var(--muted); overflow-wrap: anywhere;
|
|
1677
|
+
}
|
|
1678
|
+
.cap-ev li::before { content: "·"; position: absolute; left: 4px; color: var(--faint); }
|
|
1679
|
+
.cap-ev-none { margin: 7px 0 0; font-size: 12.5px; }
|
|
1680
|
+
.cap-status { justify-self: end; }
|
|
1681
|
+
|
|
1682
|
+
/* The "should it be on" line. Deliberately styled as READING MATTER, not as a control: no button
|
|
1683
|
+
affordance, no hover state, nothing that invites a click there is no executor behind. The command
|
|
1684
|
+
is selectable so it can be copied, which is the entire interaction this line supports. */
|
|
1685
|
+
.cap-turnon {
|
|
1686
|
+
margin: 9px 0 0; max-width: 62ch; font-size: 12.5px; line-height: 1.55; color: var(--ink-2);
|
|
1687
|
+
padding-top: 8px; border-top: 1px dotted var(--hair);
|
|
1688
|
+
}
|
|
1689
|
+
.cap-turnon-lb {
|
|
1690
|
+
display: block; font-family: var(--mono); font-size: 10px; font-weight: 600;
|
|
1691
|
+
letter-spacing: 0.14em; text-transform: uppercase; color: var(--faint); margin-bottom: 3px;
|
|
1692
|
+
}
|
|
1693
|
+
/* The command gets its OWN line rather than flowing inline after the prose. Inline, it wrapped
|
|
1694
|
+
mid-path — "node / scripts/lesson-promote.mjs --apply" split across two lines with the code
|
|
1695
|
+
background broken in half, which reads as two fragments rather than one thing you can copy.
|
|
1696
|
+
A command is a unit; display:block keeps it looking like one. */
|
|
1697
|
+
.cap-turnon code {
|
|
1698
|
+
display: block; width: fit-content; max-width: 100%; margin-top: 5px;
|
|
1699
|
+
font-size: 12px; overflow-wrap: anywhere; user-select: all;
|
|
1700
|
+
}
|
|
1701
|
+
.cap-turnon-none { color: var(--muted); }
|
|
1702
|
+
|
|
1703
|
+
/* ── capability-row checkbox — the ONE clickable control on this card, and only on rows that cleared
|
|
1704
|
+
every gate in capCheckboxEligible() (state=OFF, a zero-blank verified command, a schema-gated rec,
|
|
1705
|
+
scope != machine). Everything else on this card stays "reading matter, not a control" — see the
|
|
1706
|
+
note on .cap-turnon just above these rules. ──────────────────────────────────────────────────── */
|
|
1707
|
+
.cap-toggle-wrap {
|
|
1708
|
+
margin: 9px 0 0; padding-top: 8px; border-top: 1px dotted var(--hair);
|
|
1709
|
+
}
|
|
1710
|
+
.cap-toggle-label {
|
|
1711
|
+
display: inline-flex; align-items: center; gap: 9px; cursor: pointer;
|
|
1712
|
+
font-size: 12.5px; color: var(--ink); font-weight: 600;
|
|
1713
|
+
}
|
|
1714
|
+
.cap-toggle {
|
|
1715
|
+
/* Deliberately NOT the browser default box — a checkbox that looks identical to a form checkbox
|
|
1716
|
+
invites the assumption that unchecked==off in the generic sense; this one only ever means "not
|
|
1717
|
+
yet applied," and giving it its own skin keeps that from being confused with a settings toggle
|
|
1718
|
+
elsewhere on the page. */
|
|
1719
|
+
appearance: none; width: 18px; height: 18px; flex: none; margin: 0;
|
|
1720
|
+
border: 1.5px solid var(--amber); border-radius: 5px;
|
|
1721
|
+
background: color-mix(in srgb, var(--amber) 8%, transparent);
|
|
1722
|
+
display: grid; place-items: center; transition: border-color 0.15s var(--ease);
|
|
1723
|
+
}
|
|
1724
|
+
.cap-toggle:hover { border-color: color-mix(in srgb, var(--amber) 70%, var(--ink)); }
|
|
1725
|
+
.cap-toggle:focus-visible { outline: 2px solid var(--amber); outline-offset: 2px; }
|
|
1726
|
+
/* Checked state is reachable ONLY by recheckMachine() re-rendering the row as state=on — see
|
|
1727
|
+
capRow(), which stops emitting capCheckbox() at all once known !== 'OFF'. There is therefore no
|
|
1728
|
+
client code path that sets this attribute directly; it is drawn here so the browser has somewhere
|
|
1729
|
+
to paint it if a future refactor ever does bind it declaratively. */
|
|
1730
|
+
.cap-toggle:checked { background: var(--green); border-color: var(--green); }
|
|
1731
|
+
.cap-toggle:checked::after {
|
|
1732
|
+
content: ''; width: 9px; height: 5px; border-left: 2px solid var(--on-accent);
|
|
1733
|
+
border-bottom: 2px solid var(--on-accent); transform: rotate(-45deg) translateY(-1px);
|
|
1734
|
+
}
|
|
1735
|
+
.cap-toggle-text { line-height: 1.4; }
|
|
1736
|
+
.cap-toggle-note {
|
|
1737
|
+
margin: 4px 0 0 27px; max-width: 56ch; font-size: 11.5px; line-height: 1.5; color: var(--muted);
|
|
1738
|
+
}
|
|
1739
|
+
.cap-toggle-pending .cap-toggle-text { color: var(--muted); font-weight: 500; }
|
|
1740
|
+
|
|
1741
|
+
/* ── honest, explicitly-not-a-checkbox marks for idle / unknown rows ───────────────────────────── */
|
|
1742
|
+
.cap-honest-mark {
|
|
1743
|
+
margin: 9px 0 0; padding-top: 8px; border-top: 1px dotted var(--hair);
|
|
1744
|
+
font-size: 12.5px; line-height: 1.55; color: var(--muted); display: flex; gap: 8px; align-items: flex-start;
|
|
1745
|
+
max-width: 62ch;
|
|
1746
|
+
}
|
|
1747
|
+
.cap-honest-mark .mark-glyph {
|
|
1748
|
+
flex: none; font-family: var(--mono); font-size: 13px; line-height: 1.4;
|
|
1749
|
+
width: 16px; text-align: center; color: var(--faint);
|
|
1750
|
+
}
|
|
1751
|
+
.cap-honest-mark.is-idle .mark-glyph { color: var(--amber-text); }
|
|
1752
|
+
.cap-honest-mark.is-unknown .mark-glyph { color: var(--faint); }
|
|
1753
|
+
|
|
1754
|
+
/* The key, stated before the rows so nobody has to reverse-engineer the colours from the data. */
|
|
1755
|
+
/* max-width:none is load-bearing, not tidying: the global `p { max-width: 70ch }` measures a prose
|
|
1756
|
+
column, and this <p> is a horizontal key, so 70ch broke every entry onto its own line with half
|
|
1757
|
+
the card empty beside it. Same override .lead-stat and .trust-val p already carry. */
|
|
1758
|
+
.cap-legend {
|
|
1759
|
+
display: flex; flex-wrap: wrap; align-items: center; gap: 6px 18px;
|
|
1760
|
+
margin: 12px 0 0; max-width: none;
|
|
1761
|
+
font-size: 11.5px; letter-spacing: 0.06em; color: var(--ink-2);
|
|
1762
|
+
}
|
|
1763
|
+
.cap-legend .cl-cap { color: var(--faint); letter-spacing: 0.2em; text-transform: uppercase; }
|
|
1764
|
+
.cap-legend .cl { display: inline-flex; align-items: center; gap: 7px; }
|
|
1765
|
+
.cap-legend .cl-key { width: 14px; height: 0; flex: none; border-top: 3px solid var(--hair-strong); border-radius: 3px; }
|
|
1766
|
+
/* The L0-L5 ladder. Reads top-to-bottom as a climb: what is built is solid, what is not is dimmed
|
|
1767
|
+
and dashed, and the current rung is the only one that carries weight. The visual hierarchy IS the
|
|
1768
|
+
honesty here — a uniform list would let the unbuilt levels read as shipped features. */
|
|
1769
|
+
.ladder { list-style: none; margin: 14px 0 0; padding: 0; display: grid; gap: 2px; max-width: 72ch; }
|
|
1770
|
+
.ladder .lv {
|
|
1771
|
+
display: grid; grid-template-columns: minmax(9.5em, max-content) 1fr; gap: 4px 14px;
|
|
1772
|
+
padding: 10px 14px; border-left: 3px solid var(--hair); align-items: baseline;
|
|
1773
|
+
font-size: var(--fs--1); line-height: 1.55;
|
|
1774
|
+
}
|
|
1775
|
+
.ladder .lv b { color: var(--ink); font-weight: 650; }
|
|
1776
|
+
.ladder .lv span { color: var(--ink-2); min-width: 0; }
|
|
1777
|
+
.ladder .lv.done { border-left-color: var(--green); }
|
|
1778
|
+
.ladder .lv.here {
|
|
1779
|
+
border-left-color: var(--green); border-left-width: 4px;
|
|
1780
|
+
background: color-mix(in srgb, var(--green) 6%, transparent);
|
|
1781
|
+
}
|
|
1782
|
+
.ladder .lv.here span b { color: var(--ink); }
|
|
1783
|
+
/* Dashed + dimmed, matching the "unknown" grammar elsewhere on the page: not yet real. */
|
|
1784
|
+
.ladder .lv.todo { border-left-style: dashed; border-left-color: var(--hair-strong); }
|
|
1785
|
+
.ladder .lv.todo b, .ladder .lv.todo span { color: var(--muted); }
|
|
1786
|
+
@media (max-width: 40em) {
|
|
1787
|
+
.ladder .lv { grid-template-columns: 1fr; gap: 3px; }
|
|
1788
|
+
}
|
|
1789
|
+
|
|
1790
|
+
.cap-legend .k-on { border-top-color: var(--green); }
|
|
1791
|
+
.cap-legend .k-off { border-top-color: var(--amber); }
|
|
1792
|
+
/* IDLE — amber like off (both are "not doing anything"), dotted to separate the two at a glance:
|
|
1793
|
+
off is dormant on purpose, idle is the one you THINK is working. See capLegend() in app.js. */
|
|
1794
|
+
.cap-legend .k-idle { border-top-color: var(--amber); border-top-style: dotted; }
|
|
1795
|
+
.cap-legend .k-absent { border-top-color: var(--hair-strong); }
|
|
1796
|
+
.cap-legend .k-unknown { border-top-style: dashed; }
|
|
1797
|
+
/* Legend addendum for the checkbox affordance — see capLegend() in app.js. */
|
|
1798
|
+
.cl-checkbox-note { flex-basis: 100%; color: var(--faint); font-style: italic; }
|
|
1799
|
+
|
|
1800
|
+
@media (max-width: 40em) {
|
|
1801
|
+
/* Status rides up beside the name; the plain-words column takes the full width beneath both —
|
|
1802
|
+
same reflow the trust rows use, so the two cards still read as one family on a phone. */
|
|
1803
|
+
.cap-row { grid-template-columns: minmax(0, 1fr) auto; }
|
|
1804
|
+
.cap-val { grid-column: 1 / -1; order: 3; }
|
|
1805
|
+
}
|
|
1806
|
+
|
|
1807
|
+
/* Forced-colours mode strips every custom colour, which would flatten all three states into one
|
|
1808
|
+
identical row — the exact confusion this card exists to end. Re-separate them with border STYLE,
|
|
1809
|
+
the one channel the high-contrast renderer preserves. */
|
|
1810
|
+
@media (forced-colors: active) {
|
|
1811
|
+
.cap-row { border-left: 3px solid CanvasText; }
|
|
1812
|
+
.cap-row.is-unknown { border-left-style: dotted; }
|
|
1813
|
+
.cap-row.is-off { border-left-style: double; border-left-width: 4px; }
|
|
1814
|
+
}
|
|
1815
|
+
|
|
1816
|
+
/* ── Lessons card ("what it's learned from you") ────────────────────────────────────────────────
|
|
1817
|
+
Reuses .cap-row / .cap-list / .chips wholesale — a lesson row and a capability row are the same
|
|
1818
|
+
object to a reader (a thing with a state and a switch), so they must look the same. Only the
|
|
1819
|
+
pieces with no capability equivalent are defined here. */
|
|
1820
|
+
.cap-row-head { display: flex; gap: .6rem; align-items: flex-start; cursor: pointer; }
|
|
1821
|
+
.cap-row-title { font-weight: 600; line-height: 1.35; }
|
|
1822
|
+
.lesson-switch {
|
|
1823
|
+
flex: 0 0 auto; width: 1.05rem; height: 1.05rem; margin-top: .18rem;
|
|
1824
|
+
accent-color: var(--green); cursor: pointer;
|
|
1825
|
+
}
|
|
1826
|
+
.lesson-switch:disabled { opacity: .5; cursor: progress; }
|
|
1827
|
+
.cap-row-when { font-size: .84rem; margin: .3rem 0 0; }
|
|
1828
|
+
.cap-why { margin-top: .5rem; }
|
|
1829
|
+
.cap-why > summary {
|
|
1830
|
+
cursor: pointer; font-size: .84rem; color: var(--muted);
|
|
1831
|
+
border-bottom: 1px dotted var(--hair-strong); display: inline-block;
|
|
1832
|
+
}
|
|
1833
|
+
.cap-why > summary:hover { color: var(--ink); }
|
|
1834
|
+
.cap-why-body { padding: .55rem 0 .2rem; font-size: .88rem; line-height: 1.5; }
|
|
1835
|
+
.cap-why-body p { margin: 0 0 .5rem; }
|
|
1836
|
+
.cap-row.is-off .cap-row-title { opacity: .58; text-decoration: line-through; text-decoration-thickness: 1px; }
|
|
1837
|
+
|
|
1838
|
+
/* A lesson row STACKS; it is not a table row. .cap-row is a 3-column grid built for
|
|
1839
|
+
name│buys│status, and reusing it verbatim dealt five stacked children into three cells — the
|
|
1840
|
+
statement was crushed into a 150px column with its trigger stranded two columns away. Keep the
|
|
1841
|
+
rail, padding and on/off states; drop the grid. */
|
|
1842
|
+
.cap-row.lesson-row { display: block; }
|
|
1843
|
+
.cap-row.lesson-row .chips { margin-top: .45rem; }
|
|
1844
|
+
.cap-row.lesson-row.is-off { background: color-mix(in srgb, var(--amber) 4%, transparent); }
|
|
1845
|
+
|
|
1846
|
+
/* THE CONTRACT — the reassurance line under the hero. Styled as a quiet, bordered aside rather
|
|
1847
|
+
than an alert: it is a promise being kept, not a warning being issued. Amber rail ties it to the
|
|
1848
|
+
Apply/Undo family, which is what it is actually about. */
|
|
1849
|
+
.contract {
|
|
1850
|
+
margin: 1rem 0 0; padding: .75rem .95rem;
|
|
1851
|
+
border-left: 3px solid color-mix(in srgb, var(--amber) 55%, transparent);
|
|
1852
|
+
background: color-mix(in srgb, var(--amber) 5%, transparent);
|
|
1853
|
+
border-radius: 0 var(--radius-s) var(--radius-s) 0;
|
|
1854
|
+
font-size: .92rem; line-height: 1.55; color: var(--ink);
|
|
1855
|
+
max-width: 62ch;
|
|
1856
|
+
}
|
|
1857
|
+
.contract strong { color: var(--amber-text); }
|
|
1858
|
+
|
|
1859
|
+
/* Capability groups by scope (this project / you / this machine). */
|
|
1860
|
+
.cap-group + .cap-group { margin-top: 1.4rem; }
|
|
1861
|
+
.cap-group-h {
|
|
1862
|
+
display: flex; align-items: baseline; gap: .5rem; margin: 0 0 .15rem;
|
|
1863
|
+
font-size: .98rem; font-weight: 650; letter-spacing: .01em;
|
|
1864
|
+
}
|
|
1865
|
+
.cap-group-n {
|
|
1866
|
+
font-size: .74rem; color: var(--muted); border: 1px solid var(--hair);
|
|
1867
|
+
border-radius: 999px; padding: .05rem .4rem;
|
|
1868
|
+
}
|
|
1869
|
+
.cap-group-blurb { font-size: .84rem; margin: 0 0 .5rem; max-width: 68ch; }
|
|
1870
|
+
|
|
1871
|
+
/* Lessons: the question first, the reference list folded. See partitionLessons() for why. */
|
|
1872
|
+
.lessons-ask-h { font-weight: 650; margin: .6rem 0 .15rem; }
|
|
1873
|
+
.lessons-ask-b { font-size: .86rem; margin: 0 0 .55rem; max-width: 68ch; }
|
|
1874
|
+
.lessons-more { margin-top: 1.1rem; }
|
|
1875
|
+
.lessons-more > summary {
|
|
1876
|
+
cursor: pointer; font-size: .9rem; font-weight: 600; color: var(--ink);
|
|
1877
|
+
padding: .5rem .7rem; border: 1px solid var(--hair); border-radius: var(--radius-s);
|
|
1878
|
+
background: var(--fill);
|
|
1879
|
+
}
|
|
1880
|
+
.lessons-more > summary:hover { border-color: var(--hair-strong); }
|
|
1881
|
+
.lessons-more[open] > summary { margin-bottom: .6rem; }
|
|
1882
|
+
|
|
1883
|
+
/* ── THE TIPS DOOR MUST LOOK LIKE A DOOR ────────────────────────────────────────────────────────
|
|
1884
|
+
Owner, 2026-07-24: "it just looks like a window, not a button that they should be clicking on."
|
|
1885
|
+
Correct, and measurable: every visual affordance on .tips-cta lived in :hover — the border lift,
|
|
1886
|
+
the shadow, the arrow nudge. At rest it was a static panel, so a reader who never happened to
|
|
1887
|
+
sweep the pointer across it learned nothing. And what is behind it is the single most valuable
|
|
1888
|
+
page we have: "Ten things you already own", the latent capability list.
|
|
1889
|
+
|
|
1890
|
+
THREE CUES, ALL AT REST, none of them a jiggling toy:
|
|
1891
|
+
1. the arrow breathes to the right — direction, not decoration
|
|
1892
|
+
2. a slow sheen crosses the card every ~7s — the "this is live" tell
|
|
1893
|
+
3. the kicker's dot pulses — a small heartbeat where the eye already lands
|
|
1894
|
+
|
|
1895
|
+
Deliberately SLOW and low-amplitude. A CTA that flashes reads as an ad, and this audience closes
|
|
1896
|
+
ads. It should feel like something breathing, not something selling.
|
|
1897
|
+
|
|
1898
|
+
MOTION IS A PREFERENCE, NOT A DECISION WE GET TO MAKE. Everything below is off under
|
|
1899
|
+
prefers-reduced-motion, where the resting state instead gets the border+shadow treatment
|
|
1900
|
+
permanently — the affordance still lands, it just does not move. */
|
|
1901
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
1902
|
+
.tips-cta .tc-arrow { animation: tips-arrow 2.4s var(--ease) infinite; }
|
|
1903
|
+
.tips-cta::after {
|
|
1904
|
+
content: ""; position: absolute; inset: 0; border-radius: var(--radius);
|
|
1905
|
+
background: linear-gradient(105deg, transparent 38%,
|
|
1906
|
+
color-mix(in srgb, var(--amber) 20%, transparent) 50%, transparent 62%);
|
|
1907
|
+
background-size: 260% 100%; pointer-events: none;
|
|
1908
|
+
animation: tips-sheen 7s var(--ease) infinite;
|
|
1909
|
+
}
|
|
1910
|
+
.tips-cta:hover::after { animation-play-state: paused; } /* pointer is here; stop courting them */
|
|
1911
|
+
.tips-cta .tc-kicker::before {
|
|
1912
|
+
content: ""; display: inline-block; width: .42em; height: .42em; margin-right: .5em;
|
|
1913
|
+
border-radius: 50%; background: var(--amber); vertical-align: middle;
|
|
1914
|
+
animation: tips-pulse 2.4s var(--ease) infinite;
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1917
|
+
@keyframes tips-arrow { 0%, 100% { transform: translateX(0); } 55% { transform: translateX(5px); } }
|
|
1918
|
+
@keyframes tips-sheen { 0% { background-position: 130% 0; } 55%, 100% { background-position: -130% 0; } }
|
|
1919
|
+
@keyframes tips-pulse { 0%, 100% { opacity: .35; transform: scale(.85); } 55% { opacity: 1; transform: scale(1); } }
|
|
1920
|
+
|
|
1921
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1922
|
+
.tips-cta { border-color: var(--amber); box-shadow: var(--shadow-deep); }
|
|
1923
|
+
.tips-cta .tc-arrow { transform: translateX(4px); }
|
|
1924
|
+
}
|
|
1925
|
+
.catch-n { color: var(--amber-text); font-variant-numeric: tabular-nums; }
|
|
1926
|
+
|
|
1927
|
+
/* THE VERDICT LINE — the answer, above the receipts. Larger than the ribbon beneath it because it
|
|
1928
|
+
is the thing a person came for; quiet in colour because a verdict that shouts reads as marketing. */
|
|
1929
|
+
.verdict {
|
|
1930
|
+
display: flex; gap: .6rem; align-items: baseline;
|
|
1931
|
+
margin: 0 0 .5rem; font-size: 1.02rem; line-height: 1.5; max-width: 78ch;
|
|
1932
|
+
}
|
|
1933
|
+
.verdict-mark {
|
|
1934
|
+
flex: 0 0 auto; width: 1.35rem; height: 1.35rem; border-radius: 50%;
|
|
1935
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
1936
|
+
font-size: .82rem; font-weight: 700; transform: translateY(.12rem);
|
|
1937
|
+
}
|
|
1938
|
+
.vm-good { color: var(--green-text); background: color-mix(in srgb, var(--green) 15%, transparent); }
|
|
1939
|
+
.vm-look { color: var(--amber-text); background: color-mix(in srgb, var(--amber) 18%, transparent); }
|
|
1940
|
+
|
|
1941
|
+
/* ============================== 21 · QUESTION GROUPS — 12→4 merge (design-grade -5, 2026-07-24) =====
|
|
1942
|
+
Twelve peer <details class="card"> read as a wall of identical collapsed drawers. Fix: four
|
|
1943
|
+
top-level sections, one per question a person actually asks (index.html carries the full
|
|
1944
|
+
rationale comment). A `.qgroup` is a plain <section>, always visible — it reuses `.card`'s own
|
|
1945
|
+
box (background/border/radius/shadow/rail-stripe/entrance-animation all come free from the
|
|
1946
|
+
existing `.card` + `.rail-*` rules below, since those select on CLASS, not on the <details> tag)
|
|
1947
|
+
but its header is a bare div, not a <summary>: no chevron, no hover state, no click cursor. A
|
|
1948
|
+
container that cannot toggle must never borrow the affordance that says it can.
|
|
1949
|
+
Nested cards get `.sub-card` — quieter (no shadow, no deep-shadow-on-open) so they read as the
|
|
1950
|
+
CONTENTS of the open section rather than five more drawers in the row. */
|
|
1951
|
+
.qgroup-head {
|
|
1952
|
+
display: flex; align-items: center; gap: 16px;
|
|
1953
|
+
padding: clamp(16px, 2.6vw, 22px) clamp(16px, 3vw, 26px);
|
|
1954
|
+
}
|
|
1955
|
+
.qgroup-body {
|
|
1956
|
+
padding: 6px clamp(16px, 3vw, 26px) clamp(20px, 3vw, 26px);
|
|
1957
|
+
border-top: 1px solid var(--hair);
|
|
1958
|
+
display: grid; gap: 12px;
|
|
1959
|
+
}
|
|
1960
|
+
.qgroup-body > .card { margin: 0; }
|
|
1961
|
+
.qgroup-body > .card:first-child { margin-top: 10px; }
|
|
1962
|
+
|
|
1963
|
+
.card.sub-card { box-shadow: none; border-color: var(--hair-strong); }
|
|
1964
|
+
.card.sub-card[open] { box-shadow: none; border-color: var(--line); }
|
|
1965
|
+
/* A sub-card's own h2 no longer needs to compete with the group's h2 above it. */
|
|
1966
|
+
.card.sub-card .card-head h2 { font-size: var(--fs-1); }
|
|
1967
|
+
|
|
1968
|
+
@media (max-width: 40em) {
|
|
1969
|
+
.qgroup-head { gap: 12px; }
|
|
1970
|
+
}
|
|
1971
|
+
|
|
1972
|
+
/* Explicit stagger for the 4 top-level peers. The generic `.card:nth-of-type(n)` rule above counts
|
|
1973
|
+
by TAG among siblings, and the top level now mixes three `.qgroup` <section>s with the standalone
|
|
1974
|
+
`#card-lessons` <details> — tag-based counting no longer lines up with reading order (a <details>
|
|
1975
|
+
would jump the queue over a later <section>). ID selectors sidestep the ambiguity outright and
|
|
1976
|
+
win on specificity regardless of source order. */
|
|
1977
|
+
#group-inventory { animation-delay: 0.06s; }
|
|
1978
|
+
#group-suggested { animation-delay: 0.12s; }
|
|
1979
|
+
#card-lessons { animation-delay: 0.18s; }
|
|
1980
|
+
#group-prove { animation-delay: 0.24s; }
|
|
1981
|
+
|
|
1982
|
+
/* ============================== 22 · ACTIVITY CARD — reduce visual weight (design-grade -1) ========
|
|
1983
|
+
"Activity card renders a dense monospace log table at user altitude." The feed itself is rendered
|
|
1984
|
+
by activity.js, which appends its OWN <style data-owner="card-activity"> to <head> at runtime —
|
|
1985
|
+
AFTER this file loads. Equal-specificity rules there would win by source order, so every selector
|
|
1986
|
+
below adds one extra ID ancestor (#main, which already wraps the whole page) purely to win the
|
|
1987
|
+
cascade regardless of load order; the values are the only thing that matters, activity.js itself
|
|
1988
|
+
is untouched. Three changes, per the brief: shrink the scrollable window so the log can never
|
|
1989
|
+
dominate its card, soften the typography so it reads as a quiet receipt instead of a terminal
|
|
1990
|
+
dump, and keep every row — nothing here removes information, only its visual weight. */
|
|
1991
|
+
#main #card-activity .ab-feed {
|
|
1992
|
+
max-height: 168px; /* was 252 in activity.js's own rule — a receipt window, not a dump */
|
|
1993
|
+
border-radius: 10px;
|
|
1994
|
+
background: color-mix(in srgb, var(--ink) 1.5%, transparent);
|
|
1995
|
+
padding: 2px 6px;
|
|
1996
|
+
}
|
|
1997
|
+
#main #card-activity .ab-feed.ab-expanded { max-height: 300px; }
|
|
1998
|
+
#main #card-activity .ab-row {
|
|
1999
|
+
padding: 5px 8px;
|
|
2000
|
+
border-radius: 7px;
|
|
2001
|
+
}
|
|
2002
|
+
#main #card-activity .ab-row .ab-ts {
|
|
2003
|
+
font-family: var(--sans);
|
|
2004
|
+
font-variant-numeric: tabular-nums;
|
|
2005
|
+
font-size: 12px;
|
|
2006
|
+
font-weight: 500;
|
|
2007
|
+
color: var(--faint);
|
|
2008
|
+
}
|
|
2009
|
+
#main #card-activity .ab-row .ab-txt { font-size: 13px; }
|
|
2010
|
+
#main #card-activity .ab-badge {
|
|
2011
|
+
font-family: var(--sans);
|
|
2012
|
+
font-weight: 500;
|
|
2013
|
+
font-size: 11px;
|
|
2014
|
+
letter-spacing: 0.02em;
|
|
2015
|
+
color: var(--faint);
|
|
2016
|
+
border-color: var(--hair);
|
|
2017
|
+
background: transparent;
|
|
2018
|
+
}
|
|
2019
|
+
|
|
2020
|
+
/* ============================== 23 · BRAIN POWER — the master switch, made unmissable ==============
|
|
2021
|
+
Owner, 2026-07-27, having opened the console looking for the on/off switch: "if it didn't show up
|
|
2022
|
+
in the console, how can it be implemented?" ADR-054's switch WAS rendered — as one checkbox in the
|
|
2023
|
+
Settings card, below the things it governs, behind a chevron. This is the styling for its own
|
|
2024
|
+
always-open card at the top of the page. The whole design brief is one sentence: a first-time
|
|
2025
|
+
viewer must find it, and read its state, without scrolling and without clicking anything.
|
|
2026
|
+
|
|
2027
|
+
The state is carried by THREE redundant channels — the word (ON / OFF), the color, and the
|
|
2028
|
+
position of the knob — because color alone fails for a colorblind reader and position alone is
|
|
2029
|
+
ambiguous on an unfamiliar control. */
|
|
2030
|
+
.brain-card { margin: 0 0 14px; }
|
|
2031
|
+
#card-brain { animation-delay: 0.03s; }
|
|
2032
|
+
.st-act { color: var(--amber-text); border-color: color-mix(in srgb, var(--amber) 32%, transparent); background: color-mix(in srgb, var(--amber) 8%, transparent); }
|
|
2033
|
+
|
|
2034
|
+
.bp-row {
|
|
2035
|
+
display: flex; align-items: center; gap: clamp(14px, 3vw, 26px);
|
|
2036
|
+
flex-wrap: wrap; margin: 18px 0 4px;
|
|
2037
|
+
}
|
|
2038
|
+
.bp-state { flex: 1 1 260px; min-width: 0; }
|
|
2039
|
+
.bp-word {
|
|
2040
|
+
font-size: clamp(24px, 4.4vw, 34px); font-weight: 700; line-height: 1.15; letter-spacing: -0.01em;
|
|
2041
|
+
display: flex; align-items: center; gap: 12px;
|
|
2042
|
+
}
|
|
2043
|
+
.bp-word .bp-dot { flex: none; width: 13px; height: 13px; border-radius: 50%; background: currentColor; }
|
|
2044
|
+
.bp-on .bp-word { color: var(--green-text); }
|
|
2045
|
+
.bp-off .bp-word { color: var(--amber-text); }
|
|
2046
|
+
.bp-sub { color: var(--muted); font-size: var(--fs-0); margin: 6px 0 0; max-width: 62ch; }
|
|
2047
|
+
|
|
2048
|
+
/* The switch itself: a real <button role="switch">, sized so it reads as a switch across the room.
|
|
2049
|
+
Keyboard and screen readers get it for free from the element + aria-checked. */
|
|
2050
|
+
.bp-switch {
|
|
2051
|
+
flex: none; display: inline-flex; align-items: center; gap: 14px;
|
|
2052
|
+
background: none; border: 0; padding: 6px; cursor: pointer; color: inherit;
|
|
2053
|
+
font: inherit; border-radius: 999px;
|
|
2054
|
+
}
|
|
2055
|
+
.bp-switch:focus-visible { outline: 2px solid var(--amber); outline-offset: 3px; }
|
|
2056
|
+
.bp-track {
|
|
2057
|
+
width: 88px; height: 46px; border-radius: 999px; position: relative;
|
|
2058
|
+
border: 1px solid var(--hair-strong); background: var(--fill);
|
|
2059
|
+
transition: background 0.22s var(--ease), border-color 0.22s var(--ease);
|
|
2060
|
+
}
|
|
2061
|
+
.bp-knob {
|
|
2062
|
+
position: absolute; top: 4px; left: 4px; width: 36px; height: 36px; border-radius: 50%;
|
|
2063
|
+
background: var(--ink); opacity: 0.86;
|
|
2064
|
+
transition: transform 0.22s var(--ease), background 0.22s var(--ease);
|
|
2065
|
+
}
|
|
2066
|
+
.bp-on .bp-track { background: color-mix(in srgb, var(--green) 22%, transparent); border-color: color-mix(in srgb, var(--green) 46%, transparent); }
|
|
2067
|
+
.bp-on .bp-knob { transform: translateX(42px); background: var(--green); opacity: 1; }
|
|
2068
|
+
.bp-off .bp-track { background: color-mix(in srgb, var(--amber) 14%, transparent); border-color: color-mix(in srgb, var(--amber) 40%, transparent); }
|
|
2069
|
+
.bp-off .bp-knob { background: var(--amber); opacity: 0.9; }
|
|
2070
|
+
.bp-switch-label { font-weight: 600; font-size: var(--fs-0); white-space: nowrap; }
|
|
2071
|
+
.bp-switch[disabled] { opacity: 0.6; cursor: progress; }
|
|
2072
|
+
@media (prefers-reduced-motion: reduce) { .bp-knob, .bp-track { transition: none; } }
|
|
2073
|
+
|
|
2074
|
+
/* Consent step for the destructive direction only (turning the brain OFF). Turning it back ON needs
|
|
2075
|
+
no warning — there is nothing to warn about. */
|
|
2076
|
+
.bp-confirm {
|
|
2077
|
+
margin: 14px 0 0; padding: 14px 16px; border: 1px solid var(--line);
|
|
2078
|
+
border-radius: 12px; background: var(--fill);
|
|
2079
|
+
}
|
|
2080
|
+
.bp-confirm p { margin: 0 0 10px; max-width: 74ch; }
|
|
2081
|
+
.bp-confirm .bp-actions { display: flex; gap: 10px; flex-wrap: wrap; }
|
|
2082
|
+
|
|
2083
|
+
.bp-notes { margin: 14px 0 0; padding: 0; list-style: none; display: grid; gap: 7px; }
|
|
2084
|
+
.bp-notes li { color: var(--muted); font-size: 13.5px; padding-left: 18px; position: relative; max-width: 84ch; }
|
|
2085
|
+
.bp-notes li::before { content: "·"; position: absolute; left: 6px; color: var(--faint); font-weight: 700; }
|
|
2086
|
+
.bp-warn { color: var(--amber-text); }
|
|
2087
|
+
|
|
2088
|
+
.bp-profile {
|
|
2089
|
+
margin: 20px 0 0; padding: 16px; border: 1px solid var(--hair-strong);
|
|
2090
|
+
border-radius: 14px; background: color-mix(in srgb, var(--fill) 72%, transparent);
|
|
2091
|
+
}
|
|
2092
|
+
.bp-profile-head { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
|
|
2093
|
+
.bp-profile-head h3 { margin: 0; font-size: var(--fs-1); }
|
|
2094
|
+
.bp-profile-lead { margin: 6px 0 14px; color: var(--muted); font-size: 13.5px; }
|
|
2095
|
+
.bp-profile-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
|
|
2096
|
+
.bp-profile-choice {
|
|
2097
|
+
display: grid; grid-template-columns: auto 1fr; gap: 12px; padding: 14px;
|
|
2098
|
+
border: 1px solid var(--hair-strong); border-radius: 12px; cursor: pointer; background: var(--panel);
|
|
2099
|
+
}
|
|
2100
|
+
.bp-profile-choice:has(input:checked) {
|
|
2101
|
+
border-color: color-mix(in srgb, var(--green) 55%, var(--hair-strong));
|
|
2102
|
+
box-shadow: 0 0 0 2px color-mix(in srgb, var(--green) 12%, transparent);
|
|
2103
|
+
}
|
|
2104
|
+
.bp-profile-choice.unavailable { opacity: 0.58; cursor: not-allowed; }
|
|
2105
|
+
.bp-profile-choice input { margin-top: 4px; accent-color: var(--green); }
|
|
2106
|
+
.bp-profile-copy { display: grid; gap: 5px; min-width: 0; }
|
|
2107
|
+
.bp-profile-title { display: flex; align-items: center; gap: 8px; font-weight: 700; }
|
|
2108
|
+
.bp-profile-meta { font: 12px var(--mono); color: var(--faint); }
|
|
2109
|
+
.bp-profile-desc { color: var(--muted); font-size: 13px; line-height: 1.45; }
|
|
2110
|
+
.bp-profile-actions { display: flex; margin-top: 14px; }
|
|
2111
|
+
.bp-profile-result { margin-top: 10px; }
|
|
2112
|
+
@media (max-width: 700px) { .bp-profile-grid { grid-template-columns: 1fr; } }
|
|
2113
|
+
|
|
2114
|
+
/* "Parts of the brain" — the sub-piece control surface, stated honestly while most of it is still
|
|
2115
|
+
one switch. It is INSIDE this card on purpose: the answer to "where are the per-piece controls?"
|
|
2116
|
+
has to be in the same place as the question. */
|
|
2117
|
+
.bp-parts { margin: 20px 0 0; padding: 4px 16px; border: 1px dashed var(--hair-strong); border-radius: 12px; }
|
|
2118
|
+
.bp-parts > summary {
|
|
2119
|
+
display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap;
|
|
2120
|
+
cursor: pointer; padding: 12px 0; list-style: none;
|
|
2121
|
+
}
|
|
2122
|
+
.bp-parts > summary::-webkit-details-marker { display: none; }
|
|
2123
|
+
.bp-parts > summary::after { content: "›"; margin-left: auto; color: var(--faint); transition: transform 0.2s var(--ease); }
|
|
2124
|
+
.bp-parts[open] > summary::after { transform: rotate(90deg); }
|
|
2125
|
+
.bp-parts > summary:hover { color: var(--amber-text); }
|
|
2126
|
+
.bp-parts[open] > summary { border-bottom: 1px solid var(--hair); }
|
|
2127
|
+
.bp-parts-hint { color: var(--muted); font-size: 13px; }
|
|
2128
|
+
.bp-parts h3 { margin: 0; font-size: var(--fs-1); display: inline; }
|
|
2129
|
+
.bp-parts[open] .bp-parts-lead { margin-top: 12px; }
|
|
2130
|
+
.bp-parts .bp-parts-lead { margin: 0 0 12px; color: var(--muted); font-size: 13.5px; max-width: 84ch; }
|
|
2131
|
+
.bp-part { display: grid; gap: 3px; padding: 10px 0; border-top: 1px solid var(--hair); }
|
|
2132
|
+
.bp-part:first-of-type { border-top: 0; }
|
|
2133
|
+
.bp-part-h { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
|
|
2134
|
+
.bp-part-h b { font-size: 14.5px; }
|
|
2135
|
+
.bp-part-t { color: var(--muted); font-size: 13.5px; max-width: 84ch; }
|
|
2136
|
+
|
|
2137
|
+
/* The card's footnotes need air and a quieter voice: with no top margin the "the switch is a file"
|
|
2138
|
+
line butted straight into the last bullet and read as a third bullet in body ink. `.fn-path` is
|
|
2139
|
+
scoped to `.form-note` where it was born, so the path needs its own rule here rather than
|
|
2140
|
+
inheriting one it never had. */
|
|
2141
|
+
#body-brain .fineprint { margin-top: 14px; color: var(--muted); }
|
|
2142
|
+
#body-brain .fn-path {
|
|
2143
|
+
font-family: var(--mono); font-size: 0.86em; color: var(--faint); overflow-wrap: anywhere;
|
|
2144
|
+
}
|