@volter/world-console 2.0.0 → 2.0.2

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/README.md CHANGED
@@ -1,10 +1,12 @@
1
1
  # @volter/world-console
2
2
 
3
- The console of [Volter World](https://github.com/volter-ai/world): one UI for a world, in both modes.
3
+ The dashboard of [Volter World](https://github.com/volter-ai/world): a World's pages — its vendors' screens,
4
+ overview, branches, changes, activity and keys. It is the same page on your machine (`volter world view`), on a
5
+ self-hosted host and on the hosted cloud, and it carries nothing of orgs, members or billing: those are the
6
+ platform's pages. Install it beside `@volter/world-host`; the host mounts it at `/-/console/` and prints its URL.
4
7
 
5
- - **Self-hosted**: install it beside `@volter/world-host`; the host mounts it at `/-/console/` and
6
- prints its URL. You reach every world the host serves with the token you type.
7
- - **Managed**: the hosted platform serves the same console as its portal.
8
+ `@volter/world-console/kit` is the pieces the platform's pages share with it (the brand's mark, door reads,
9
+ instants, vendors' marks and the stylesheet).
8
10
 
9
11
  It is a pure frontend — a React client bundled at serve time behind one shell — and reads nothing but
10
12
  a world's own HTTP endpoints. It holds no data path a `curl` could not call.
@@ -1,113 +1,199 @@
1
- /* The console's design system (punchlist 3.1–3.2) — the comparable is a plain modern developer
2
- console: a ground, cards with one hairline, one action colour, danger only for danger, the brand's
3
- type, monospace for addresses. Every colour and face is a role of the Volter brand (company
4
- decision 0018): the shell links the brand's tokens (`base/brand/tokens.css`, fetched at build) before
5
- this sheet, and the names below are this sheet's aliases for those roles; the pre-commit hook
6
- refuses a literal colour here. The roles carry both themes (light-dark()); `color-scheme` picks one.
7
- The portal's pages link this sheet; the site reads the same roles (apps/www/src/site.css). */
8
- :root {
9
- color-scheme: light dark;
10
- --ground: var(--volter-surface-page); --surface: var(--volter-surface-raised); --surface-2: var(--volter-surface-subtle);
11
- --line: var(--volter-border-default); --line-strong: var(--volter-border-strong);
12
- --ink: var(--volter-text-primary); --muted: var(--volter-text-muted); --faint: var(--volter-text-faint);
13
- --accent: var(--volter-action-default); --accent-ink: var(--volter-text-on-strong); --accent-soft: var(--volter-action-soft);
14
- --danger: var(--volter-status-danger-base); --danger-text: var(--volter-status-danger-text); --danger-soft: var(--volter-status-danger-soft);
15
- --warn: var(--volter-status-attention-text); --warn-soft: var(--volter-status-attention-soft); --ok: var(--volter-status-healthy-text);
16
- --mono: var(--volter-font-data);
17
- --sans: var(--volter-font-ui);
18
- --radius: 8px; --shadow: var(--volter-shadow-resting);
19
- }
20
- :root[data-theme="light"] { color-scheme: light; }
21
- :root[data-theme="dark"] { color-scheme: dark; }
1
+ /* THE DASHBOARD: a World's pages over the kit (kit/kit.css, served first). Only what a World shows lives here. */
2
+ /* the World (a place to look around): its head with the clock, its tabs, and one panel per tab */
3
+ .badge.rooted { color: var(--ok); border-color: currentColor; }
4
+ h2 .badge.read-only { vertical-align: middle; color: var(--warn); border-color: currentColor; }
22
5
 
23
- * { box-sizing: border-box; }
24
- html { background: var(--ground); }
25
- body { margin: 0; font: 14px/1.5 var(--sans); color: var(--ink); background: var(--ground); -webkit-font-smoothing: antialiased; }
26
- main { max-width: 1120px; margin: 0 auto; padding: 20px 24px 72px; }
27
- /* a link is the action colour, which is the text colour in the brand: its underline, in the strong
28
- rule, is what tells it from text (the brand's own pages mark links the same way) */
29
- a { color: var(--accent); text-decoration: underline; text-decoration-color: var(--line-strong); text-underline-offset: 3px; }
30
- a:hover { text-decoration-color: currentColor; }
31
- header a { text-decoration: none; }
32
- header a:hover { text-decoration: underline; }
33
- code { font: 12.5px/1.5 var(--mono); background: var(--surface-2); border: 1px solid var(--line); padding: 1px 6px; border-radius: 5px; color: var(--ink); }
34
- pre { margin: 0; font: 12px/1.45 var(--mono); white-space: pre-wrap; max-width: 640px; background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--radius); padding: 10px 12px; }
35
- h1, h2, h3, h4, h5 { margin: 0; font-weight: 600; letter-spacing: -0.005em; text-wrap: balance; }
36
- h1 { font-size: 17px; }
37
- h2 { font-size: 18px; margin: 28px 0 10px; }
38
- h3 { font-size: 15px; margin: 22px 0 8px; }
39
- h4 { font-size: 13px; margin: 18px 0 6px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.06em; font-weight: 600; }
40
- h5 { font-size: 13px; margin: 10px 0 4px; color: var(--danger-text); }
41
- p { margin: 6px 0; }
42
- ul, ol { margin: 6px 0; padding-left: 20px; }
43
- li { margin: 3px 0; }
6
+ /* the clock: a test clock's simulation banner, in the world's head */
7
+ .clock { flex: 1 1 360px; border: 1px solid var(--line); border-radius: var(--radius); padding: 8px 12px; background: var(--surface-2); }
8
+ .clock.frozen { border-color: color-mix(in srgb, var(--warn) 55%, var(--line)); background: var(--warn-soft); }
9
+ .clock.frozen .badge { color: var(--warn); border-color: currentColor; }
10
+ .clock-now { margin: 0; }
11
+ .clock-controls { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 6px; }
12
+ .clock-controls > p { flex-basis: 100%; margin: 0; }
13
+ .advance { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
14
+ .advance button { padding: 4px 9px; }
15
+ .advance form.inline { margin: 0; align-items: center; }
16
+ .advance input { padding: 4px 8px; font-size: 13px; }
17
+ .as-of { flex: 0 0 auto; }
44
18
 
45
- /* the top bar */
46
- header { display: flex; align-items: center; gap: 18px; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow); padding: 10px 16px; margin-bottom: 22px; }
47
- header h1 a { color: var(--ink); }
48
- header nav a { color: var(--muted); }
49
- header .mode { margin-left: auto; color: var(--muted); font-size: 12.5px; }
50
- header > a { color: var(--muted); font-size: 13px; }
51
- header button { padding: 5px 12px; }
19
+ /* a snapshot: the persistent "you are looking at the past" banner */
20
+ .snapshot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 14px; margin: -4px 0 14px; padding: 9px 12px; border: 1px solid color-mix(in srgb, var(--warn) 55%, var(--line)); background: var(--warn-soft); border-radius: var(--radius); color: var(--ink); }
52
21
 
