@bongos/core 1.19.484 → 1.19.485
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/.bongos-core.json +58 -38
- package/docs/copy-inventory.md +163 -175
- package/docs/copy-registry.json +265 -402
- package/docs/file-map.md +1 -1
- package/docs/module-api-changelog.md +2 -0
- package/modules/hall-ui/public/not-ready.html +14 -10
- package/modules/hall-ui/public/not-ready.states.json +14 -0
- package/modules/hall-ui/public/pair.css +17 -67
- package/modules/hall-ui/public/pair.html +8 -1
- package/modules/hall-ui/public/pair.states.json +14 -0
- package/modules/hall-ui/public/panel.css +333 -0
- package/modules/hall-ui/public/profile.css +85 -0
- package/modules/hall-ui/public/profile.html +12 -5
- package/modules/hall-ui/public/profile.states.json +15 -0
- package/modules/hall-ui/public/settings.css +119 -336
- package/modules/hall-ui/public/settings.html +28 -19
- package/modules/hall-ui/public/settings.js +44 -35
- package/modules/hall-ui/public/settings.states.json +16 -0
- package/modules/hall-ui/public/style.css +5 -2
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/scripts/gds/fitness-checks-vocabulary.js +0 -1
- package/src/module-api.js +1 -1
- package/tests/hall_settings_world.mjs +274 -0
- package/tests/join_application_note.mjs +7 -15
- package/tests/module-scope-map.mjs +1 -1
- package/modules/hall-ui/public/my-projects.css +0 -62
- package/modules/hall-ui/public/my-projects.html +0 -73
- package/modules/hall-ui/public/my-projects.js +0 -153
package/docs/file-map.md
CHANGED
|
@@ -130,7 +130,7 @@
|
|
|
130
130
|
│ ├── sessions/ ← CORE-DOMAIN carve (BV1.R82, default-on): the session_records corpus + data plane (upload, cross-builder search/deep-dive), the BFG read-the-room scorer, session-pulse/stale-claim helpers. Registers no port — reached via HTTP POST to its own /sessions route; resolves the economy `reward` port for the cost-plus token reward. CLAUDE.md, module.json, routes/sessions.js, bfg.js, pulse.js.
|
|
131
131
|
│ ├── autonomy/ ← CORE-DOMAIN carve (BV1.R83, default-on): the MAS autonomy surfaces — the $0 deterministic autonomy gate (System 3, inert until armed), the conductor/architect CLIs, and the in-process routine timers (incl. the weekly peer-vote-tally poller). Registers no port; resolves the lifecycle `tallyPeerVotes` doorway. CLAUDE.md, module.json, routes/autonomy.js, autonomy.js.
|
|
132
132
|
│ ├── status-ui/ ← CORE-DOMAIN WEB-SURFACE carve (BV1.R84, default-on): the public status dashboard at status.<apex>, moved from public-status/. NO routes/db/port — declares contributes.webSurfaces:[{host:"status.",dir:"public"}], served by the loader web-surface seam (moduleWebSurfaces → serve-internal). CLAUDE.md, module.json, public/{index.html,status.js,style.css,cursors/,snapshots/}.
|
|
133
|
-
│ ├── hall-ui/ ← CORE-DOMAIN WEB-SURFACE carve (BV1.R85, default-on): the authenticated builders' hall at builders.<apex>, moved from public-builders/ (~13k LOC, the largest). NO routes/db/port — declares contributes.webSurfaces:[{host:"builders.",dir:"public"}] for discovery, but UNLIKE status-ui keeps its DEDICATED serving block in serve-internal (the /builders shim + canonical redirects + citizen/Archon page gates + asset-stamping + hall-widget injection), partitioned out of the generic web-surface loop and served from BUILDERS_DIR. CLAUDE.md, module.json, public/{index.html,builders.js,style.css,work,watch,harbor,gate,pair,settings,ranks,sessions,primer,diagrams,atlas,...}.{html,js},cursors/,chime.wav.
|
|
133
|
+
│ ├── hall-ui/ ← CORE-DOMAIN WEB-SURFACE carve (BV1.R85, default-on): the authenticated builders' hall at builders.<apex>, moved from public-builders/ (~13k LOC, the largest). NO routes/db/port — declares contributes.webSurfaces:[{host:"builders.",dir:"public"}] for discovery, but UNLIKE status-ui keeps its DEDICATED serving block in serve-internal (the /builders shim + canonical redirects + citizen/Archon page gates + asset-stamping + hall-widget injection), partitioned out of the generic web-surface loop and served from BUILDERS_DIR. CLAUDE.md, module.json, public/{index.html,builders.js,style.css,work,watch,harbor,gate,pair,settings,ranks,sessions,primer,diagrams,atlas,...}.{html,js},cursors/,chime.wav. Four ARCHETYPE sheets sit beside the per-page ones: `record.css` (the task + idea records, task 1003305), `room.css` (the READING ROOMS — the primer + the diagrams index, task 1003306: the reading measure and rhythm, the table of contents, the progress hairline and the framed figure diagram-viewer.js upgrades on both pages), `oversight.css` (the OVERSIGHT family — government, watch, harbor, gate, task 1003469: the row, the figure band inside a panel, the group head, the inline form, the grant toggle and the shared confirm modal; named oversight because the vocabulary wall bans "governance" on the government surface) and `panel.css` (the PANEL family — settings, profile, pair, not-ready, task 1003308: the row, the switch, the field with its label above, the chip control, the four voices and the sign-in gate; the hall's my-projects page was DELETED in the same task — "my projects" is the hub's user-level page, and the hall keeps no link or redirect). A page sheet then holds only what one page has and the others do not — `primer.css` the acknowledge gate, `diagrams.css` the legend strip, `gate.css` the hold reasons and file chips, `watch.css` the severities, the report reader and the grade trend, `settings.css` the rail layout, the group head, the token ladder and the voices grid, `profile.css` the identity band and the shelf, `pair.css` the device row, `people.css` the directory's identity cell (task 1003470 made the legacy door `/scouting` ship the same body and script as `/people`; task 1003440 then deleted the door — `scouting.html` and `scouting.states.json` are gone and the URL 301s to `/people`).
|
|
134
134
|
│ ├── lifecycle/ ← CORE-DOMAIN carve (BV1.R86, default-on): the build state machine — tasks · claims · versions · done-when · goals · dependencies · claim→ship→grade→credit · github-push + merge-lock + conflict-resolve + publish-reconciler. The LAST, most-coupled carve; registers the `lifecycle` kernel port (createTask, classifyTaskKind, tallyPeerVotes, work-tracking reads). CLAUDE.md, module.json, routes/{tasks,claims,versions,done-when,goals,dependencies,gate-approvals,analytics}.js, lifecycle.js, github-push.js, merge-lock.js, conflict-resolve.js, publish-reconciler.js, task-visuals.js + task-visual-db.js + routes/visuals.js (the optional ship-time visual, task 1003109 — the route file is NOT named task-*.js on purpose; see the module CLAUDE.md).
|
|
135
135
|
│ ├── copy-desk/ ← CORE-DOMAIN module (task 1003113 / R02 of goal 1000074, default-on): the COPY half of the design contract — ADR 0081 gave design TOKENS a repo-owned source of truth, text had none. Owns the FLAG (anyone in any role marks a string or a whole surface as needing an artist's attention, with a reason required in BOTH the route and a CHECK constraint) and the QUEUE an artist reads it from. READS R01's committed registry (docs/copy-registry.json, generated by scripts/gds/copy-inventory.js) and never writes it. NO LIVE CMS is the hard non-goal: no column here could hold replacement text, and copy_no_cms.mjs pins that. Key is `copy-desk`, not `copy` — the branding contract already owns a `copy` block, so the bare word reds the "core carries no module code" fitness check. CLAUDE.md, module.json, registry.js, flags.js, routes/copy-desk.js, migrations/copy_desk_001_flags.sql, tests/{copy_flags,copy_queue,copy_no_cms}.mjs. Its hall surface lives with hall-ui (public/copy-desk.{html,js,css}), per the one-key-per-web-surface precedent.
|
|
136
136
|
│ ├── ui-design/ ← CORE-DOMAIN module (task 1003324 / ADR 0197, default-on): the design capability every builder on every instance gets — ships METHOD, never a world. Absorbs ADR 0081's layer: adapters/{claude-design,figma}/index.js (moved from src/ui/adapters/), scripts/{design-sync,figma-design-sync,validate-design}.js (moved from scripts/gds/, which keeps thin shims), docs/design-contract.md (moved from docs/). Declaration-only: contributes.skills design (the /design playbook, new) + design-sync + figma-design-sync; no routes/port/migrations, so disabling it touches no served surface. CLAUDE.md separates the platform FLOORS (the Fifteen Rule, the dark twins, no page :root, the 24px floor, AA in both modes, the kill switch) from the instance's WORLD (its packs + DESIGN.md). kit/ (task 1003320) is the look-before-you-ship kit: lib.js (the floors, the states/probes contracts, the action + expectation vocabularies, the WCAG maths, the stub spawner), serve.js (any surface through the doorway's real transforms + fixtures/), render.js (states × 1440/390/320 × dark/light, audited), probe.js (PASS/FAIL contracts), check-mock.js (platform rules + the instance's DESIGN.md taste bans, then the detector), tells.js (task 1003329 / ADR 0223: the anti-pattern detector as two tiers — floors FAIL, craft tells WARN, kit-ignore waivers per file; the rendered twins live in lib.js factsInPage), contrast.js + png.js; a page's <page>.states.json / <page>.probes.json sit BESIDE the surface (modules/public-landing/public/, modules/hall-ui/public/). Recipe: docs/recipes/ui-look-before-you-ship.md. skills/ (task 1003321 / ADR 0198) is the vendoring policy: policy.json (licence allowlist, verdicts that may land, sidecar fields, preamble markers), PREAMBLE.md (the platform preamble every vendored SKILL.md opens with), README.md (the roster — both origins scanned dangerous on 2026-08-28, landed as rebuild specs; nothing vendored — and the landing recipe); a landable copy goes under skills/vendor/<name>/ with PROVENANCE.md + LICENSE and is materialised into an instance's .claude/skills/ by claude-materialize.js step 1b. skills/<name>/ (task 1003325 / ADR 0220) are the in-house rebuilds from the specs, first-party and counted: design-taste-frontend (the default taste skill), design-taste-frontend-v1 (the earlier generation, kept distinct), high-end-visual-design (the polish pass), redesign-existing-projects (the in-place upgrade); each opens with the same preamble and carries a "Rebuilt from" section instead of a sidecar. impeccable/ (task 1003326 / ADR 0221) is the design-craft method as ONE skill with sub-commands: SKILL.md (the router, the menu, the craft floor, the bounded finish) + reference/<sub-command>.md (eighteen playbooks, one loaded per request); no hooks, no bypass agent, no telemetry, no live server. minimalist-ui/, industrial-brutalist-ui/, gpt-taste/, stitch-design-taste/ (task 1003327 / ADR 0230) are the four looks, composition grammars with no colours of their own: the palette is the instance's pack and the texture is a named entry in styles/; a substrate is an archetype that still ships both modes, gpt-taste's selection is derived from the route rather than rolled, and stitch-design-taste writes a DESIGN.md-shaped contract document whose thirteen are transcribed from the pack. image-to-code/, imagegen-frontend-web/, imagegen-frontend-mobile/, brandkit/ (task 1003328 / ADR 0222) are the image family under the hero-only rule: plates and hero objects only, the pair (JPEG dark plate + WebP alpha cutout) with a <file>.json sidecar beside each, through the instance's art pipeline key; the grove specimen's styles/grove/assets/ is the worked example. style/ (task 1003475 / ADR 0231) is the module's first FIRST-PARTY skill (no upstream, so a `## First party` section instead of `## Rebuilt from`): the /style session in which an owner authors their own look in four bounded steps, rendering the nearest library entries before asking, drafting inside the contract, retuning by measurement, and handing over the one-step adoption without ever writing config/branding.json. styles/ (task 1003323 / ADR 0219) is the style library: <name>/pack.json (the theme.ui overlay, exactly the fifteen) + DESIGN.md (the look's derived recipes, thirteen in lockstep with the pack) + mock.html (the specimen); chrome-world (pinned to the neutral pack), expedition, grove, blueprint (the first cool look, authored through /style at task 1003475); STYLE=<name> on the kit lays a look over the instance's pack through GDS_BRANDING_FILE; tests/ui_design_styles.mjs runs the world/cosmos/hall token suites once per alternate (UI_DESIGN_PACK). config/design-tokens.* + design-sources.json STAY in config/ as the host boundary; public-landing keeps its own key (first customer, not owner).
|
|
@@ -1405,5 +1405,7 @@ is load-bearing: the script throws rather than guess if it is missing, and
|
|
|
1405
1405
|
landed since 1.19.482 with no explicit bump. run 33674657478. (task 1002620)
|
|
1406
1406
|
1.19.484 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
1407
1407
|
landed since 1.19.483 with no explicit bump. run 33675143968. (task 1002620)
|
|
1408
|
+
1.19.485 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
1409
|
+
landed since 1.19.484 with no explicit bump. run 33681828446. (task 1002620)
|
|
1408
1410
|
---------------------------------------------------------------------------
|
|
1409
1411
|
```
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
10
10
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
11
11
|
<link rel="stylesheet" href="/builders/style.css?v=2026-07-02-shell1">
|
|
12
|
+
<!-- The PANEL archetype (task 1003308): this page is its sign-in gate shape. -->
|
|
13
|
+
<link rel="stylesheet" href="/builders/panel.css">
|
|
12
14
|
</head>
|
|
13
15
|
<body data-page="not-ready" data-page-title="Locked">
|
|
14
16
|
|
|
@@ -18,21 +20,23 @@
|
|
|
18
20
|
<div class="app-body">
|
|
19
21
|
<header class="app-topbar" id="app-topbar"></header>
|
|
20
22
|
<div class="app-content">
|
|
23
|
+
<!-- The page's ONE h1 (one-header-main-h1), in the family's voice. -->
|
|
24
|
+
<div class="page-head page-head--room page-head--panel">
|
|
25
|
+
<h1 id="not-ready-h1" class="page-head__h">not yet</h1>
|
|
26
|
+
<p class="page-head__sub">This page unlocks as you advance.</p>
|
|
27
|
+
</div>
|
|
21
28
|
<main id="hall-main">
|
|
22
|
-
<section class="scroll">
|
|
23
|
-
<h2 class="
|
|
24
|
-
<p class="
|
|
25
|
-
<p>
|
|
29
|
+
<section class="scroll gate" aria-labelledby="not-ready-h">
|
|
30
|
+
<h2 id="not-ready-h" class="gate__h">Not yet available</h2>
|
|
31
|
+
<p class="gate__lede">
|
|
26
32
|
Xenos builders start with a focused set of pages — ship your first
|
|
27
33
|
<strong>three tasks</strong> to graduate and open the rest of
|
|
28
34
|
{{worldName}}'s builder hub.
|
|
29
35
|
</p>
|
|
30
|
-
<
|
|
31
|
-
<a href="/ranks">See how ranks work
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
<a href="/">← Back to Home</a>
|
|
35
|
-
</p>
|
|
36
|
+
<div class="row-end">
|
|
37
|
+
<a class="pbtn pbtn--save" href="/ranks">See how ranks work</a>
|
|
38
|
+
<a class="pbtn pbtn--quiet" href="/">Back to home</a>
|
|
39
|
+
</div>
|
|
36
40
|
</section>
|
|
37
41
|
</main>
|
|
38
42
|
<footer class="app-foot" id="app-foot"></footer>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_": "The NOT-READY page through modules/ui-design/kit/render.js (task 1003308) — the sign-in gate shape of the panel family, static markup with no feed. Renders under the kit's own stub and under the harness alike.",
|
|
3
|
+
"page": "/not-ready",
|
|
4
|
+
"surface": "hall-ui",
|
|
5
|
+
"stub": { "prefix": "/builders/" },
|
|
6
|
+
"modeQuery": false,
|
|
7
|
+
"ignoreRequests": ["/api/(gds|bongos)/"],
|
|
8
|
+
"ignoreConsole": ["/api/(gds|bongos)/", "\b401\b", "\b404\b", "Unauthorized", "Not Found", "load failed"],
|
|
9
|
+
"states": {
|
|
10
|
+
"locked": { "auth": true, "actions": [["wait", 400]], "expect": { "visible": ["#not-ready-h1", "#not-ready-h"] } },
|
|
11
|
+
"out": { "auth": false, "actions": [["wait", 400]], "expect": { "visible": ["#not-ready-h1"] } }
|
|
12
|
+
},
|
|
13
|
+
"reducedMotion": { "auth": true, "actions": [["wait", 400]] }
|
|
14
|
+
}
|
|
@@ -1,73 +1,23 @@
|
|
|
1
|
-
/* pair.css —
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
/* pair.css — what the Dev Box pairing page has and the rest of the panel family
|
|
2
|
+
does not (task 1003308, goal 1000081; the archetype is panel.css). One panel,
|
|
3
|
+
one device, one button. The device is a row of the family with the platform
|
|
4
|
+
glyph as its figure; the approve button is the page's one accent door. */
|
|
5
5
|
|
|
6
|
-
/* Page-local styles for the pairing approve page (#904) — built on the
|
|
7
|
-
shared design-system tokens in style.css. */
|
|
8
6
|
#pair-scroll { max-width: 640px; }
|
|
9
7
|
|
|
10
8
|
.pair-device {
|
|
11
9
|
display: flex;
|
|
12
10
|
align-items: center;
|
|
13
|
-
gap:
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
border-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
.pair-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
.pair-
|
|
25
|
-
|
|
26
|
-
font-size: 14px;
|
|
27
|
-
font-weight: 600;
|
|
28
|
-
color: var(--ink);
|
|
29
|
-
}
|
|
30
|
-
.pair-device__meta {
|
|
31
|
-
font-family: var(--font-body);
|
|
32
|
-
font-size: 13px;
|
|
33
|
-
color: var(--ink-soft);
|
|
34
|
-
}
|
|
35
|
-
.pair-code {
|
|
36
|
-
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
37
|
-
font-size: 12.5px;
|
|
38
|
-
letter-spacing: 0.08em;
|
|
39
|
-
color: var(--ink-soft);
|
|
40
|
-
}
|
|
41
|
-
.pair-actions {
|
|
42
|
-
display: flex;
|
|
43
|
-
align-items: center;
|
|
44
|
-
gap: 14px;
|
|
45
|
-
flex-wrap: wrap;
|
|
46
|
-
}
|
|
47
|
-
.pair-approve {
|
|
48
|
-
font-family: var(--font-body);
|
|
49
|
-
font-size: 13.5px;
|
|
50
|
-
font-weight: 600;
|
|
51
|
-
padding: 10px 22px;
|
|
52
|
-
background: var(--accent);
|
|
53
|
-
color: #fff;
|
|
54
|
-
border: 1px solid var(--accent);
|
|
55
|
-
border-radius: var(--radius-sm);
|
|
56
|
-
cursor: pointer;
|
|
57
|
-
}
|
|
58
|
-
.pair-approve:hover:not(:disabled) { background: var(--accent-deep); border-color: var(--accent-deep); }
|
|
59
|
-
.pair-approve:disabled { opacity: 0.55; cursor: default; }
|
|
60
|
-
.pair-status {
|
|
61
|
-
font-family: var(--font-body);
|
|
62
|
-
font-size: 13.5px;
|
|
63
|
-
color: var(--ink-soft);
|
|
64
|
-
min-height: 1.2em;
|
|
65
|
-
}
|
|
66
|
-
.pair-status--ok { color: var(--ok); font-weight: 600; }
|
|
67
|
-
.pair-status--err { color: var(--danger); }
|
|
68
|
-
.pair-note {
|
|
69
|
-
font-family: var(--font-body);
|
|
70
|
-
font-size: 13px;
|
|
71
|
-
color: var(--ink-faint);
|
|
72
|
-
margin-top: 16px;
|
|
73
|
-
}
|
|
11
|
+
gap: var(--sp-sm);
|
|
12
|
+
margin: var(--sp-sm) 0 var(--sp-md);
|
|
13
|
+
padding: var(--sp-sm) 0;
|
|
14
|
+
border-top: var(--line) solid var(--rule-soft);
|
|
15
|
+
border-bottom: var(--line) solid var(--rule-soft);
|
|
16
|
+
}
|
|
17
|
+
.pair-device__glyph { width: 40px; font-size: 26px; line-height: 1; text-align: center; color: var(--ink-soft); flex: none; }
|
|
18
|
+
.pair-device__name { font-size: 14.5px; font-weight: 500; color: var(--ink); }
|
|
19
|
+
.pair-device__meta { margin-top: 2px; font-size: 13.5px; color: var(--ink-soft); }
|
|
20
|
+
.pair-code { font-family: var(--font-mono); font-size: 12.5px; letter-spacing: .08em; color: var(--ink); }
|
|
21
|
+
.pair-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-xs); }
|
|
22
|
+
.pair-actions .pair-status { margin: 0; }
|
|
23
|
+
.pair-note { margin: var(--sp-sm) 0 0; max-width: var(--measure); font-size: 13px; color: var(--ink-faint); }
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
10
10
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
11
11
|
<link rel="stylesheet" href="/builders/style.css?v=2026-07-02-shell1">
|
|
12
|
+
<!-- The PANEL archetype (task 1003308) before the page's own sheet. -->
|
|
13
|
+
<link rel="stylesheet" href="/builders/panel.css">
|
|
12
14
|
<link rel="stylesheet" href="/builders/pair.css">
|
|
13
15
|
</head>
|
|
14
16
|
<body data-page="pair" data-page-title="Device pairing">
|
|
@@ -19,7 +21,12 @@
|
|
|
19
21
|
<div class="app-body">
|
|
20
22
|
<header class="app-topbar" id="app-topbar"></header>
|
|
21
23
|
<div class="app-content">
|
|
22
|
-
|
|
24
|
+
<!-- The page's ONE h1 (one-header-main-h1), in the family's voice; the
|
|
25
|
+
sub-line is pair.js's — the request, the approval, or the error. -->
|
|
26
|
+
<div class="page-head page-head--room page-head--panel">
|
|
27
|
+
<h1 id="pair-h1" class="page-head__h">pairing</h1>
|
|
28
|
+
<p class="page-head__sub" id="pair-sub">Reading the request…</p>
|
|
29
|
+
</div>
|
|
23
30
|
<main id="hall-main">
|
|
24
31
|
<section class="scroll" id="pair-scroll" aria-labelledby="pair-h">
|
|
25
32
|
<h2 id="pair-h" class="scroll__h">A device is asking to act as you</h2>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_": "The Dev Box PAIRING page through modules/ui-design/kit/render.js (task 1003308). The device row and the approve button only exist once the pairing request has LOADED, so the populated state runs against the hall-preview harness (see settings.states.json for the two commands; the harness serves scripts/hall-preview/fixtures/auth__app-pair__info.json for any code). `nocode` is the page's own error render — the link arrived without its pairing code — and needs nothing served.",
|
|
3
|
+
"page": "/pair",
|
|
4
|
+
"surface": "hall-ui",
|
|
5
|
+
"stub": { "prefix": "/builders/" },
|
|
6
|
+
"modeQuery": false,
|
|
7
|
+
"ignoreRequests": ["/api/(gds|bongos)/"],
|
|
8
|
+
"ignoreConsole": ["/api/(gds|bongos)/", "\b401\b", "\b404\b", "Unauthorized", "Not Found", "load failed"],
|
|
9
|
+
"states": {
|
|
10
|
+
"request": { "auth": true, "url": "/pair?code=K7QD-4M2X", "actions": [["wait", 700]], "expect": { "visible": ["#pair-h1", "#pair-approve-btn"] } },
|
|
11
|
+
"nocode": { "auth": true, "actions": [["wait", 700]], "expect": { "visible": ["#pair-h1", "#pair-scroll .pair-status--err"] } }
|
|
12
|
+
},
|
|
13
|
+
"reducedMotion": { "auth": true, "url": "/pair?code=K7QD-4M2X", "actions": [["wait", 700]] }
|
|
14
|
+
}
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
/* panel.css — the PANEL archetype: a titled panel that holds a form, read top
|
|
2
|
+
to bottom (task 1003308, goal 1000081). Shared by settings, profile, pair,
|
|
3
|
+
and not-ready — the pages where the builder reads a label, a
|
|
4
|
+
sentence of consequence, and then acts on ONE control.
|
|
5
|
+
|
|
6
|
+
THE ARCHETYPE is v3 "the glass hall", the owner's pick from the composition
|
|
7
|
+
round — docs/design/hall-direction-v2.md §6, mock
|
|
8
|
+
docs/design/mocks/hall/settings/v3.html. Reading order inside a panel: the
|
|
9
|
+
panel's name, one lede of purpose, then ROWS — each a label, a description in
|
|
10
|
+
the soft ink, and the control on the right — or a FIELD, its label above it
|
|
11
|
+
in the label voice, the input and its button on one line, the status line
|
|
12
|
+
under it, and a note in the faint ink at the foot saying when the change
|
|
13
|
+
applies. The panel is the shell's `.scroll`; v3 has exactly three card levels
|
|
14
|
+
and a fourth would be a design decision, not a local override.
|
|
15
|
+
|
|
16
|
+
WHAT IS SHARED and what is not: the row, the switch, the field, the chip
|
|
17
|
+
control, the status/hint/note voices and the sign-in gate are the family's.
|
|
18
|
+
The section rail and the token ladder are settings' (settings.css); the
|
|
19
|
+
identity band and the shelf are the profile's (profile.css); the device card
|
|
20
|
+
is pair's (pair.css).
|
|
21
|
+
|
|
22
|
+
THE NAMES the page scripts already write (`.sound-row`, `.sessions-row`,
|
|
23
|
+
`.settings-btn`, `.craft-chip` …) are aliased onto the family's rules here
|
|
24
|
+
rather than renamed in three JS files: a class name is not what was wrong
|
|
25
|
+
with these pages — the six divergent hand-rolled rows were.
|
|
26
|
+
|
|
27
|
+
Everything below spends the world's real token names. No compat alias
|
|
28
|
+
(--surface / --surface-2 / --border / --border-strong / --accent-weak /
|
|
29
|
+
--accent-text) appears here — they exist for pages nobody has re-skinned, so
|
|
30
|
+
spending one is legal CSS that quietly opts this sheet back out of the world.
|
|
31
|
+
`--line` is a WIDTH; the hairline's colour is --rule / --rule-soft. */
|
|
32
|
+
|
|
33
|
+
/* ---- the page head ------------------------------------------------------ */
|
|
34
|
+
/* The family takes the reading room's VOICE — the page's own name, lowercase in
|
|
35
|
+
the display face — because on a settings page the document IS the page: the
|
|
36
|
+
builder came to read their own record and change one line of it. The room's
|
|
37
|
+
top air is a reading room's; a form page starts at the content edge. */
|
|
38
|
+
.page-head--room.page-head--panel { padding-top: 0; }
|
|
39
|
+
.page-head--room.page-head--panel .page-head__sub { margin-top: var(--sp-sm); }
|
|
40
|
+
|
|
41
|
+
/* ---- the panel's voices ------------------------------------------------- */
|
|
42
|
+
.panel-lede,
|
|
43
|
+
.scroll > .panel-lede { margin: 0 0 var(--sp-sm); max-width: var(--measure); font-size: 14.5px; color: var(--ink-soft); }
|
|
44
|
+
.panel-note,
|
|
45
|
+
.section-note { margin: var(--sp-sm) 0 0; max-width: var(--measure); font-size: 13px; color: var(--ink-faint); }
|
|
46
|
+
.panel-note:empty, .section-note:empty { display: none; }
|
|
47
|
+
.panel-hint,
|
|
48
|
+
.settings-card__hint { font-size: 13px; color: var(--ink-faint); }
|
|
49
|
+
.panel-status,
|
|
50
|
+
.settings-status,
|
|
51
|
+
.pair-status { margin: var(--sp-xs) 0 0; min-height: 1.2em; font-size: 13.5px; color: var(--ink-soft); }
|
|
52
|
+
.panel-status--ok, .settings-card__ok, .pair-status--ok { color: var(--ok); }
|
|
53
|
+
.panel-status--danger, .pair-status--err { color: var(--danger); }
|
|
54
|
+
.panel-status:empty, .settings-status:empty { margin-top: 0; min-height: 0; }
|
|
55
|
+
/* a prose link in any of the four voices is a control and owes the 24px floor */
|
|
56
|
+
.panel-lede a, .panel-note a, .panel-hint a, .panel-status a, .settings-card__hint a, .section-note a {
|
|
57
|
+
display: inline-block;
|
|
58
|
+
min-width: 24px;
|
|
59
|
+
min-height: 24px;
|
|
60
|
+
padding: 3px 4px;
|
|
61
|
+
margin: 0 -4px;
|
|
62
|
+
color: var(--accent-ink);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* ---- the row: label, description, control ------------------------------ */
|
|
66
|
+
.prows,
|
|
67
|
+
.sound-rows, .event-sound-rows, .sessions-list, #cross-project-rows, #privacy-rows { display: flex; flex-direction: column; margin-top: var(--sp-sm); }
|
|
68
|
+
.prow,
|
|
69
|
+
.sound-row, .event-sound-row, .sessions-row {
|
|
70
|
+
display: flex;
|
|
71
|
+
align-items: center;
|
|
72
|
+
gap: var(--sp-sm);
|
|
73
|
+
padding: var(--sp-sm) 0;
|
|
74
|
+
border-top: var(--line) solid var(--rule-soft);
|
|
75
|
+
}
|
|
76
|
+
.prow__main,
|
|
77
|
+
.sound-row__text, .event-sound-row__text, .sessions-row__main { flex: 1 1 auto; min-width: 0; }
|
|
78
|
+
.prow__label,
|
|
79
|
+
.sound-row__label, .event-sound-row__label, .sessions-row__main > strong { display: block; margin: 0; font-size: 14.5px; font-weight: 500; color: var(--ink); }
|
|
80
|
+
.prow__desc,
|
|
81
|
+
.sound-row__desc, .event-sound-row__desc, .sessions-row__agent, .sessions-row__when { display: block; margin: 2px 0 0; font-size: 13.5px; color: var(--ink-soft); }
|
|
82
|
+
.prow__ctl,
|
|
83
|
+
.event-sound-row__controls { display: flex; align-items: center; justify-content: flex-end; flex: none; flex-wrap: wrap; gap: var(--sp-hair); }
|
|
84
|
+
/* the default note on a row label — "· default for your rank" — is a fact, so it
|
|
85
|
+
takes the label voice beside the label rather than the label's own weight */
|
|
86
|
+
.prow__tag,
|
|
87
|
+
.voices__default { margin-left: 8px; font-family: var(--label-face); font-size: 10.5px; font-weight: 400; letter-spacing: var(--label-space); text-transform: var(--label-case); color: var(--ink-faint); }
|
|
88
|
+
/* a pick row: the whole row is the radio's label */
|
|
89
|
+
.prow--pick { cursor: pointer; }
|
|
90
|
+
.prow--pick .prow__main { display: block; }
|
|
91
|
+
.prow--pick .prow__label, .prow--pick .prow__desc { display: block; }
|
|
92
|
+
.prow--pick[aria-disabled="true"] { cursor: default; }
|
|
93
|
+
.prow--pick[aria-disabled="true"] .prow__label { color: var(--ink-soft); }
|
|
94
|
+
|
|
95
|
+
/* the action row at a panel's foot: buttons and their status on one line */
|
|
96
|
+
.row-end,
|
|
97
|
+
.settings-card, .craft-actions, .artkey-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-xs); margin-top: var(--sp-sm); }
|
|
98
|
+
.row-end .panel-status, .row-end .settings-status,
|
|
99
|
+
.craft-actions .settings-status { margin: 0; }
|
|
100
|
+
|
|
101
|
+
/* ---- the controls: every one clears 24px on both axes ------------------- */
|
|
102
|
+
/* the family button: a glass pill, 38px, quiet by default. `--save` is the
|
|
103
|
+
accent door — the panel's one primary act — and takes --accent-on, the dark
|
|
104
|
+
ink for the salmon; white on it fails AA and DESIGN.md bans it. */
|
|
105
|
+
.pbtn,
|
|
106
|
+
.settings-btn, .sessions-row__end, .event-sound-preview, .pair-approve {
|
|
107
|
+
display: inline-flex;
|
|
108
|
+
align-items: center;
|
|
109
|
+
justify-content: center;
|
|
110
|
+
gap: 8px;
|
|
111
|
+
min-height: 38px;
|
|
112
|
+
min-width: 38px;
|
|
113
|
+
padding: 0 15px;
|
|
114
|
+
border: var(--line) solid var(--glass-edge);
|
|
115
|
+
border-radius: var(--radius-pill);
|
|
116
|
+
background: var(--glass);
|
|
117
|
+
color: var(--ink);
|
|
118
|
+
font: inherit;
|
|
119
|
+
font-size: 14px;
|
|
120
|
+
line-height: 1.2;
|
|
121
|
+
white-space: nowrap;
|
|
122
|
+
text-decoration: none;
|
|
123
|
+
cursor: pointer;
|
|
124
|
+
transition: background 200ms cubic-bezier(.2,.7,.3,1), border-color 200ms cubic-bezier(.2,.7,.3,1), color 200ms cubic-bezier(.2,.7,.3,1);
|
|
125
|
+
}
|
|
126
|
+
.pbtn:hover:not(:disabled), .settings-btn:hover:not(:disabled), .sessions-row__end:hover:not(:disabled),
|
|
127
|
+
.event-sound-preview:hover:not(:disabled), .pair-approve:hover:not(:disabled) { background: var(--glass-strong); color: var(--ink); text-decoration: none; }
|
|
128
|
+
.pbtn:disabled, .settings-btn:disabled, .sessions-row__end:disabled, .pair-approve:disabled,
|
|
129
|
+
.pbtn[aria-disabled="true"], .settings-btn[aria-disabled="true"] { color: var(--ink-faint); background: var(--glass); cursor: default; }
|
|
130
|
+
.pbtn--quiet, .settings-btn--quiet, .sessions-row__end, .event-sound-preview { background: transparent; }
|
|
131
|
+
.pbtn--save,
|
|
132
|
+
.craft-save, .pair-approve { background: var(--accent); border-color: var(--accent); color: var(--accent-on); font-weight: 500; }
|
|
133
|
+
.pbtn--save:hover:not(:disabled), .craft-save:hover:not(:disabled), .pair-approve:hover:not(:disabled) { background: var(--accent-lift); border-color: var(--accent-lift); color: var(--accent-on); }
|
|
134
|
+
.craft-save:disabled, .pbtn--save:disabled, .pair-approve:disabled { background: var(--glass); border-color: var(--glass-edge); color: var(--ink-faint); }
|
|
135
|
+
/* the shell's `.craft-save` was a bordered box; it is the family's save button
|
|
136
|
+
now, so it carries the pill's own box model too */
|
|
137
|
+
button.craft-save { display: inline-flex; align-items: center; justify-content: center; min-height: 38px; min-width: 38px; padding: 0 15px; border-radius: var(--radius-pill); font: inherit; font-size: 14px; cursor: pointer; }
|
|
138
|
+
|
|
139
|
+
/* the field: label above, input and its button on one line */
|
|
140
|
+
.field-label,
|
|
141
|
+
.join-note-label {
|
|
142
|
+
display: block;
|
|
143
|
+
margin: var(--sp-sm) 0 var(--sp-hair);
|
|
144
|
+
font-family: var(--label-face);
|
|
145
|
+
font-size: var(--label-size);
|
|
146
|
+
letter-spacing: var(--label-space);
|
|
147
|
+
text-transform: var(--label-case);
|
|
148
|
+
color: var(--ink-faint);
|
|
149
|
+
}
|
|
150
|
+
.field,
|
|
151
|
+
.display-name-row, .artkey-entry-row, .join { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-xs); margin-top: 0; }
|
|
152
|
+
.field .field-label { flex: 1 1 100%; margin-top: 0; }
|
|
153
|
+
.pinput,
|
|
154
|
+
.display-name-input, .artkey-input, .join input, .join-note {
|
|
155
|
+
flex: 1 1 260px;
|
|
156
|
+
max-width: 420px;
|
|
157
|
+
min-height: 38px;
|
|
158
|
+
padding: 0 16px;
|
|
159
|
+
font: inherit;
|
|
160
|
+
font-size: 15px;
|
|
161
|
+
color: var(--ink);
|
|
162
|
+
background: var(--glass);
|
|
163
|
+
border: var(--line) solid var(--glass-edge);
|
|
164
|
+
border-radius: var(--radius-pill);
|
|
165
|
+
transition: border-color 200ms cubic-bezier(.2,.7,.3,1);
|
|
166
|
+
}
|
|
167
|
+
.pinput::placeholder, .display-name-input::placeholder, .artkey-input::placeholder, .join input::placeholder, .join-note::placeholder { color: var(--ink-faint); }
|
|
168
|
+
.pinput:hover, .display-name-input:hover, .artkey-input:hover, .join input:hover, .join-note:hover { border-color: var(--rule); }
|
|
169
|
+
.pinput[aria-invalid="true"], .display-name-input[aria-invalid="true"] { border-color: var(--danger); }
|
|
170
|
+
/* a secret is typed in the mono face so a pasted key reads as what it is */
|
|
171
|
+
.artkey-input { font-family: var(--font-mono); font-size: 13.5px; }
|
|
172
|
+
.psel,
|
|
173
|
+
.event-sound-select, .voices__select { min-height: 38px; padding: 0 var(--sp-xs); font: inherit; font-size: 14px; color: var(--ink); background: var(--glass); border: var(--line) solid var(--glass-edge); border-radius: var(--radius-pill); cursor: pointer; }
|
|
174
|
+
.psel:hover, .event-sound-select:hover, .voices__select:hover { border-color: var(--rule); }
|
|
175
|
+
.prange,
|
|
176
|
+
.sound-volume input[type="range"] { flex: 1 1 200px; max-width: 260px; height: 38px; margin: 0; accent-color: var(--accent); cursor: pointer; }
|
|
177
|
+
.pradio { width: 24px; height: 24px; flex: none; margin: 0; accent-color: var(--accent); cursor: pointer; }
|
|
178
|
+
.pradio:disabled { cursor: default; opacity: .55; }
|
|
179
|
+
|
|
180
|
+
/* the switch: a 46x38 button whose drawn track is 44x24 — the target clears
|
|
181
|
+
the floor, the drawing stays the world's small shape. State is aria-checked;
|
|
182
|
+
the page scripts still read data-on, which they wrote. */
|
|
183
|
+
.sw,
|
|
184
|
+
.sound-toggle {
|
|
185
|
+
position: relative;
|
|
186
|
+
display: inline-flex;
|
|
187
|
+
align-items: center;
|
|
188
|
+
width: 46px;
|
|
189
|
+
min-width: 46px;
|
|
190
|
+
height: 38px;
|
|
191
|
+
flex: none;
|
|
192
|
+
padding: 0;
|
|
193
|
+
margin: 0;
|
|
194
|
+
border: 0;
|
|
195
|
+
background: none;
|
|
196
|
+
font-size: 0;
|
|
197
|
+
color: transparent;
|
|
198
|
+
cursor: pointer;
|
|
199
|
+
}
|
|
200
|
+
.sw__track {
|
|
201
|
+
width: 44px;
|
|
202
|
+
height: 24px;
|
|
203
|
+
border-radius: var(--radius-pill);
|
|
204
|
+
background: var(--glass-strong);
|
|
205
|
+
border: 1px solid var(--rule);
|
|
206
|
+
transition: background 240ms cubic-bezier(.2,.7,.3,1), border-color 240ms cubic-bezier(.2,.7,.3,1);
|
|
207
|
+
}
|
|
208
|
+
.sw__knob {
|
|
209
|
+
position: absolute;
|
|
210
|
+
left: 5px;
|
|
211
|
+
width: 16px;
|
|
212
|
+
height: 16px;
|
|
213
|
+
border-radius: var(--radius-pill);
|
|
214
|
+
background: var(--ink-faint);
|
|
215
|
+
transition: transform 260ms cubic-bezier(.2,.7,.3,1), background 240ms cubic-bezier(.2,.7,.3,1);
|
|
216
|
+
}
|
|
217
|
+
.sw[aria-checked="true"] .sw__track, .sound-toggle[aria-checked="true"] .sw__track { background: var(--accent-tint); border-color: var(--accent); }
|
|
218
|
+
.sw[aria-checked="true"] .sw__knob, .sound-toggle[aria-checked="true"] .sw__knob { transform: translateX(20px); background: var(--accent); }
|
|
219
|
+
.sw:disabled, .sound-toggle:disabled { cursor: default; opacity: .55; }
|
|
220
|
+
@media (prefers-reduced-motion: reduce) {
|
|
221
|
+
.sw__track, .sw__knob, .pbtn, .settings-btn, .pinput { transition: none; }
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/* the chip control: a checkbox in a pill. The box is a 24px target drawing a
|
|
225
|
+
14px square — the 13x13 native box was the smallest control in the hall. */
|
|
226
|
+
.chips,
|
|
227
|
+
.craft-chips { display: flex; flex-wrap: wrap; gap: var(--sp-hair); margin-top: var(--sp-sm); }
|
|
228
|
+
.chip-ctl,
|
|
229
|
+
.craft-chip {
|
|
230
|
+
display: inline-flex;
|
|
231
|
+
align-items: center;
|
|
232
|
+
gap: 6px;
|
|
233
|
+
min-height: 38px;
|
|
234
|
+
padding: 0 14px 0 8px;
|
|
235
|
+
border: var(--line) solid var(--glass-edge);
|
|
236
|
+
border-radius: var(--radius-pill);
|
|
237
|
+
background: var(--glass);
|
|
238
|
+
color: var(--ink-soft);
|
|
239
|
+
font-size: 14px;
|
|
240
|
+
text-transform: lowercase;
|
|
241
|
+
cursor: pointer;
|
|
242
|
+
user-select: none;
|
|
243
|
+
}
|
|
244
|
+
.chip-ctl:has(input:checked), .craft-chip[data-on="1"] { color: var(--ink); border-color: var(--rule); }
|
|
245
|
+
.chip-ctl input, .craft-pref {
|
|
246
|
+
appearance: none;
|
|
247
|
+
-webkit-appearance: none;
|
|
248
|
+
position: relative;
|
|
249
|
+
width: 24px;
|
|
250
|
+
height: 24px;
|
|
251
|
+
margin: 0;
|
|
252
|
+
flex: none;
|
|
253
|
+
cursor: pointer;
|
|
254
|
+
}
|
|
255
|
+
.chip-ctl input::before, .craft-pref::before {
|
|
256
|
+
content: "";
|
|
257
|
+
position: absolute;
|
|
258
|
+
inset: 5px;
|
|
259
|
+
width: 14px;
|
|
260
|
+
height: 14px;
|
|
261
|
+
border: var(--line) solid var(--ink-faint);
|
|
262
|
+
border-radius: 4px;
|
|
263
|
+
background: transparent;
|
|
264
|
+
}
|
|
265
|
+
.chip-ctl input:checked::before, .craft-pref:checked::before { background: var(--accent); border-color: var(--accent); }
|
|
266
|
+
.chip-ctl input:checked::after, .craft-pref:checked::after {
|
|
267
|
+
content: "";
|
|
268
|
+
position: absolute;
|
|
269
|
+
left: 9px;
|
|
270
|
+
top: 6px;
|
|
271
|
+
width: 4px;
|
|
272
|
+
height: 8px;
|
|
273
|
+
border: solid var(--accent-on);
|
|
274
|
+
border-width: 0 2px 2px 0;
|
|
275
|
+
transform: rotate(45deg);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/* ---- the status pill on a row --------------------------------------------- */
|
|
279
|
+
/* the fixed status vocabulary in the label voice — the shell's .fact-pill; the
|
|
280
|
+
sessions badge is the same pill under the name settings-sessions.js writes */
|
|
281
|
+
.sessions-row__badge {
|
|
282
|
+
display: inline-flex;
|
|
283
|
+
align-items: center;
|
|
284
|
+
min-height: 24px;
|
|
285
|
+
padding: 0 11px;
|
|
286
|
+
margin-left: 8px;
|
|
287
|
+
border: var(--line) solid currentColor;
|
|
288
|
+
border-radius: var(--radius-pill);
|
|
289
|
+
font-family: var(--label-face);
|
|
290
|
+
font-size: 10.5px;
|
|
291
|
+
font-weight: 400;
|
|
292
|
+
letter-spacing: var(--label-space);
|
|
293
|
+
text-transform: var(--label-case);
|
|
294
|
+
color: var(--info);
|
|
295
|
+
white-space: nowrap;
|
|
296
|
+
vertical-align: middle;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/* ---- the banner: one line of consequence, warn or ok ---------------------- */
|
|
300
|
+
.pbanner {
|
|
301
|
+
margin: 0 0 var(--sp-sm);
|
|
302
|
+
padding: var(--sp-xs) var(--sp-sm);
|
|
303
|
+
font-size: 14px;
|
|
304
|
+
line-height: 1.45;
|
|
305
|
+
color: var(--ink);
|
|
306
|
+
background: var(--warn-weak);
|
|
307
|
+
border-left: 2px solid var(--warn);
|
|
308
|
+
border-radius: var(--radius-sm);
|
|
309
|
+
}
|
|
310
|
+
.pbanner--ok { background: var(--ok-weak); border-left-color: var(--ok); }
|
|
311
|
+
.pbanner strong { font-weight: 500; }
|
|
312
|
+
|
|
313
|
+
/* ---- the sign-in gate ----------------------------------------------------- */
|
|
314
|
+
/* Shown INSTEAD of the page when there is nobody to show it to. It is a panel
|
|
315
|
+
with the display voice, the honest sentence, and the one door. */
|
|
316
|
+
.gate { border-top: var(--line) solid var(--glass-edge); }
|
|
317
|
+
.gate__h { margin: 0; font-family: var(--font-display); font-weight: 300; font-size: clamp(22px, 2.1vw, 29px); line-height: 1.15; letter-spacing: -.03em; color: var(--ink); }
|
|
318
|
+
.gate__lede { margin: var(--sp-xs) 0 var(--sp-sm); max-width: var(--measure); font-size: 15px; color: var(--ink-soft); }
|
|
319
|
+
.gate .row-end { margin-top: 0; }
|
|
320
|
+
|
|
321
|
+
/* ---- the skeleton --------------------------------------------------------- */
|
|
322
|
+
/* --skeleton, never --bg-deep: that one collapses to pure black in dark */
|
|
323
|
+
.pskel { display: block; background: var(--skeleton); border-radius: var(--radius-sm); }
|
|
324
|
+
.pskel--row { height: 52px; margin-top: var(--sp-hair); }
|
|
325
|
+
.pskel--h { height: 26px; width: min(240px, 60%); }
|
|
326
|
+
|
|
327
|
+
/* ---- responsive ----------------------------------------------------------- */
|
|
328
|
+
@media (max-width: 520px) {
|
|
329
|
+
.prow, .sound-row, .event-sound-row, .sessions-row { flex-direction: column; align-items: flex-start; gap: var(--sp-xs); }
|
|
330
|
+
.prow__ctl, .event-sound-row__controls { justify-content: flex-start; }
|
|
331
|
+
.prow--pick { flex-direction: row; align-items: flex-start; }
|
|
332
|
+
.pinput, .display-name-input, .artkey-input, .join input, .join-note { max-width: none; }
|
|
333
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/* profile.css — what the builder's profile page has and the rest of the panel
|
|
2
|
+
family does not (task 1003308, goal 1000081; the archetype is panel.css). The
|
|
3
|
+
page everyone else reads: the identity band, the figures, the shelf, the
|
|
4
|
+
ledgers. The figures are the shell's glass band (.stat-row) and the ledgers
|
|
5
|
+
the shell's .ledger; this sheet owns the identity band and the shelf, both
|
|
6
|
+
drawn from docs/design/mocks/hall/settings/v3.html (the profile half).
|
|
7
|
+
|
|
8
|
+
The shell's .profile grid is shared with Home's Standing card, so the band
|
|
9
|
+
here is a MODIFIER (.profile--ident) rather than a second rule for the base
|
|
10
|
+
name; the shelf's .ach is scoped by this sheet loading on this page only. */
|
|
11
|
+
|
|
12
|
+
/* ---- the identity band ---------------------------------------------------- */
|
|
13
|
+
.profile--ident {
|
|
14
|
+
grid-template-columns: 56px minmax(0, 1fr) auto;
|
|
15
|
+
gap: var(--sp-sm);
|
|
16
|
+
align-items: center;
|
|
17
|
+
}
|
|
18
|
+
.profile--ident .profile__avatar {
|
|
19
|
+
width: 56px;
|
|
20
|
+
height: 56px;
|
|
21
|
+
border-radius: var(--radius-pill);
|
|
22
|
+
background: var(--skeleton);
|
|
23
|
+
border: 1px solid var(--rule);
|
|
24
|
+
}
|
|
25
|
+
.profile--ident .profile__name {
|
|
26
|
+
font-family: var(--font-display);
|
|
27
|
+
font-weight: 300;
|
|
28
|
+
font-size: clamp(22px, 2vw, 28px);
|
|
29
|
+
letter-spacing: -.03em;
|
|
30
|
+
line-height: 1.1;
|
|
31
|
+
}
|
|
32
|
+
.profile--ident .profile__handle { margin: 4px 0 0; font-family: var(--font-mono); font-size: 12.5px; color: var(--ink-faint); }
|
|
33
|
+
.profile--ident .profile__stats { margin-top: 4px; font-size: 13px; }
|
|
34
|
+
.profile--ident .profile__disciplines { margin-top: 4px; font-size: 13px; }
|
|
35
|
+
.profile--ident .profile__credits-num { font-family: var(--font-display); font-weight: 300; font-size: clamp(26px, 2.4vw, 32px); letter-spacing: -.035em; line-height: 1; color: var(--ink); }
|
|
36
|
+
.profile--ident .profile__credits-label,
|
|
37
|
+
.profile--ident .profile__karma-label { font-family: var(--label-face); font-size: var(--label-size); font-weight: 400; letter-spacing: var(--label-space); text-transform: var(--label-case); color: var(--ink-faint); }
|
|
38
|
+
.profile--ident .profile__karma-num { font-weight: 500; }
|
|
39
|
+
.profile--ident .profile__placeholder { grid-column: 1 / -1; }
|
|
40
|
+
|
|
41
|
+
/* ---- the shelf -------------------------------------------------------------
|
|
42
|
+
An achievement is a --bg-card tile on the ground (the section is bare, so a
|
|
43
|
+
tile is the panel and not a card in a card), a hairline on top, the mark as
|
|
44
|
+
its figure, the name at the row's weight and the day it was won in the soft
|
|
45
|
+
ink at the foot. */
|
|
46
|
+
.ach-grid { grid-template-columns: repeat(auto-fill, minmax(215px, 1fr)); gap: var(--sp-sm); }
|
|
47
|
+
.ach {
|
|
48
|
+
flex-direction: column;
|
|
49
|
+
gap: 5px;
|
|
50
|
+
padding: 18px;
|
|
51
|
+
background: var(--bg-card);
|
|
52
|
+
border: var(--line) solid var(--glass-edge);
|
|
53
|
+
border-top-color: var(--rule);
|
|
54
|
+
border-radius: var(--radius);
|
|
55
|
+
}
|
|
56
|
+
.ach__icon { font-size: 22px; line-height: 1; margin-bottom: 4px; }
|
|
57
|
+
.ach__name { font-size: 14.5px; font-weight: 500; margin: 0; }
|
|
58
|
+
.ach__desc { font-size: 13px; line-height: 1.4; color: var(--ink-soft); }
|
|
59
|
+
.ach__bonus { margin: auto 0 0; padding-top: var(--sp-hair); font-size: 12.5px; font-weight: 400; color: var(--ink-soft); }
|
|
60
|
+
.ach--locked { border-top-color: var(--rule-soft); }
|
|
61
|
+
.ach--locked .ach__name, .ach--locked .ach__desc { color: var(--ink-faint); }
|
|
62
|
+
|
|
63
|
+
/* ---- the ledgers ---------------------------------------------------------- */
|
|
64
|
+
/* A title in a ledger cell is a door and owes the 24px floor on both axes; it
|
|
65
|
+
measured 18px tall on every populated render (thirteen links a page). The
|
|
66
|
+
prose-link recipe: inline-block buys the height, the padding buys the width,
|
|
67
|
+
the negative margin hands both back so the cell does not re-space. */
|
|
68
|
+
#works-scroll .ledger td a,
|
|
69
|
+
#activity-scroll .ledger td a,
|
|
70
|
+
#xp-scroll a {
|
|
71
|
+
display: inline-block;
|
|
72
|
+
min-width: 24px;
|
|
73
|
+
min-height: 24px;
|
|
74
|
+
padding: 3px 4px;
|
|
75
|
+
margin: -3px -4px;
|
|
76
|
+
color: var(--accent-ink);
|
|
77
|
+
}
|
|
78
|
+
.profile-act__h { margin: var(--sp-md) 0 var(--sp-xs); font-size: 15px; font-weight: 500; color: var(--ink); }
|
|
79
|
+
#activity-body > [id$="-panel"] + [id$="-panel"] { margin-top: var(--sp-md); }
|
|
80
|
+
|
|
81
|
+
@media (max-width: 640px) {
|
|
82
|
+
.profile--ident { grid-template-columns: 48px minmax(0, 1fr); }
|
|
83
|
+
.profile--ident .profile__avatar { width: 48px; height: 48px; }
|
|
84
|
+
.profile--ident .profile__credits { grid-column: 2; align-items: flex-start; text-align: left; }
|
|
85
|
+
}
|