create-pmos 0.196.0 → 0.198.0
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/package.json +1 -1
- package/payload/KIT-VERSION +1 -1
- package/payload/planning/evals/eval-calibration.md +1 -1
- package/payload/planning/okrs/health-budgets.md +1 -1
- package/payload/state/discoveries.md +1 -1
- package/workspace/c3-ib-items-test.js +16 -8
- package/workspace/c3-ib-more-test.js +3 -2
- package/workspace/c3-ib-triage-backlog-test.js +1 -1
- package/workspace/c3-quiet-test.js +4 -3
- package/workspace/c3-report-design-real-test.js +225 -0
- package/workspace/c3-report-design-test.js +403 -0
- package/workspace/c3-report-setup-test.js +3 -2
- package/workspace/c3-work-test.js +1 -1
- package/workspace/guide/index.md +1 -0
- package/workspace/guide/initiative-boards.md +9 -5
- package/workspace/guide/report-design.md +104 -0
- package/workspace/guide/report-slides.md +3 -1
- package/workspace/guide/reports-set-up.md +2 -1
- package/workspace/lib/headless.js +24 -6
- package/workspace/lib/report-design.js +741 -0
- package/workspace/lib/report-draft.js +8 -3
- package/workspace/lib/report-setups.js +1 -1
- package/workspace/lib/route-modules.js +1 -0
- package/workspace/lib/routes-doc-sheet.js +8 -1
- package/workspace/lib/routes-report-design.js +481 -0
- package/workspace/lib/routes-reports.js +2 -1
- package/workspace/package-lock.json +2 -2
- package/workspace/package.json +1 -1
- package/workspace/public/pm/c3-demo-rd.js +426 -0
- package/workspace/public/pm/c3-demo-rep2.js +2 -0
- package/workspace/public/pm/c3-demo-rs.js +5 -1
- package/workspace/public/pm/c3-design-studio.js +308 -0
- package/workspace/public/pm/c3-doc-formats.js +3 -2
- package/workspace/public/pm/c3-doc-sheet.js +30 -5
- package/workspace/public/pm/c3-ib-items.js +26 -17
- package/workspace/public/pm/c3-ib-releases.js +4 -7
- package/workspace/public/pm/c3-ib-sprints.js +5 -8
- package/workspace/public/pm/c3-ib-triage.js +4 -9
- package/workspace/public/pm/c3-ini-life.css +2 -0
- package/workspace/public/pm/c3-initiatives.js +2 -1
- package/workspace/public/pm/c3-quiet.css +1 -1
- package/workspace/public/pm/c3-quiet.js +4 -5
- package/workspace/public/pm/c3-report-deck.css +139 -0
- package/workspace/public/pm/c3-report-deck.js +558 -0
- package/workspace/public/pm/c3-report-frame.css +20 -0
- package/workspace/public/pm/c3-report-setup.js +18 -6
- package/workspace/server.js +17 -5
- package/workspace/skills/report-design.skill +61 -0
- package/workspace/test-lists/report-design-backend.json +5 -0
- package/workspace/test-lists/report-design-studio-ui.json +5 -0
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
* registerBoardTab('sprints', (host, ctx) => ...)
|
|
3
3
|
* Reads GET /api/boards/sprints { source: jira|none, readAt, sprints: [{ name, state: active|future|closed, issues: [{ key, summary, status,
|
|
4
4
|
* category: todo|doing|done, initiative }], counts }] }. READ-ONLY: the sprints mirror Jira, so there is no create, edit or move control.
|
|
5
|
-
* Left: the
|
|
6
|
-
* future and closed sprints in place. Right: the active sprint's
|
|
5
|
+
* Left: the active sprint's items, its header chip saying Jira, read-only and the read time (c3-board-declutter: no banner), as rows (a linked initiative opens its page), then the
|
|
6
|
+
* future and closed sprints in place. Right: the active sprint's bars, and its burndown from GET /api/stage-tools/burndown (built by
|
|
7
7
|
* the stage-records change; when that route is not on this server yet, the card says so quietly). source 'none' says there is no tracker. */
|
|
8
8
|
import { el } from './dom.js';
|
|
9
9
|
import { registerBoardTab } from './c3-initiatives.js';
|
|
10
|
-
import { icon,
|
|
10
|
+
import { icon, lk, chip, tag, st, note, sect, card, list, empty, nrow, cols, hbs, hbr, jiraLabel, day, put } from './c3-ini-ui.js';
|
|
11
11
|
import { loadItems } from './c3-ini-work.js';
|
|
12
12
|
import { recordCards } from './c3-ini-records.js';
|
|
13
13
|
|
|
@@ -32,8 +32,7 @@ registerBoardTab('sprints', async (host, ctx) => {
|
|
|
32
32
|
right: [el('span', { class: 'chip2', title: 'Status lives in Jira' }, icon('lock', 'sm'))], attrs: { 'data-inb-issue': i.key } });
|
|
33
33
|
const t = readTime(r.readAt);
|
|
34
34
|
const left = [
|
|
35
|
-
el('
|
|
36
|
-
active ? sect({ ic: 'check', title: active.name + ' items', count: (active.issues || []).length, right: tag('read-only'), attrs: { 'data-inb-sprint': active.name, 'data-inb-state': 'active' } },
|
|
35
|
+
active ? sect({ ic: 'check', title: active.name + ' items', count: (active.issues || []).length, right: el('span', { class: 'chip2', 'data-inb': 'sprints-source', title: 'Mirrored from Jira ' + jiraLabel(b) + '. Change sprints in Jira.' }, icon('lock', 'sm'), 'Jira, read-only' + (t ? ' · read ' + t : '')), attrs: { 'data-inb-sprint': active.name, 'data-inb-state': 'active' } },
|
|
37
36
|
(active.issues || []).length ? list(active.issues.map(issueRow)) : empty('No items in this sprint yet.', { 'data-inb': 'sprint-no-issues' }))
|
|
38
37
|
: empty(sprints.length ? 'No sprint is active.' : 'Jira has no sprints for this board.', { 'data-inb': sprints.length ? 'sprints-no-active' : 'sprints-empty' }),
|
|
39
38
|
...others.map((s) => { const c = countsOf(s); return sect({ ic: s.state === 'closed' ? 'check' : 'clock', title: s.name, count: (s.issues || []).length, right: tag(s.state || 'sprint'), attrs: { 'data-inb-sprint': s.name, 'data-inb-state': s.state } },
|
|
@@ -42,13 +41,11 @@ registerBoardTab('sprints', async (host, ctx) => {
|
|
|
42
41
|
const right = [];
|
|
43
42
|
if (active) {
|
|
44
43
|
const c = countsOf(active); const tot = Math.max(1, c.todo + c.doing + c.done);
|
|
45
|
-
right.push(card({ ic: 'clock', title: active.name, attrs: { 'data-inb': 'sprint-counts' } },
|
|
46
|
-
hbs([hbr('Done', c.done, c.done / tot, 'ok'), hbr('In progress', c.doing, c.doing / tot, 'acc'), hbr('To do', c.todo, c.todo / tot, 'pm')])));
|
|
44
|
+
right.push(card({ ic: 'clock', title: active.name, attrs: { 'data-inb': 'sprint-counts' } }, hbs([hbr('Done', c.done, c.done / tot, 'ok'), hbr('In progress', c.doing, c.doing / tot, 'acc'), hbr('To do', c.todo, c.todo / tot, 'pm')])));
|
|
47
45
|
const ids = items.ok ? items.initiatives.map((i) => i.id) : [];
|
|
48
46
|
const pseudo = { ...ctx, row: { id: ids.join(','), title: '' } };
|
|
49
47
|
right.push(...await recordCards(pseudo, ['burndown']));
|
|
50
48
|
}
|
|
51
|
-
right.push(card({ ic: 'out', title: 'In Jira' }, note('Sprints, their dates and their items are Jira\'s. PMOS mirrors them after each sync.'), el('div', { class: 'chips2' }, pbtn('outline', 'Open the Board', 'cols', { onclick: () => ctx.openBoard(b.id, 'board') }))));
|
|
52
49
|
if (dead) return () => {};
|
|
53
50
|
put(host, cols(left, right));
|
|
54
51
|
return () => { dead = true; };
|
|
@@ -8,12 +8,12 @@
|
|
|
8
8
|
* opens it.
|
|
9
9
|
* Ask for more a sheet for the question to the asker (POST /api/boards/asks/more). The ask stays open, marked "asked for more".
|
|
10
10
|
* Decline a sheet that asks for the reason (POST /api/boards/asks/decline).
|
|
11
|
-
*
|
|
11
|
+
* The New asks header names the default workflow and its first stage (c3-board-declutter: no side card, the asks take the width).
|
|
12
12
|
* Contract fields relied on: an ask is { id, line, source?, at?, by?, needMore?, moreNote?, draft?: { title?, lane, confidence,
|
|
13
13
|
* anchor_suggestion, prior_rejections: [{ id, title, why }] }, initiative? (accepted), why? (declined) }. Nothing is invented. */
|
|
14
14
|
import { el } from './dom.js';
|
|
15
15
|
import { registerBoardTab } from './c3-initiatives.js';
|
|
16
|
-
import { icon, pbtn, lk, chip, tag, st, note, noteA, lbl, sect, card, list, empty, nrow,
|
|
16
|
+
import { icon, pbtn, lk, chip, tag, st, note, noteA, lbl, sect, card, list, empty, nrow, ago, put } from './c3-ini-ui.js';
|
|
17
17
|
import { TEMPLATES } from './c3-ini-work.js';
|
|
18
18
|
import { isScanAsk, scanAskParts } from './c3-scan.js';
|
|
19
19
|
|
|
@@ -34,12 +34,7 @@ registerBoardTab('triage', async (host, ctx) => {
|
|
|
34
34
|
const addBtn = pbtn('outline', 'Add', 'plus', { 'data-ibt': 'add', onclick: () => add() });
|
|
35
35
|
const msg = errLine({ 'data-ibt': 'error' });
|
|
36
36
|
const left = el('div', { class: 'ini-col' });
|
|
37
|
-
|
|
38
|
-
note('New asks land here from Slack, email, Jira Service Desk and meeting notes. Each gets a sharpness check and a prior-ask check. Accepting starts an initiative with this board\'s default workflow, ' + def.name + ', in ' + first.name + '. You can switch the initiative to another workflow afterwards.'),
|
|
39
|
-
chgl([el('li', null, icon('check', 'sm'), el('span', null, 'Accept: starts an initiative (' + def.name + ', ' + first.name + ')'), el('span')),
|
|
40
|
-
el('li', null, icon('reply', 'sm'), el('span', null, 'Ask for more: the asker is prompted for detail'), el('span')),
|
|
41
|
-
el('li', null, icon('x', 'sm'), el('span', null, 'Decline: the asker is told why'), el('span'))]));
|
|
42
|
-
put(host, cols(left, right));
|
|
37
|
+
put(host, left);
|
|
43
38
|
const setErr = (t) => { msg.textContent = t || ''; msg.hidden = !t; };
|
|
44
39
|
|
|
45
40
|
function draftNodes(a) {
|
|
@@ -74,7 +69,7 @@ registerBoardTab('triage', async (host, ctx) => {
|
|
|
74
69
|
function draw() {
|
|
75
70
|
put(left,
|
|
76
71
|
card({ ic: 'plus', title: 'Add an ask' }, el('div', { class: 'form', 'data-ibt': 'add-form' }, input, addBtn), msg),
|
|
77
|
-
sect({ ic: 'inbox', title: 'New asks', count: S.open.length }, S.open.length ? list(S.open.map((a) => row(a, 'open')), { 'data-ibt': 'asks', 'aria-label': 'Open asks' }) : empty('Nothing new to triage on this board.', { 'data-ibt': 'empty' })),
|
|
72
|
+
sect({ ic: 'inbox', title: 'New asks', count: S.open.length, right: el('span', { class: 'dim', 'data-ibt': 'intro', title: 'Accept starts an initiative on this board\'s default workflow. Ask for more prompts the asker. Decline tells them why.' }, 'Accept starts ' + def.name + ', in ' + first.name) }, S.open.length ? list(S.open.map((a) => row(a, 'open')), { 'data-ibt': 'asks', 'aria-label': 'Open asks' }) : empty('Nothing new to triage on this board.', { 'data-ibt': 'empty' })),
|
|
78
73
|
S.other.length ? sect({ ic: 'check', title: 'Decided', count: S.other.length, attrs: { 'data-ibt': 'closed' } }, list(S.other.map((x) => row(x, x.state)))) : null);
|
|
79
74
|
if (S.justAdded) {
|
|
80
75
|
const li = left.querySelector('[data-ibt-ask="' + CSS.escape(S.justAdded) + '"] .tt'); S.justAdded = '';
|
|
@@ -24,6 +24,8 @@
|
|
|
24
24
|
.c3 .ini-mpanel .il-f{display:grid;grid-template-columns:76px 1fr;align-items:center;gap:8px;padding:4px 8px;font-size:var(--fs-2);color:var(--muted-foreground)}
|
|
25
25
|
.c3 .ini-mpanel .il-f select{width:100%}
|
|
26
26
|
.c3 .ini-mpanel .il-fend{justify-content:flex-end;padding:6px 8px 2px}
|
|
27
|
+
.c3 .ini-mpanel .il-fnote{padding:4px 8px;font-size:var(--fs-2);max-width:280px}
|
|
28
|
+
.c3 .wk-fbar .il-chips{margin-left:auto}
|
|
27
29
|
.c3 .ini-mi .il-hint{color:var(--muted-foreground)}
|
|
28
30
|
.c3 .ini-mi[aria-checked="false"] .il-tick{visibility:hidden}
|
|
29
31
|
/* The board's Initiatives list shows every chip of a row, as the mockup draws it (the quiet pages keep two elsewhere). */
|
|
@@ -166,7 +166,8 @@ export function mountInitiatives(pane, opts) {
|
|
|
166
166
|
const openBoard = (id, tab, filter) => go({ view: 'board', board: id, tab: tab || 'summary', filter: filter || {} });
|
|
167
167
|
const refresh = () => { P.boards = null; P.ini = null; dropItems(); draw(); };
|
|
168
168
|
// The Briefing's Horizon scan card opens a board's Triage or settings (c3-scan.js goBoard). A page that is not built yet reads the address instead.
|
|
169
|
-
|
|
169
|
+
// A report deck's live initiative link sends { id } (c3-report-deck.js openInitiative): the initiative opens on the board in view, else the first board.
|
|
170
|
+
if (typeof window !== 'undefined') { if (window.__iniGo) window.removeEventListener('pmos:ini-go', window.__iniGo); window.__iniGo = (e) => { const d = (e && e.detail) || {}; if (!root.isConnected) return; if (d.id) { const b = d.board || (P.loc && P.loc.board) || (P.boards && P.boards[0] && P.boards[0].id); if (b) go({ view: 'ini', board: b, id: d.id, tab: d.tab || 'overview' }); return; } if (d.loc != null) go(parseLoc(d.loc)); else if (d.board) openBoard(d.board, d.tab || 'summary'); }; window.addEventListener('pmos:ini-go', window.__iniGo); }
|
|
170
171
|
const redraw = () => draw();
|
|
171
172
|
|
|
172
173
|
async function loadBoards() {
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
.c3 [data-ini-view="board"] > .calbody > .lh{display:none !important} /* board name repeats the breadcrumb */
|
|
44
44
|
.c3 [data-ini="board-tabs"] .bdg{display:none !important}
|
|
45
45
|
.c3 [data-ini="board-tabs"] .qt-more-tab{display:none}
|
|
46
|
-
.c3 [data-ini="board-tabs"]
|
|
46
|
+
.c3 [data-ini="board-tabs"] .qt-more-tab[aria-pressed="true"]{display:inline-flex}
|
|
47
47
|
.c3 .qt-status{color:var(--muted-foreground);font-size:var(--fs-2);margin-left:8px}
|
|
48
48
|
.c3 .qt-status.warn{color:var(--warning)}
|
|
49
49
|
.c3 [data-ini="glance"] .chip2.mono{display:none !important}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* mountQuiet(root) links c3-quiet.css once and keeps the page in its quiet layout as the views draw:
|
|
5
5
|
* - the freshness line folds into one dot next to the date ("4 sources not read"); pressing the dot shows the full line;
|
|
6
6
|
* - a board: its status joins the breadcrumb, the board tabs join that row, Backlog, Releases, Docs and Sprints go
|
|
7
|
-
* behind More, Dashboard and the all-zero Work items card are not shown;
|
|
7
|
+
* behind More (a menu; the open one shows beside the five, c3-board-declutter), Dashboard and the all-zero Work items card are not shown;
|
|
8
8
|
* - the portfolio: the headline joins the breadcrumb, an empty triage card is not shown, the timeline folds;
|
|
9
9
|
* - empty chips ("No owner", "0 epics", ...) are not drawn;
|
|
10
10
|
* - Calendar: the layer chips sit behind one Layers button, the Detail card shows once a meeting is picked;
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* It runs again, debounced, whenever the views redraw (one MutationObserver on the root). */
|
|
15
15
|
|
|
16
16
|
import { button } from './primitives.js';
|
|
17
|
+
import { openMenu } from './c3-ini-ui.js';
|
|
17
18
|
|
|
18
19
|
const EMPTY_CHIP = /^(No owner|No dates yet|0 epics|0%|No release planned|Build and deliver)$/;
|
|
19
20
|
const MORE_TABS = /^(backlog|releases|docs|sprints)$/;
|
|
@@ -76,12 +77,10 @@ function board(v) {
|
|
|
76
77
|
if (tabs) {
|
|
77
78
|
for (const t of tabs.querySelectorAll('[data-ini-tab]')) if (MORE_TABS.test(t.dataset.iniTab)) t.classList.add('qt-more-tab');
|
|
78
79
|
if (!tabs.querySelector('.qt-more')) {
|
|
79
|
-
const m = button({ label: 'More', variant: 'ghost', size: 'sm', attrs: { class: 'qt-more', 'aria-expanded': 'false' },
|
|
80
|
-
onClick: () => {
|
|
80
|
+
const m = button({ label: 'More', variant: 'ghost', size: 'sm', attrs: { class: 'qt-more', 'aria-haspopup': 'menu', 'aria-expanded': 'false' },
|
|
81
|
+
onClick: () => openMenu(m, { label: 'More board views', items: [...tabs.querySelectorAll('.qt-more-tab')].map((t) => ({ kids: [...t.childNodes].map((n) => n.cloneNode(true)), checked: t.getAttribute('aria-pressed') === 'true', attrs: { 'data-qt-more': t.dataset.iniTab }, onPick: () => t.click() })) }) });
|
|
81
82
|
tabs.appendChild(m);
|
|
82
83
|
}
|
|
83
|
-
// a tab behind More that is the open one keeps the row shown, so the pressed tab never disappears
|
|
84
|
-
if (tabs.querySelector('.qt-more-tab[aria-pressed="true"]')) tabs.classList.add('qt-show');
|
|
85
84
|
const row = crumbs && crumbs.parentElement;
|
|
86
85
|
if (row && tabs.parentElement !== row) { row.classList.add('qt-ctx'); row.insertBefore(tabs, row.querySelector(':scope > .chips2:not([data-ini="crumbs"])')); }
|
|
87
86
|
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/* pm/c3-report-deck.css — the deck view, Present, the notes, the Design studio and the design brief (initiative report-design-studio). The mockup's
|
|
2
|
+
42-reportdeck.css under real class names: .mk-dk is .rd-dk, .mk-dks is .rd-dks, the mockup's .mk-btn/.mk-log/.mk-sync/.mk-stale are the document
|
|
3
|
+
sheet's .ds-btn/.ds-log/.ds-sync/.ds-stale. The slide is a render in a sandboxed frame (.rd-card > iframe), scaled with --rp-scale.
|
|
4
|
+
Tokens only. Corners: 6px on a control, 8px on a container, 50% only on a dot. c3-report-deck.js links it once. */
|
|
5
|
+
.c3 .sheet.rd-wide { width: min(1320px, calc(100% - 24px)); max-width: none; }
|
|
6
|
+
.c3 .rd-dk { display: grid; gap: var(--sp-3); min-width: 0; }
|
|
7
|
+
.c3 .rd-dk > * { min-width: 0; }
|
|
8
|
+
.c3 .rd-wrap { flex-wrap: wrap; min-width: 0; }
|
|
9
|
+
.c3 .rd-small { font-size: var(--fs-2); }
|
|
10
|
+
.c3 .rd-m0 { margin: 0; }
|
|
11
|
+
.c3 .rd-fg { color: var(--foreground); }
|
|
12
|
+
.c3 .rd-hide { display: none; }
|
|
13
|
+
.c3 .rd-stack { display: grid; gap: 6px; min-width: 0; }
|
|
14
|
+
.c3 .rd-between { justify-content: space-between; }
|
|
15
|
+
.c3 .rd-warn { color: var(--warning); }
|
|
16
|
+
.c3 .rd-on { color: var(--acc); border-color: var(--acc); }
|
|
17
|
+
.c3 .rd-dk-bar { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; justify-content: space-between; }
|
|
18
|
+
.c3 .rd-dk-bar .seg { max-width: 100%; overflow-x: auto; }
|
|
19
|
+
.c3 .rd-dk-bar .seg button { white-space: nowrap; }
|
|
20
|
+
.c3 .rd-dk-caps { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
|
|
21
|
+
.c3 .rd-dk-caps .dim { font-size: var(--fs-1); margin-right: 4px; }
|
|
22
|
+
.c3 .rd-dk-diff p { margin: 0; }
|
|
23
|
+
|
|
24
|
+
/* a slide: the render in a sandboxed frame, 1280 x 720, scaled to the card's width */
|
|
25
|
+
.c3 .rd-card { position: relative; width: 100%; aspect-ratio: 16 / 9; overflow: hidden; background: var(--slide-bg); box-shadow: 0 0 0 1px var(--border); border-radius: 6px; }
|
|
26
|
+
.c3 .rd-card > .rd-if { position: absolute; top: 0; left: 0; width: 1280px; height: 720px; border: 0; transform: scale(var(--rp-scale, 0.5)); transform-origin: top left; background: var(--slide-bg); }
|
|
27
|
+
.c3 .rd-thumb > .rd-if { pointer-events: none; }
|
|
28
|
+
.c3 .rd-big.placing, .c3 .rd-docf.placing { box-shadow: 0 0 0 2px var(--acc); }
|
|
29
|
+
.c3 .rd-big.placing > .rd-if, .c3 .rd-docf.placing > .rd-if { cursor: crosshair; }
|
|
30
|
+
.c3 .rd-docf { position: relative; border: 1px solid var(--border); border-radius: 8px; background: var(--slide-bg); overflow: hidden; }
|
|
31
|
+
.c3 .rd-docf > .rd-if { display: block; width: 100%; height: var(--rp-h, 480px); border: 0; background: var(--slide-bg); }
|
|
32
|
+
.c3 .rd-docf.sm { max-height: 520px; overflow: auto; }
|
|
33
|
+
.c3 .rd-doclayer { position: absolute; inset: 0; pointer-events: none; }
|
|
34
|
+
.c3 .rd-doclayer > * { pointer-events: auto; }
|
|
35
|
+
.c3 .rd-tip { position: absolute; z-index: 4; left: var(--rp-x, 0); top: var(--rp-y, 0); transform: translate(-50%, calc(-100% - 6px)); max-width: 280px; padding: 4px 8px; border-radius: 6px; background: var(--foreground); color: var(--background); font: 500 var(--fs-2) var(--sans); pointer-events: none; white-space: normal; }
|
|
36
|
+
.c3 .rd-tip[hidden] { display: none; }
|
|
37
|
+
|
|
38
|
+
/* the deck: filmstrip, current slide, notes */
|
|
39
|
+
.c3 .rd-dk-main { display: grid; grid-template-columns: 124px minmax(0, 1fr); gap: var(--sp-3); align-items: start; }
|
|
40
|
+
.c3 .rd-dk-strip { display: grid; gap: 8px; align-content: start; max-height: calc(100vh - 230px); overflow: auto; position: sticky; top: 0; padding: 3px; }
|
|
41
|
+
.c3 .rd-dk-strip.h { grid-auto-flow: column; grid-auto-columns: 120px; max-height: none; position: static; overflow-x: auto; overflow-y: hidden; }
|
|
42
|
+
.c3 .rd-dk-th { position: relative; display: block; width: 100%; height: auto; min-height: 0; padding: 0; border: 0; border-radius: 6px; background: none; cursor: pointer; }
|
|
43
|
+
.c3 .rd-dk-th[aria-current="true"] { outline: 2px solid var(--acc); outline-offset: 2px; }
|
|
44
|
+
.c3 .rd-dk-thn { position: absolute; left: 4px; bottom: 4px; font: var(--fs-1) var(--mono); background: var(--card); color: var(--foreground); border-radius: 6px; padding: 0 4px; }
|
|
45
|
+
.c3 .rd-dk-thp { position: absolute; right: 4px; top: 4px; display: inline-flex; gap: 2px; align-items: center; font: var(--fs-1) var(--mono); background: var(--acc); color: var(--background); border-radius: 6px; padding: 0 4px; }
|
|
46
|
+
.c3 .rd-dk-thp .ic { width: 10px; height: 10px; }
|
|
47
|
+
.c3 .rd-dk-stage { display: grid; gap: var(--sp-2); min-width: 0; }
|
|
48
|
+
.c3 .rd-dk-cap { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; justify-content: space-between; }
|
|
49
|
+
.c3 .rd-dk-under { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr)); gap: var(--sp-3); align-items: start; }
|
|
50
|
+
.c3 .rd-dk-ncol { display: grid; gap: var(--sp-3); min-width: 0; }
|
|
51
|
+
.c3 .rd-spk { min-height: 96px; resize: vertical; width: 100%; box-sizing: border-box; padding: 8px 10px; border: 1px solid var(--border); border-radius: 8px; background: var(--card); color: var(--foreground); font: var(--fs-3)/1.5 var(--sans); }
|
|
52
|
+
.c3 .rd-carry { display: grid; gap: 6px; padding: 8px 10px; border: 1px dashed var(--border); border-radius: 8px; color: var(--muted-foreground); }
|
|
53
|
+
.c3 .rd-carry p { margin: 0; font-size: var(--fs-3); font-style: italic; }
|
|
54
|
+
/* pins: a numbered dot on the slide; yours blue, PMOS's purple and dashed while it is a proposal */
|
|
55
|
+
.c3 .rd-pindot { position: absolute; z-index: 2; left: var(--rp-x, 50%); top: var(--rp-y, 50%); transform: translate(-50%, -50%); width: 26px; height: 26px; min-width: 0; min-height: 0; padding: 0; border-radius: 50%; display: grid; place-items: center; place-content: center; font: 600 var(--fs-1) var(--mono); color: var(--background); background: var(--acc); border: 2px solid var(--slide-bg); box-shadow: 0 2px 6px color-mix(in oklab, var(--slide-fg) 30%, transparent); cursor: pointer; }
|
|
56
|
+
.c3 .rd-pindot.a { background: var(--agent); }
|
|
57
|
+
.c3 .rd-pindot.prop { border-style: dashed; }
|
|
58
|
+
.c3 .rd-pindot.on { box-shadow: 0 0 0 4px color-mix(in oklab, var(--acc) 35%, transparent); }
|
|
59
|
+
.c3 .rd-pindot.a.on { box-shadow: 0 0 0 4px color-mix(in oklab, var(--agent) 35%, transparent); }
|
|
60
|
+
.c3 .rd-notes .rd-pindot { position: static; transform: none; border-color: var(--card); box-shadow: none; }
|
|
61
|
+
.c3 .rd-notes > li.rd-note { grid-template-columns: 28px minmax(0, 1fr); padding: 6px; margin: 0 -6px; border-radius: 8px; }
|
|
62
|
+
.c3 .rd-notes > li.rd-note::before { display: none; }
|
|
63
|
+
.c3 .rd-notes > li.rd-note.on { background: var(--muted); }
|
|
64
|
+
.c3 .rd-clip { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--muted-foreground); }
|
|
65
|
+
.c3 .rd-cmpg { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr)); gap: var(--sp-3); }
|
|
66
|
+
.c3 .rd-cmph { flex-wrap: wrap; margin-bottom: 6px; }
|
|
67
|
+
.c3 .rd-cmpc { min-width: 0; }
|
|
68
|
+
.c3 .rd-none { min-height: 120px; align-content: center; }
|
|
69
|
+
|
|
70
|
+
/* Present: the audience view is the product's .rp-deck; the presenter view lays cards on the same stage */
|
|
71
|
+
.c3 .rd-ovhost { position: fixed; inset: 0; z-index: 60; }
|
|
72
|
+
.c3 .rp-deck.rd-ov { z-index: 60; display: flex; flex-direction: column; gap: 0; }
|
|
73
|
+
.c3 .rd-ovframe { overflow: hidden; }
|
|
74
|
+
.c3 .rd-ovframe > .rd-if { position: absolute; top: 0; left: 0; width: 1280px; height: 720px; border: 0; transform: scale(var(--rp-scale, 1)); transform-origin: top left; background: var(--slide-bg); }
|
|
75
|
+
.c3 .rd-pg { flex: 1 1 auto; min-height: 0; display: grid; grid-template-columns: minmax(0, 1fr) 360px; gap: 16px; padding: 16px; overflow: auto; align-items: start; }
|
|
76
|
+
.c3 .rd-pmain, .c3 .rd-pside { display: grid; gap: 12px; min-width: 0; }
|
|
77
|
+
.c3 .rd-pp { display: grid; gap: 8px; padding: 12px; border: 1px solid var(--border); border-radius: 8px; background: var(--card); color: var(--foreground); }
|
|
78
|
+
.c3 .rd-plab { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; }
|
|
79
|
+
.c3 .rd-ph { display: flex; gap: 6px; align-items: center; font: 500 var(--fs-1) var(--mono); color: var(--muted-foreground); text-transform: uppercase; letter-spacing: .06em; }
|
|
80
|
+
.c3 .rd-pnote { margin: 0; font-size: var(--fs-4); line-height: 1.5; }
|
|
81
|
+
.c3 .rd-ptime { grid-template-columns: 1fr 1fr; }
|
|
82
|
+
.c3 .rd-timer { font: 600 var(--fs-6) var(--mono); }
|
|
83
|
+
.c3 .rd-jump { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; max-height: 260px; overflow: auto; }
|
|
84
|
+
.c3 .rd-jump button { display: flex; gap: 8px; align-items: center; justify-content: flex-start; width: 100%; height: auto; text-align: left; background: none; border: 0; padding: 5px 8px; border-radius: 6px; font-size: var(--fs-2); }
|
|
85
|
+
.c3 .rd-jump button[aria-current="true"] { background: color-mix(in oklab, var(--acc) 14%, transparent); color: var(--acc); font-weight: 500; }
|
|
86
|
+
.c3 .rd-jump .mono { color: var(--muted-foreground); font-size: var(--fs-1); }
|
|
87
|
+
.c3 .rd-ov .rp-deck__bar { flex-wrap: wrap; }
|
|
88
|
+
@media (hover: hover) {
|
|
89
|
+
.c3 .rd-jump button:hover { background: var(--muted); }
|
|
90
|
+
.c3 .rd-dks-opt:hover { background: var(--muted); }
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/* the Design studio: the conversation left, the live result right */
|
|
94
|
+
.c3 .rd-dks { display: grid; grid-template-columns: minmax(300px, 380px) minmax(0, 1fr); gap: var(--sp-4); align-items: start; }
|
|
95
|
+
.c3 .rd-dks-chat { display: grid; gap: var(--sp-2); position: sticky; top: 0; max-height: calc(100vh - 220px); grid-template-rows: auto minmax(0, 1fr) auto auto; min-width: 0; }
|
|
96
|
+
.c3 .rd-dks-desc { display: grid; gap: 6px; }
|
|
97
|
+
.c3 .rd-dks-desc .dim { font-size: var(--fs-1); }
|
|
98
|
+
.c3 .rd-dks-log { list-style: none; margin: 0; padding: 0 4px 0 0; display: grid; gap: 12px; align-content: start; overflow: auto; min-height: 120px; }
|
|
99
|
+
.c3 .rd-dks-msg { display: grid; grid-template-columns: 28px minmax(0, 1fr); gap: 8px; align-items: start; }
|
|
100
|
+
.c3 .rd-dks-msg .bub { display: grid; grid-template-columns: minmax(0, 1fr); gap: 6px; justify-items: start; padding: 8px 10px; border: 1px solid var(--border); border-radius: 8px; background: var(--card); min-width: 0; }
|
|
101
|
+
.c3 .rd-dks-msg.you .bub { background: color-mix(in oklab, var(--acc) 7%, var(--card)); border-color: color-mix(in oklab, var(--acc) 25%, var(--border)); }
|
|
102
|
+
.c3 .rd-dks-msg.err .bub { border-color: color-mix(in oklab, var(--warning) 50%, var(--border)); }
|
|
103
|
+
.c3 .rd-dks-msg .who { font: 500 var(--fs-1) var(--mono); color: var(--muted-foreground); text-transform: uppercase; letter-spacing: .06em; }
|
|
104
|
+
.c3 .rd-dks-msg p { margin: 0; font-size: var(--fs-3); line-height: 1.5; overflow-wrap: anywhere; }
|
|
105
|
+
.c3 .rd-dks-ver { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
106
|
+
.c3 .rd-dks-ver[aria-pressed="true"] { color: var(--acc); border-color: var(--acc); }
|
|
107
|
+
.c3 .rd-dks-smp { display: grid; grid-template-columns: 56px minmax(0, 1fr); gap: 10px; align-items: start; width: 100%; box-sizing: border-box; padding: 8px; border: 1px solid var(--border); border-radius: 8px; background: var(--background); }
|
|
108
|
+
.c3 .rd-dks-smp b { display: flex; gap: 6px; align-items: center; font-size: var(--fs-2); overflow-wrap: anywhere; }
|
|
109
|
+
.c3 .rd-dks-smp .mono { font-size: var(--fs-1); }
|
|
110
|
+
.c3 .rd-dks-smp p { margin: 2px 0 0; font-size: var(--fs-2); line-height: 1.4; }
|
|
111
|
+
.c3 .rd-dks-thumb { display: grid; gap: 3px; align-content: start; width: 56px; aspect-ratio: 16 / 9; padding: 4px; box-sizing: border-box; border: 1px solid var(--slide-border); border-radius: 6px; background: var(--slide-bg); }
|
|
112
|
+
.c3 .rd-dks-thumb.img { padding: 0; object-fit: cover; }
|
|
113
|
+
.c3 .rd-dks-thumb i { display: block; height: 3px; background: var(--slide-track); }
|
|
114
|
+
.c3 .rd-dks-thumb.deck i:first-child { height: 6px; background: var(--slide-brand); }
|
|
115
|
+
.c3 .rd-dks-thumb.deck i:nth-child(2) { width: 70%; }
|
|
116
|
+
.c3 .rd-dks-thumb.page { aspect-ratio: 3 / 4; width: 40px; justify-self: center; }
|
|
117
|
+
.c3 .rd-dks-thumb.page i:first-child { width: 60%; background: var(--slide-fg); }
|
|
118
|
+
.c3 .rd-dks-panel { display: grid; gap: 8px; padding: 10px; border: 1px dashed var(--border); border-radius: 8px; }
|
|
119
|
+
.c3 .rd-dks-opt { display: flex; gap: 10px; align-items: center; justify-content: flex-start; width: 100%; height: auto; text-align: left; white-space: normal; padding: 8px 10px; border: 1px solid var(--border); border-radius: 8px; background: var(--card); color: var(--foreground); font: inherit; font-size: var(--fs-3); cursor: pointer; }
|
|
120
|
+
.c3 .rd-dks-in { display: grid; gap: 8px; padding-top: var(--sp-2); border-top: 1px solid var(--border); }
|
|
121
|
+
.c3 .rd-dks-in textarea { min-height: 64px; resize: vertical; width: 100%; box-sizing: border-box; padding: 8px 10px; border: 1px solid var(--border); border-radius: 8px; background: var(--card); color: var(--foreground); font: var(--fs-3)/1.5 var(--sans); }
|
|
122
|
+
.c3 .rd-dks-out { display: grid; gap: var(--sp-2); min-width: 0; }
|
|
123
|
+
.c3 .rd-dks-vers { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; justify-content: space-between; }
|
|
124
|
+
.c3 .rd-dks-vers .seg button { display: inline-flex; gap: 4px; align-items: center; }
|
|
125
|
+
.c3 .rd-dks-mk { z-index: 3; }
|
|
126
|
+
/* the saved design: a brief, not a template */
|
|
127
|
+
.c3 .rd-dks-q { margin: 0; padding: 8px 12px; border-left: 3px solid var(--acc); background: var(--muted); border-radius: 0; font-size: var(--fs-3); line-height: 1.5; }
|
|
128
|
+
.c3 .rd-dks-ref { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 10px; }
|
|
129
|
+
.c3 .rd-dks-rule { display: grid; gap: 4px; padding: 8px 12px; border: 1px solid var(--border); border-radius: 8px; }
|
|
130
|
+
.c3 .rd-dks-rule b { font-size: var(--fs-3); }
|
|
131
|
+
.c3 .rd-dks-rule ul { margin: 0; padding-left: 18px; font-size: var(--fs-3); line-height: 1.5; }
|
|
132
|
+
@media (max-width: 900px) {
|
|
133
|
+
.c3 .rd-dk-main { grid-template-columns: minmax(0, 1fr); }
|
|
134
|
+
.c3 .rd-dk-strip { grid-auto-flow: column; grid-auto-columns: 104px; max-height: none; position: static; overflow-x: auto; overflow-y: hidden; }
|
|
135
|
+
.c3 .rd-pg { grid-template-columns: minmax(0, 1fr); padding: 12px; }
|
|
136
|
+
.c3 .rd-dks { grid-template-columns: minmax(0, 1fr); }
|
|
137
|
+
.c3 .rd-dks-chat { position: static; max-height: none; }
|
|
138
|
+
.c3 .rd-dks-log { max-height: 420px; }
|
|
139
|
+
}
|