53
- /* cards: every section that holds a thing */
54
- section, .billing, .members, .onboarding, .org-settings { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow); padding: 16px 18px; margin: 14px 0; }
55
- section > h2:first-child, section > h3:first-child { margin-top: 0; }
56
- .billing, .members { margin: 10px 0 0; padding: 14px 16px; background: var(--surface-2); }
57
- .billing p:first-child { margin-top: 0; }
58
- .usage { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 6px 16px; padding: 0; list-style: none; margin: 8px 0; }
59
- .usage li { margin: 0; color: var(--muted); }
60
- .plan-preview { margin: 10px 0; padding: 10px 12px; border: 1px dashed var(--line-strong); border-radius: var(--radius); }
61
- .plan-preview p { margin: 0 0 4px; }
62
- .onboarding { border-color: var(--accent); background: var(--accent-soft); }
63
- .onboarding ol { margin: 8px 0 12px; }
64
- .onboarding li[role="checkbox"] { list-style: none; margin-left: -20px; }
65
- .onboarding li[aria-checked="true"] { color: var(--muted); }
66
- details.org-settings { padding: 10px 16px; }
67
- details.org-settings summary { cursor: pointer; color: var(--muted); font-weight: 600; }
68
- details.org-settings[open] summary { margin-bottom: 8px; }
69
- .danger { margin-top: 14px; padding: 12px 14px; border: 1px solid color-mix(in srgb, var(--danger) 45%, var(--line)); background: var(--danger-soft); border-radius: var(--radius); }
70
- .danger button { border-color: var(--danger); color: var(--danger-text); }
71
- .danger button:hover:not(:disabled) { background: var(--danger); color: var(--volter-text-on-strong); }
72
- .admin { margin-top: 24px; padding-top: 12px; border-top: 1px dashed var(--line); }
22
+ .panel { padding-top: 6px; }
23
+ .empty { border: 1px dashed var(--line-strong); border-radius: var(--radius); padding: 14px 16px; margin: 10px 0; }
73
24
 
74
- /* tables */
75
- table { border-collapse: collapse; width: 100%; margin: 6px 0 4px; font-variant-numeric: tabular-nums; }
76
- th, td { text-align: left; vertical-align: top; padding: 9px 10px; border-bottom: 1px solid var(--line); }
77
- th { color: var(--muted); font-weight: 600; font-size: 12px; text-transform: uppercase; letter-spacing: 0.05em; }
78
- tr:last-child td { border-bottom: 0; }
79
- td code { font-size: 12px; }
25
+ /* overview: a card per twin */
26
+ .map { list-style: none; padding: 0; margin: 8px 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 12px; }
27
+ .map .card { margin: 0; border: 1px solid var(--line); border-radius: var(--radius); padding: 12px 14px; background: var(--surface-2); display: grid; gap: 4px; align-content: start; }
28
+ .card-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
29
+ .map h4.vendor { margin: 0; font-size: 15px; text-transform: none; letter-spacing: 0; color: var(--ink); }
30
+ .resources { list-style: none; padding: 0; margin: 4px 0; display: grid; gap: 2px; }
31
+ .resources li { display: flex; justify-content: space-between; margin: 0; font-variant-numeric: tabular-nums; }
32
+ .card-actions { display: flex; align-items: center; gap: 12px; margin: 6px 0 0; }
80
33
 
81
- /* usage by day (layer 6): a bar per day of the period */
82
- .bars { list-style: none; padding: 0; margin: 6px 0; display: grid; gap: 4px; max-width: 520px; }
83
- .bars li { display: grid; grid-template-columns: 44px 1fr auto; align-items: center; gap: 8px; font-size: 12.5px; }
84
- .bars .bar { display: block; height: 10px; background: var(--volter-data-base); border-radius: 3px; opacity: 0.8; }
34
+ /* timeline: an activity feed, by day, same-instant entries together */
35
+ .chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 0; }
36
+ .chips button { border-radius: 999px; padding: 3px 12px; }
37
+ .chips button[aria-pressed="true"] { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
38
+ .pill-slot { position: sticky; top: 8px; z-index: 2; display: flex; justify-content: center; height: 0; overflow: visible; }
39
+ .pill { border-radius: 999px; background: var(--accent); border-color: var(--accent); color: var(--accent-ink); box-shadow: var(--shadow); padding: 5px 14px; }
40
+ .pill:hover:not(:disabled) { color: var(--accent-ink); filter: brightness(1.06); }
41
+ .feed { margin-top: 8px; }
42
+ .day-head { position: sticky; top: 0; z-index: 1; margin: 14px 0 0; padding: 6px 0; background: var(--surface); border-bottom: 1px solid var(--line); font-size: 13px; color: var(--muted); }
43
+ .instants { list-style: none; padding: 0; margin: 0; }
44
+ .instant { display: grid; grid-template-columns: minmax(96px, 150px) 1fr; gap: 10px; margin: 0; padding: 7px 0; border-bottom: 1px solid var(--line); }
45
+ .instant-time { color: var(--muted); font-size: 12.5px; font-variant-numeric: tabular-nums; }
46
+ .entries { list-style: none; padding: 0; margin: 0; display: grid; gap: 4px; }
47
+ .entry { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; margin: 0; }
48
+ .twin-chip { font: 600 12px/1.6 var(--mono); padding: 0 7px; border-radius: 5px; background: var(--accent-soft); color: var(--ink); }
49
+ .entry .op { font-weight: 600; }
50
+ .entry .standing { color: var(--muted); font-size: 12.5px; }
51
+ .feed > button { margin-top: 12px; }
52
+ @media (max-width: 720px) { .instant { grid-template-columns: 1fr; gap: 2px; } }
85
53
 
86
- /* controls */
87
- button { font: inherit; font-size: 13px; padding: 6px 12px; border: 1px solid var(--line-strong); border-radius: 6px; background: var(--surface); color: var(--ink); cursor: pointer; }
88
- button:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
89
- button:disabled { opacity: 0.45; cursor: default; }
90
- button[type="submit"] { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
91
- button[type="submit"]:hover:not(:disabled) { color: var(--accent-ink); filter: brightness(1.06); }
92
- button[role="tab"] { border-color: transparent; background: transparent; color: var(--muted); }
93
- button[role="tab"][aria-selected="true"] { border-color: var(--line-strong); background: var(--surface); color: var(--ink); }
94
- button:focus-visible, input:focus-visible, select:focus-visible, a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
95
- form { display: grid; gap: 10px; max-width: 560px; margin-top: 8px; }
96
- form button[type="submit"] { justify-self: start; }
97
- label { display: grid; gap: 4px; color: var(--muted); font-size: 12.5px; }
98
- label:has(input[type="checkbox"]) { display: flex; align-items: center; gap: 8px; color: var(--ink); font-size: 13px; }
99
- input, select { font: inherit; font-size: 14px; padding: 7px 10px; border: 1px solid var(--line-strong); border-radius: 6px; background: var(--surface); color: var(--ink); }
100
- input::placeholder { color: var(--faint); }
101
- select { padding-right: 28px; }
102
- [role="alert"] { color: var(--danger-text); background: var(--danger-soft); border: 1px solid color-mix(in srgb, var(--danger) 35%, var(--line)); border-radius: 6px; padding: 8px 10px; }
103
- [role="status"] { color: var(--muted); }
104
- .mode { color: var(--muted); font-size: 12.5px; }
54
+ /* trace: a waterfall with a lane per twin */
55
+ .waterfall { display: grid; border: 1px solid var(--line); border-radius: var(--radius); overflow-x: auto; margin: 8px 0; }
56
+ .wf-row { display: contents; }
57
+ .wf-row > span { padding: 7px 10px; border-bottom: 1px solid var(--line); min-width: 0; }
58
+ .wf-head > span { color: var(--muted); font-weight: 600; font-size: 12px; text-transform: uppercase; letter-spacing: 0.05em; background: var(--surface-2); }
59
+ .wf-time { font-size: 12.5px; font-variant-numeric: tabular-nums; }
60
+ .wf-cell { border-left: 1px dashed var(--line); }
61
+ .wf-cell.on details { border-left: 3px solid var(--volter-data-base); padding-left: 8px; }
62
+ .wf-cell summary { cursor: pointer; }
63
+ .fields { display: grid; grid-template-columns: max-content 1fr; gap: 2px 12px; margin: 6px 0; }
64
+ .fields dt { color: var(--muted); font-size: 12.5px; }
65
+ .fields dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }
105
66
 
106
- /* the portal's own pages share this sheet */
107
- body.portal { display: grid; place-items: center; min-height: 100vh; padding: 24px; }
108
- body.portal .card { background: var(--surface); border: 1px solid var(--line); border-radius: 12px; box-shadow: var(--shadow); padding: 28px 30px; width: min(440px, 100%); text-align: center; }
109
- body.portal .card h1 { font-size: 22px; margin-bottom: 4px; }
110
- body.portal .card p { color: var(--muted); margin: 0 0 18px; }
111
- body.account main { max-width: 900px; }
112
- body.account #profile { margin-top: 12px; }
113
- @media (max-width: 720px) { main { padding: 14px 14px 60px; } header { flex-wrap: wrap; } header .mode { margin-left: 0; } }
67
+
68
+ /* changes: a compare view, by twin */
69
+ .compare { margin: 12px 0; border: 1px solid var(--line); border-radius: var(--radius); }
70
+ .compare h3 { margin: 0; padding: 8px 12px; background: var(--surface-2); border-bottom: 1px solid var(--line); }
71
+ .compare ul { list-style: none; padding: 0; margin: 0; }
72
+ .compare li { margin: 0; padding: 7px 12px; border-bottom: 1px solid var(--line); }
73
+ .compare li:last-child { border-bottom: 0; }
74
+ .compare summary { cursor: pointer; }
75
+ .compare .op { font-weight: 600; margin: 0 6px; }
76
+
77
+ /* A World is a repository page: a sentence says what it is; its vendors' own screens are the live preview. */
78
+ .lede { margin: 2px 0 6px; color: var(--ink); max-width: 62ch; }
79
+ .connect summary, .clock-more summary { cursor: pointer; color: var(--muted); font-size: 12.5px; }
80
+ .connect[open] summary, .clock-more[open] summary { color: var(--ink); }
81
+ .connect p { margin: 6px 0 0; }
82
+ .clock-more { margin-top: 4px; }
83
+ .clock-more > p { margin: 6px 0; }
84
+ .vendors { display: grid; grid-template-columns: 220px 1fr; gap: 14px; margin-top: 12px; align-items: start; }
85
+ .vendor-list ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; }
86
+ .vendor-list a { display: grid; gap: 1px; padding: 8px 10px; border-radius: var(--radius); border: 1px solid transparent; color: var(--ink); text-decoration: none; }
87
+ .vendor-list a:hover { background: var(--surface-2); }
88
+ .vendor-list a[aria-current="page"] { background: var(--surface-2); border-color: var(--line); }
89
+ .vendor-list > button { margin-top: 10px; }
90
+ .stage { border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; background: var(--surface-2); }
91
+ .stage-bar { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px; padding: 8px 12px; border-bottom: 1px solid var(--line); background: var(--surface); }
92
+ .stage-bar a { margin-left: auto; }
93
+ .stage-note { margin: 0; padding: 6px 12px; border-bottom: 1px solid var(--line); }
94
+ .stage iframe { display: block; width: 100%; height: max(560px, calc(100vh - 300px)); border: 0; background: var(--ground); }
95
+ .stage > p { padding: 12px; margin: 0; }
96
+ .entry .label { color: var(--ink); }
97
+ .entry.run details > summary { cursor: pointer; list-style: none; display: flex; flex-wrap: wrap; gap: 4px 10px; align-items: baseline; }
98
+ .entry.run details > ul { margin: 6px 0 0 14px; padding: 0; list-style: none; display: grid; gap: 4px; }
99
+ @media (max-width: 760px) { .vendors { grid-template-columns: 1fr; } }
100
+
101
+ .stats { list-style: none; margin: 0 0 18px; padding: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px; }
102
+ .stats li { margin: 0; padding: 12px 14px; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); display: grid; gap: 2px; }
103
+ .stat-label { color: var(--muted); font-size: 12px; }
104
+ .stat-value { font-size: 24px; font-weight: 600; letter-spacing: -0.01em; font-variant-numeric: tabular-nums; }
105
+ .overview-grid { display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); gap: 16px; align-items: start; }
106
+ .mini-feed { list-style: none; margin: 0; padding: 0; }
107
+ .mini-feed li { display: flex; align-items: center; gap: 10px; margin: 0; padding: 8px 14px; border-top: 1px solid var(--line); }
108
+ .mini-feed li:first-child { border-top: 0; }
109
+ .mini-what { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
110
+ .empty-block { display: grid; gap: 6px; padding: 18px 14px; }
111
+ .empty-block pre { max-width: none; }
112
+ .content .vendors { display: block; margin: 0; }
113
+ .content .stage-bar { align-items: center; }
114
+ .stage-actions { margin-left: auto; display: flex; gap: 8px; align-items: center; }
115
+ .content .stage iframe { height: calc(100vh - 175px); min-height: 520px; }
116
+ .content .instant { display: grid; grid-template-columns: 92px minmax(0, 1fr); gap: 12px; }
117
+ .content .entry { display: grid; grid-template-columns: 104px minmax(120px, 190px) minmax(0, 1fr) auto auto; align-items: baseline; }
118
+ .content .entry.run { display: block; }
119
+ .content .entry .label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
120
+ .content .twin-chip { display: inline-flex; align-items: center; gap: 7px; background: none; padding: 0; font: 500 13px/1.4 var(--sans); }
121
+ .content .twin-chip .mark { width: 20px; height: 20px; }
122
+ /* the canvas (React Flow): frames on a dotted surface, as a canvas app is; React Flow's variables take the brand's roles */
123
+ .canvas { position: relative; height: calc(100vh - 140px); min-height: 480px; border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden;
124
+ --xy-background-color: var(--surface-2); --xy-background-pattern-color: var(--line-strong); --xy-minimap-background-color: var(--surface);
125
+ --xy-minimap-mask-background-color: color-mix(in srgb, var(--surface-2) 72%, transparent); --xy-minimap-node-background-color: var(--line-strong); --xy-controls-button-background-color: var(--surface);
126
+ --xy-controls-button-background-color-hover: var(--surface-2); --xy-controls-button-color: var(--ink); --xy-controls-button-border-color: var(--line); --xy-node-border-radius: 12px; }
127
+ .canvas .react-flow__node-screen { padding: 0; border: 0; background: none; }
128
+ .frame { display: grid; grid-template-rows: 48px 1fr; background: var(--surface); border: 1px solid var(--line-strong); border-radius: 12px; box-shadow: var(--shadow); overflow: hidden; }
129
+ .frame.on { outline: 4px solid var(--accent); outline-offset: 3px; }
130
+ .frame-bar { display: flex; align-items: center; gap: 12px; padding: 0 16px; border-bottom: 1px solid var(--line); background: var(--surface-2); cursor: grab; font-size: 17px; }
131
+ .frame-bar .mark { width: 26px; height: 26px; }
132
+ .frame-bar .mark.logo svg { width: 16px; height: 16px; }
133
+ .frame-url { flex: 1; min-width: 0; margin: 0 8px; padding: 5px 12px; border-radius: 999px; background: var(--surface); border: 1px solid var(--line); color: var(--muted); font: 14px var(--mono); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
134
+ .frame-body { position: relative; }
135
+ .frame-body iframe { display: block; width: 100%; height: 100%; border: 0; background: var(--ground); }
136
+ .frame-label { display: flex; align-items: center; gap: 7px; padding: 3px 8px; background: var(--surface); border: 1px solid var(--line); border-radius: 6px; box-shadow: var(--shadow); font-weight: 600; font-size: 12.5px; }
137
+ .canvas-hint { position: absolute; left: 50%; transform: translateX(-50%); top: 10px; font-size: 12px; margin: 0; padding: 4px 10px; background: var(--surface); border: 1px solid var(--line); border-radius: 999px; z-index: 5; pointer-events: none; }
138
+ /* THE WORLD, laid out as Neon's console (docs/concepts/the-model.md: Neon for every SaaS): the top bar's breadcrumb
139
+ and Connect; a sidebar of the World's pages, the branch picker, the branch's pages and its vendors as services */
140
+ /* ALL SCREENS: the canvas is the whole window, with its panels floating over it */
141
+ .canvas.full { position: fixed; inset: 0; z-index: 30; height: auto; min-height: 0; border: 0; border-radius: 0; }
142
+ .float { background: var(--surface); border: 1px solid var(--line); border-radius: 10px; box-shadow: var(--shadow); }
143
+ .float.layers { width: 232px; padding: 6px; max-height: calc(100vh - 32px); overflow-y: auto; }
144
+ .float-head { display: flex; align-items: center; gap: 8px; }
145
+ .float-title { display: grid; line-height: 1.2; flex: 1; min-width: 0; }
146
+ .float button.back, .float button.ghost { border: 0; background: transparent; padding: 4px 8px; }
147
+ .float button.back:hover, .float button.ghost:hover { background: var(--surface-2); }
148
+ .layer-list { list-style: none; margin: 6px 0 0; padding: 6px 0 0; border-top: 1px solid var(--line); display: grid; gap: 1px; }
149
+ .layer-list li { margin: 0; }
150
+ .layer-list button { width: 100%; display: flex; align-items: center; gap: 8px; border: 0; background: transparent; padding: 5px 8px; text-align: left; color: var(--ink); }
151
+ .layer-list button:hover { background: var(--surface-2); color: var(--ink); }
152
+ .layer-list button.on { background: var(--accent-soft); }
153
+ .float.hint { padding: 4px 12px; border-radius: 999px; font-size: 12px; pointer-events: none; }
154
+
155
+ /* THE DASHBOARD, as Vercel's and Neon's open a project: the live screens first, connect and branches beside, activity under */
156
+ .dash { display: grid; grid-template-columns: minmax(0, 2fr) minmax(260px, 1fr); gap: 16px; align-items: start; }
157
+ .dash-screens { grid-column: 1; }
158
+ .dash-side { grid-column: 2; display: grid; gap: 16px; }
159
+ .dash-activity { grid-column: 1 / -1; }
160
+ .dash .block-head { gap: 12px; }
161
+ .dash .block-head h3 { display: flex; align-items: center; gap: 8px; margin-right: auto; }
162
+ .badge.live { color: var(--ok); border-color: currentColor; }
163
+ .pad { padding: 10px 14px; margin: 0; }
164
+ .dash .pad pre { max-width: none; margin: 8px 0; }
165
+ .thumbs { list-style: none; margin: 0; padding: 14px; display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 14px; }
166
+ .thumbs li { margin: 0; }
167
+ .thumbs a { display: grid; gap: 6px; color: var(--ink); text-decoration: none; }
168
+ .thumb { position: relative; display: block; aspect-ratio: 1280 / 820; overflow: hidden; border: 1px solid var(--line); border-radius: 8px; background: var(--surface-2); }
169
+ .thumbs a:hover .thumb { border-color: var(--accent); }
170
+ .thumb iframe { position: absolute; top: 0; left: 0; border: 0; transform-origin: 0 0; pointer-events: none; background: var(--ground); }
171
+ .thumb-none { position: absolute; inset: 0; display: grid; place-items: center; color: var(--faint); font-size: 12px; }
172
+ .thumb-foot { display: flex; align-items: center; gap: 8px; min-width: 0; font-size: 13px; }
173
+ .thumb-foot .mode { margin-left: auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
174
+ @media (max-width: 980px) { .dash { grid-template-columns: 1fr; } .dash-side, .dash-screens { grid-column: 1; } }
175
+ .dash section.block { padding: 0; margin: 0; box-shadow: none; }
176
+ .dash .pad code { word-break: break-all; }
177
+ .dash .branch-glyph { display: inline-grid; place-items: center; width: 20px; color: var(--muted); }
178
+ section.pitch { background: none; border: 0; box-shadow: none; padding: 0; margin: 0; }
179
+ .thumb-status { position: absolute; top: 8px; right: 8px; background: var(--surface); }
180
+ /* Neon's sidebar opens on Connect; its branch Overview is a services table and a monitoring chart */
181
+ .connect-side { display: block; margin: 0 0 10px; }
182
+ .connect-side > .connect-button { display: block; width: 100%; text-align: center; border-color: var(--accent); color: var(--accent); font-weight: 600; }
183
+ .connect-side .popover { left: 0; right: auto; width: min(420px, 80vw); }
184
+ .connect-side .popover .agent-prompt-button { width: 100%; margin-top: 8px; }
185
+ .chart-block { margin-top: 16px; }
186
+ .chart { width: 100%; height: auto; display: block; }
187
+ .chart .grid { stroke: var(--line); stroke-dasharray: 3 4; }
188
+ .chart .axis { stroke: var(--line-strong); }
189
+ .chart .tick { font: 8px var(--mono); fill: var(--muted); text-anchor: middle; }
190
+ .legend { list-style: none; display: flex; flex-wrap: wrap; gap: 6px 16px; margin: 8px 0 0; padding: 0; font-size: 12.5px; }
191
+ .legend li { display: flex; align-items: center; gap: 6px; margin: 0; }
192
+ .legend .swatch { width: 10px; height: 10px; border-radius: 2px; display: inline-block; }
193
+ /* the World's keys: what they are beside the way to make one */
194
+ .keys-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 8px; }
195
+ .keys-head h3 { margin-top: 0; }
196
+ .keys-head p { margin: 2px 0 0; max-width: 620px; }
197
+ /* a phone: the top bar keeps the menu, the mark, where you are, the way back as an arrow and Sign out */
198
+ @media (max-width: 720px) { main.app > header .mode, main.app > header .back-link .back-text { display: none; } main.app > header .back-link { flex: none; } }
199
+ @media (max-width: 720px) { .head-actions .clock { flex-wrap: wrap; max-width: 100%; } }