@lovek4d/kickflip 0.4.0 → 0.5.3
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/CONTEXT.md +69 -48
- package/README.md +1 -1
- package/SKILL.md +22 -20
- package/bin/doctor.mjs +4 -4
- package/bin/install.mjs +3 -3
- package/bin/kickflip.mjs +27 -18
- package/bin/wait-events.mjs +2 -2
- package/board/agents.mjs +2 -0
- package/board/bin/board.mjs +108 -39
- package/board/domain.mjs +7 -7
- package/board/finish.mjs +4 -3
- package/board/headless.mjs +5 -3
- package/board/merge3.mjs +1 -0
- package/board/on-host.mjs +1 -1
- package/board/permissions.mjs +2 -2
- package/board/public/app-asks.js +9 -92
- package/board/public/app-banner.js +7 -13
- package/board/public/app-cards.js +70 -37
- package/board/public/app-core.js +24 -25
- package/board/public/app-header.js +2 -1
- package/board/public/app-lanes.js +55 -23
- package/board/public/app-needs.js +129 -4
- package/board/public/app-reader.js +174 -0
- package/board/public/app-snapshot.js +6 -5
- package/board/public/app-threads.js +83 -58
- package/board/public/app.html +2 -0
- package/board/public/app.js +66 -24
- package/board/public/attach.js +2 -2
- package/board/public/dialogs.js +9 -39
- package/board/public/hub-kit.js +4 -2
- package/board/public/hub.css +1 -0
- package/board/public/linear-key.js +46 -35
- package/board/public/new-task.js +100 -0
- package/board/public/prototype-kit.js +28 -3
- package/board/public/prototype-switcher.js +42 -107
- package/board/public/shell.js +7 -1
- package/board/public/sidebar.css +1 -0
- package/board/public/sidebar.js +44 -5
- package/board/public/style.css +194 -35
- package/board/public/ui-cards.js +80 -44
- package/board/public/ui-enums.js +1 -1
- package/board/public/ui-header.js +2 -2
- package/board/public/ui-order.js +12 -10
- package/board/public/ui-phase-bars.js +4 -4
- package/board/public/ui-questions.js +63 -47
- package/board/public/ui-sidebar.js +27 -15
- package/board/public/ui-threads.js +27 -14
- package/board/public/ui.js +76 -14
- package/board/public/view-frame.js +1 -0
- package/board/public/view-hub-settings.js +11 -10
- package/board/public/view-hub.js +17 -3
- package/board/public/view-questions.js +174 -202
- package/board/public/view-settings.js +208 -70
- package/board/server.mjs +19 -18
- package/board/store.mjs +20 -13
- package/board/transcript.mjs +2 -0
- package/board/worktree.mjs +24 -20
- package/hooks-plugin/hooks/board-data-gate.mjs +50 -0
- package/hooks-plugin/hooks/hooks.json +9 -0
- package/hub/boards.mjs +4 -4
- package/hub/front-door.mjs +20 -0
- package/hub/github.mjs +3 -3
- package/hub/hub.mjs +11 -14
- package/hub/linear.mjs +1 -2
- package/hub/live.mjs +2 -2
- package/hub/locks.mjs +1 -1
- package/hub/new-board.mjs +2 -2
- package/hub/owner-checks.mjs +1 -0
- package/hub/pr-report.mjs +2 -2
- package/hub/presence.mjs +1 -1
- package/hub/push.mjs +2 -2
- package/hub/readiness.mjs +1 -2
- package/hub/review-send.mjs +1 -0
- package/hub/secrets.mjs +2 -0
- package/hub/self-restart.mjs +2 -0
- package/hub/sessions.mjs +2 -2
- package/hub/share.mjs +1 -0
- package/hub/slack.mjs +2 -2
- package/hub/stream.mjs +10 -13
- package/hub/try.mjs +7 -7
- package/hub/upgrade.mjs +1 -1
- package/hub/usage.mjs +3 -3
- package/hub/views.mjs +1 -1
- package/package.json +2 -1
- package/shared/audit.mjs +4 -0
- package/shared/fake-gh.mjs +17 -4
- package/shared/owner-check.mjs +3 -0
- package/shared/service.mjs +4 -4
- package/shared/tailscale.mjs +1 -0
- package/shared/usage-gate.mjs +1 -1
package/board/public/style.css
CHANGED
|
@@ -163,6 +163,11 @@ button.link { background: none; border: 0; color: var(--accent); padding: 8px 12
|
|
|
163
163
|
.wb-done { padding: 8px 12px; font-size: 12.5px; color: var(--muted); }
|
|
164
164
|
.wb-done a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
|
|
165
165
|
.wb-loosehead { cursor: default; }
|
|
166
|
+
.wb-counts { position: relative; border: 0; background: none; padding: 4px 0; font: inherit; cursor: help; color: var(--muted); font-weight: 400; font-variant-numeric: tabular-nums; white-space: nowrap; }
|
|
167
|
+
.wb-tip { display: none; position: absolute; right: 0; top: 100%; z-index: 6; margin-top: 2px; padding: 8px 10px; border: 1px solid var(--line); border-radius: 8px; background: var(--panel); box-shadow: 0 6px 18px rgba(0,0,0,.18); color: var(--text); font-weight: 400; text-align: left; }
|
|
168
|
+
.wb-counts:hover .wb-tip, .wb-counts.open .wb-tip { display: block; }
|
|
169
|
+
.wb-counts .wv-cur { font-weight: 700; color: var(--accent); }
|
|
170
|
+
.wb-lane + .wb-lane, .wb-lane + .wb-loose { border-top: 1px solid var(--line); }
|
|
166
171
|
.wb-loosehead:hover { background: var(--band); }
|
|
167
172
|
/* A wave card's step number, inside its id chip, and its ⋯ menu. */
|
|
168
173
|
.wn { color: var(--muted); font-variant-numeric: tabular-nums; padding-right: 5px; margin-right: 4px; border-right: 1px solid var(--line); }
|
|
@@ -202,10 +207,12 @@ code { overflow-wrap: anywhere; }
|
|
|
202
207
|
/* The ⌘↵ / Ctrl+↵ hint left of Send: only where there is a keyboard to press it on. */
|
|
203
208
|
.send-hint { display: none; color: var(--muted); font-size: 12px; white-space: nowrap; }
|
|
204
209
|
@media (hover: hover) and (pointer: fine) { .send-hint { display: inline; } }
|
|
205
|
-
/* A composer's text box (BoardUI.dropZone)
|
|
206
|
-
the
|
|
210
|
+
/* A composer's text box (BoardUI.dropZone), its attach button inside at the bottom right with the text kept clear of it:
|
|
211
|
+
while files are dragged over the composer, attach.js marks it .dragging and the box gets a dashed accent outline
|
|
212
|
+
with Drop to attach over it. */
|
|
207
213
|
.dz { position: relative; clear: both; border-radius: 8px; }
|
|
208
|
-
.dz > textarea { display: block; }
|
|
214
|
+
.dz > textarea { display: block; padding-bottom: 40px; }
|
|
215
|
+
.dz > .attach { position: absolute; right: 6px; bottom: 6px; width: 32px; height: 32px; z-index: 1; }
|
|
209
216
|
.dz-hint { display: none; position: absolute; inset: 0; align-items: center; justify-content: center; border-radius: 8px; pointer-events: none;
|
|
210
217
|
background: color-mix(in srgb, var(--panel) 80%, transparent); color: var(--accent); font-weight: 600; font-size: 15px; }
|
|
211
218
|
[data-composer].dragging .dz { outline: 2px dashed var(--accent); outline-offset: 3px; }
|
|
@@ -232,7 +239,6 @@ code { overflow-wrap: anywhere; }
|
|
|
232
239
|
.msg .body:empty { display: none; }
|
|
233
240
|
.note-tools { display: flex; align-items: flex-start; gap: 6px; }
|
|
234
241
|
.note-tools .pending-files { flex: 1; margin-top: 4px; }
|
|
235
|
-
.note-tools .attach { margin-top: 2px; }
|
|
236
242
|
|
|
237
243
|
/* Compose button and sheet */
|
|
238
244
|
main { padding-bottom: calc(110px + env(safe-area-inset-bottom)); }
|
|
@@ -257,6 +263,10 @@ main { padding-bottom: calc(110px + env(safe-area-inset-bottom)); }
|
|
|
257
263
|
.sheet::backdrop { background: rgba(0,0,0,.35); touch-action: none; }
|
|
258
264
|
/* A phone sheet sits above the bottom bar, which already pads the safe area (--app-bottom). */
|
|
259
265
|
.sheet form { padding: 10px 16px max(12px, calc(env(safe-area-inset-bottom) - var(--app-bottom, 0px))); }
|
|
266
|
+
/* Modals never scroll sideways: content wraps at the modal's width, and overflow-x hidden is only the last guard. */
|
|
267
|
+
.sheet, .settings-modal { overflow-x: hidden; overflow-wrap: anywhere; }
|
|
268
|
+
.settings-body { overflow-x: hidden; overflow-wrap: anywhere; }
|
|
269
|
+
.sheet input, .sheet select, .sheet textarea, .settings-modal input, .settings-modal select, .settings-modal textarea { max-width: 100%; min-width: 0; }
|
|
260
270
|
/* A sheet's last row of buttons stays in view at the foot of its scrolling content. Sticking stops at the scroll
|
|
261
271
|
area's bottom padding, so the shadow covers what scrolls through that padding. */
|
|
262
272
|
.sheet-actions { position: sticky; bottom: 0; z-index: 1; padding-top: 8px; background: var(--panel); box-shadow: 0 40px 0 var(--panel); }
|
|
@@ -320,7 +330,19 @@ main { padding-bottom: calc(110px + env(safe-area-inset-bottom)); }
|
|
|
320
330
|
@media (prefers-reduced-motion: no-preference) { .working-dot { animation: pulse 1.4s ease-in-out infinite; } }
|
|
321
331
|
form[data-reply] .row .quick { margin-left: auto; margin-right: 6px; }
|
|
322
332
|
form[data-reply] .row [data-confirm="finish"] { margin-right: 6px; }
|
|
323
|
-
|
|
333
|
+
/* A composer's send buttons (ui.js sendButton), each with its key as a small gray hint where there is a keyboard and
|
|
334
|
+
room. A pair takes a row of two halves; a Todo card's reply box wraps its pair under the row. */
|
|
335
|
+
.send-actions { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; margin-top: 10px; }
|
|
336
|
+
.send-actions button, [data-sends] button { display: inline-flex; align-items: center; justify-content: center; gap: 6px; }
|
|
337
|
+
.send-actions button { min-height: 44px; }
|
|
338
|
+
form[data-reply] .row { flex-wrap: wrap; }
|
|
339
|
+
form[data-reply] .row > .send-actions { flex: 0 0 100%; margin-top: 4px; }
|
|
340
|
+
.key-hint { display: none; font-size: 11px; font-weight: 400; color: var(--muted); white-space: nowrap; }
|
|
341
|
+
button.primary .key-hint { color: color-mix(in srgb, var(--on-accent) 62%, transparent); }
|
|
342
|
+
@media (hover: hover) and (pointer: fine) and (min-width: 600px) { .key-hint { display: inline; } }
|
|
343
|
+
#askStatus { margin: 6px 2px 0; }
|
|
344
|
+
#askStatus:empty { display: none; }
|
|
345
|
+
.q .proto-view { display: inline-block; margin: 0 0 10px; color: var(--accent); }
|
|
324
346
|
.msg .ask-actions { margin: -4px -6px 0 8px; }
|
|
325
347
|
button.attach { border: 0; background: transparent; padding: 0; }
|
|
326
348
|
button.attach:disabled { opacity: .35; }
|
|
@@ -343,7 +365,18 @@ button.attach:disabled { opacity: .35; }
|
|
|
343
365
|
@keyframes pulse-fill { 50% { background-color: color-mix(in srgb, var(--color-notice) 35%, transparent); } }
|
|
344
366
|
@media (prefers-reduced-motion: no-preference) { .phase-bars:not(.dim) i.now { animation: pulse-fill 1.4s ease-in-out infinite; } }
|
|
345
367
|
/* A stale build's status line, dot included, is the needs-you red, and a tap on it nudges Claude (ui-cards.js builderStatus). */
|
|
346
|
-
button
|
|
368
|
+
/* A status line that is a button is drawn as the div it replaces: this one reset, then only a colour per state. The font
|
|
369
|
+
shorthand stays out so .sub's 12px wins. It sets no width: a button is its own block formatting context, so a full-width one
|
|
370
|
+
drops below the bump icons' float instead of sitting beside it as the div's line box does (board/layout.test.mjs). */
|
|
371
|
+
button.sub { display: block; margin-inline: 0; margin-bottom: 0; padding: 0; min-height: 0; border: 0; border-radius: 0; background: none;
|
|
372
|
+
font-family: inherit; font-weight: inherit; letter-spacing: inherit; line-height: inherit; text-align: left; appearance: none; -webkit-appearance: none; }
|
|
373
|
+
button.sub.agent.stalled { color: var(--color-danger); }
|
|
374
|
+
/* A tap on it calms the line to the in-progress orange, its dot sending a ripple, until the card's next status line (app-cards.js nudge). */
|
|
375
|
+
button.sub.agent.stalled.nudging { color: var(--color-notice); cursor: default; }
|
|
376
|
+
.nudging .working-dot { position: relative; }
|
|
377
|
+
.nudging .working-dot::after { content: ''; position: absolute; inset: -1px; border-radius: 50%; border: 1.5px solid currentColor; opacity: 0; }
|
|
378
|
+
@keyframes nudge-ping { from { transform: scale(1); opacity: .9; } to { transform: scale(2.6); opacity: 0; } }
|
|
379
|
+
@media (prefers-reduced-motion: no-preference) { .nudging .working-dot::after { animation: nudge-ping 1.1s ease-out infinite; } }
|
|
347
380
|
.stalled .working-dot { background: currentColor; }
|
|
348
381
|
.brand { display: grid; grid-template-columns: auto auto minmax(0, 1fr); column-gap: 10px; row-gap: 2px; }
|
|
349
382
|
.brand .hub { grid-row: 1 / span 2; align-self: center; }
|
|
@@ -361,10 +394,40 @@ button.sub.agent.stalled { display: block; width: 100%; padding: 0; border: 0; b
|
|
|
361
394
|
(docs/adr/2026-11-03-1551-planners-and-implementers-are-two-kinds-of-agent.md). */
|
|
362
395
|
.sub.agent.planner, .msg.builder-status.planner, .msg.agent.started.planner { color: var(--accent); }
|
|
363
396
|
.planner .working-dot { background: currentColor; }
|
|
397
|
+
/* Every status line on an In Progress card is the phase-bar orange, a planner's too, and every build or plan line on a
|
|
398
|
+
Todo card the owner's blue, dot included; a Todo card's planner dashes are that blue, the running one pulsing
|
|
399
|
+
(docs/adr/2026-11-04-2300-each-lane-is-a-queue-for-the-orchestrator.md). */
|
|
400
|
+
.sub.agent.in-progress { color: var(--color-notice); }
|
|
401
|
+
.sub.agent.in-todo { color: var(--accent); }
|
|
402
|
+
.sub.agent.in-progress .working-dot, .sub.agent.in-todo .working-dot { background: currentColor; }
|
|
403
|
+
/* docs/adr/2026-11-05-0410-a-card-status-word-comes-from-a-signal-the-board-checks.md: a quiet builder and a request no planner
|
|
404
|
+
has picked up are grey, after the lane colours so they win. */
|
|
405
|
+
.sub.agent.quiet, .sub.asked { color: var(--muted); }
|
|
406
|
+
.phase-bars.plan { --bar-fill: var(--accent); }
|
|
407
|
+
@keyframes pulse-fill-plan { 50% { background-color: color-mix(in srgb, var(--accent) 35%, transparent); } }
|
|
408
|
+
@media (prefers-reduced-motion: no-preference) { .phase-bars.plan:not(.dim) i.now { animation-name: pulse-fill-plan; } }
|
|
364
409
|
.msg.calls { padding: 0 10px; margin: 4px 0; font-size: 12px; overflow-wrap: anywhere; }
|
|
365
|
-
.msg.calls summary { cursor: pointer; color: var(--muted); }
|
|
366
|
-
.msg.calls
|
|
410
|
+
.msg.calls summary { cursor: pointer; color: var(--muted); list-style: none; }
|
|
411
|
+
.msg.calls summary::-webkit-details-marker { display: none; }
|
|
412
|
+
.msg.calls[open] summary .mark-icon { transform: rotate(90deg); }
|
|
413
|
+
.msg.calls ol { margin: 4px 0; padding-left: 23px; }
|
|
367
414
|
.agent-dot { display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: currentColor; margin-right: 5px; vertical-align: 1px; }
|
|
415
|
+
/* Every thread status line's leading mark, icon or dot, sits centred in one 18px box, so the text after it always starts
|
|
416
|
+
at the same place; the box is 12px tall so line heights stay
|
|
417
|
+
(docs/adr/2026-11-04-2130-a-button-tap-is-a-status-line-or-a-message-footer.md). */
|
|
418
|
+
.mark { display: inline-block; position: relative; width: 18px; height: 12px; margin-right: 5px; vertical-align: -1px; flex: none; }
|
|
419
|
+
.mark > * { position: absolute; inset: 0; margin: auto; }
|
|
420
|
+
.mark .working-dot, .mark .agent-dot { margin: auto; vertical-align: 0; }
|
|
421
|
+
.mark-icon { width: 12px; height: 12px; }
|
|
422
|
+
/* New questions' plain question mark is a size up from its siblings. */
|
|
423
|
+
.mark-icon.big { width: 18px; height: 18px; }
|
|
424
|
+
.msg.new-questions a { color: inherit; }
|
|
425
|
+
/* A message's footer: the tap it came from, then Claude's pick-up to its right. */
|
|
426
|
+
.msg .reply { display: flex; flex-wrap: wrap; align-items: center; column-gap: 12px; row-gap: 2px; }
|
|
427
|
+
.msg-foot .foot-status { display: inline-flex; align-items: center; }
|
|
428
|
+
/* The thread's eye and fire are toggles: pressed reads as chosen, and the hint under the box says what Send posts. */
|
|
429
|
+
form[data-reply] .tools { display: inline-flex; flex: none; }
|
|
430
|
+
button.attach[aria-pressed="true"] { color: var(--accent); background: var(--chip); }
|
|
368
431
|
/* INT-30: card line order */
|
|
369
432
|
.line6 { margin-top: 4px; }
|
|
370
433
|
.card-time time { font-variant-numeric: tabular-nums; }
|
|
@@ -383,6 +446,13 @@ button.sub.agent.stalled { display: block; width: 100%; padding: 0; border: 0; b
|
|
|
383
446
|
/* Each lane's sort icon and its menu, grey (docs/adr/2026-11-01-1817-colour-says-whos-waiting.md) */
|
|
384
447
|
/* INT-35: offline header */
|
|
385
448
|
.view-board.offline #compose { display: none; }
|
|
449
|
+
/* A board shared with someone else, view only (docs/adr/2026-11-05-2215-a-board-is-shared-view-only-with-a-tailscale-login.md):
|
|
450
|
+
shell.js marks the page .shared-view, which hides the +, every composer, Board settings, the architecture review and
|
|
451
|
+
a card's buttons, keeping its links (Visit, Notes, Open questions). */
|
|
452
|
+
.shared-view #compose, .shared-view [data-composer], .shared-view #settingsLink, .shared-view #archBulb,
|
|
453
|
+
.shared-view .actions button, .shared-view button[data-confirm] { display: none !important; }
|
|
454
|
+
.view-only-strip { margin: 8px 0; padding: 8px 12px; border-radius: 10px; background: var(--accent-soft); font-size: 13px; }
|
|
455
|
+
.view-only-strip b { color: var(--accent); }
|
|
386
456
|
.view-board.offline main > * { opacity: .72; }
|
|
387
457
|
.view-board.offline main, .view-board.offline > .top > :not(.nav), .view-board.offline > .top .nav > :not(.refresh) { pointer-events: none; }
|
|
388
458
|
/* INT-28: answer banner */
|
|
@@ -493,6 +563,17 @@ main > * { transition: opacity .25s ease; }
|
|
|
493
563
|
.view-settings .who.new { border-color: var(--accent); }
|
|
494
564
|
.view-settings .add { display: flex; gap: 6px; margin-top: 8px; }
|
|
495
565
|
.view-settings .add input { flex: 1; min-width: 0; }
|
|
566
|
+
.view-settings .add.pick { flex-wrap: wrap; }
|
|
567
|
+
.view-settings .share-now { color: var(--ok); font-weight: 600; }
|
|
568
|
+
.view-settings .share-now::before { content: ""; display: inline-block; width: 7px; height: 7px; margin-right: 5px; border-radius: 50%; background: currentColor; vertical-align: 1px; }
|
|
569
|
+
.view-settings .share-reach { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin: 10px 0 4px; }
|
|
570
|
+
.view-settings .share-reach p { flex: 1 1 220px; margin: 0; }
|
|
571
|
+
.view-settings .share-reach button { flex: none; }
|
|
572
|
+
.view-settings .pick-col { flex: 1 1 140px; min-width: 0; display: flex; flex-direction: column; gap: 6px; }
|
|
573
|
+
.view-settings .pick-list { max-height: 160px; overflow-y: auto; display: flex; flex-direction: column; gap: 4px; }
|
|
574
|
+
.view-settings .pick-list button { text-align: left; }
|
|
575
|
+
.view-settings .pick-list button[aria-pressed="true"] { border-color: var(--accent); }
|
|
576
|
+
.view-settings .who .sub { display: block; margin-top: 2px; }
|
|
496
577
|
.view-settings .replies .reply { margin-top: 8px; }
|
|
497
578
|
.view-settings label.who { gap: 12px; cursor: pointer; }
|
|
498
579
|
.view-settings label.who .sub { display: block; margin-top: 2px; }
|
|
@@ -527,6 +608,9 @@ main > * { transition: opacity .25s ease; }
|
|
|
527
608
|
.view-questions .opt .lbl { font-weight: 600; }
|
|
528
609
|
.view-questions .opt .rec { color: var(--accent); font-weight: 500; font-size: 12px; margin-left: 4px; }
|
|
529
610
|
.view-questions .opt .det { color: var(--muted); font-size: 13px; }
|
|
611
|
+
.view-questions .opt .suggested { margin-left: 6px; white-space: nowrap; }
|
|
612
|
+
.view-questions .opt .suggested-why { margin-top: 4px; color: var(--muted); font-size: 13px; line-height: 1.35; overflow-wrap: anywhere; }
|
|
613
|
+
.view-questions .opt .suggested-why a { color: var(--accent); }
|
|
530
614
|
.view-questions .note { margin-top: 4px; }
|
|
531
615
|
.view-questions .ans { background: var(--accent-soft); border-radius: 9px; padding: 7px 10px; margin-top: 8px; font-size: 13px; }
|
|
532
616
|
.view-questions .rep { background: var(--claude); border-radius: 9px; padding: 7px 10px; margin-top: 6px; font-size: 13px; }
|
|
@@ -536,6 +620,8 @@ main > * { transition: opacity .25s ease; }
|
|
|
536
620
|
.view-questions .topics button { min-width: 0; border: 1px solid var(--line); border-radius: 999px; padding: 4px 11px; font-size: 13px;
|
|
537
621
|
background: var(--panel); color: var(--text); white-space: normal; text-align: left; overflow-wrap: anywhere; }
|
|
538
622
|
.view-questions .topics button[aria-pressed="true"] { border-color: var(--accent); background: var(--accent-soft); }
|
|
623
|
+
@keyframes pill-arrive { from { opacity: 0; transform: translateX(-12px); box-shadow: 0 0 0 3px var(--accent); } to { opacity: 1; transform: none; box-shadow: 0 0 0 0 transparent; } }
|
|
624
|
+
@media (prefers-reduced-motion: no-preference) { .view-questions .topics button.arrived { animation: pill-arrive .6s ease-out; } }
|
|
539
625
|
.view-questions .topics .n { color: var(--muted); margin-left: 4px; }
|
|
540
626
|
.view-questions .topichead { margin: 2px 0 6px; }
|
|
541
627
|
.view-questions details.done > summary { cursor: pointer; color: var(--muted); font-size: 13px; margin: 16px 0 4px; }
|
|
@@ -543,41 +629,41 @@ main > * { transition: opacity .25s ease; }
|
|
|
543
629
|
.view-questions details.done button.ghost { font-size: 14px; text-align: left; padding: 6px 2px; }
|
|
544
630
|
.view-questions details.done .trow button { min-width: 0; }
|
|
545
631
|
.view-questions details.done .trow span { flex: none; }
|
|
632
|
+
.view-questions details.resolved-group > summary { list-style: none; min-height: 44px; display: flex; align-items: center; gap: 8px; font-size: 14px; margin: 12px 0; }
|
|
633
|
+
.view-questions details.resolved-group > summary::-webkit-details-marker { display: none; }
|
|
634
|
+
.view-questions details.resolved-group > summary .caret { transition: transform .15s; }
|
|
635
|
+
.view-questions details.resolved-group[open] > summary .caret { transform: rotate(90deg); }
|
|
636
|
+
.view-questions details.resolved-group > summary .names { font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
|
|
637
|
+
.view-questions .q.resolved button.chip { cursor: pointer; font: inherit; font-size: 12px; min-height: 28px; }
|
|
638
|
+
.view-questions .q.resolved button.chip:disabled { cursor: default; }
|
|
639
|
+
.view-questions .q.resolved .resolved-line { margin: 8px 0; }
|
|
640
|
+
.view-questions .q.resolved .opt { cursor: default; }
|
|
641
|
+
.view-questions .q.resolved .opt .det { display: none; }
|
|
642
|
+
.view-questions .q.resolved .opt:has(input:checked) .det { display: block; }
|
|
643
|
+
.view-questions .q.resolved .opt:not(:has(input:checked)) { opacity: .6; }
|
|
644
|
+
.view-questions .q.resolved .reask-line { margin-top: 10px; }
|
|
546
645
|
.view-questions .bar { position: sticky; bottom: var(--app-bottom, 0px); padding: 10px 0 max(10px, env(safe-area-inset-bottom)); background: var(--bg);
|
|
547
646
|
display: flex; justify-content: space-between; align-items: center; gap: 8px; border-top: 1px solid var(--line); }
|
|
548
647
|
.view-questions .bar .send-hint { margin-left: auto; }
|
|
648
|
+
/* The + rides above the sticky Send bar rather than over its Send. */
|
|
549
649
|
.view-questions .bar #qstatus { min-width: 0; }
|
|
650
|
+
/* Typing with the keyboard up: one compact row docked on the keyboard, and the + out of the way (view-questions.js dock). */
|
|
651
|
+
.view-questions.kb-up .bar { position: fixed; left: 0; right: 0; bottom: var(--kb, 0px); z-index: 7; padding: 6px 16px; box-shadow: 0 -6px 14px rgba(0,0,0,.12); }
|
|
652
|
+
.view-questions.kb-up .bar .send-hint { display: none; }
|
|
550
653
|
.view-questions .bar #qstatus.sent { color: var(--color-success); font-weight: 600; }
|
|
551
654
|
.view-questions .solo { display: flex; justify-content: space-between; align-items: center; gap: 8px; margin: 4px 0; }
|
|
552
655
|
/* docs/adr/2026-11-02-1332-a-prototype-round-ends-with-a-one-take-confirm.md */
|
|
553
656
|
.view-questions .topichead { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; }
|
|
554
657
|
.view-questions .topichead .try-spin { width: 9px; height: 9px; margin-right: 5px; vertical-align: -1px; }
|
|
555
|
-
.view-questions .q .pr-open { display: inline-block; margin: 0 0 8px; }
|
|
556
658
|
.view-questions .pr-rule { display: flex; align-items: center; gap: 6px; margin: 0 0 6px; font-size: 12.5px; color: var(--muted); }
|
|
557
659
|
.view-questions .pr-rule svg { flex: none; }
|
|
558
660
|
|
|
559
|
-
/* A question's takes sit in as many columns as keep each at least 380px wide, one on a phone; each its option above
|
|
560
|
-
|
|
661
|
+
/* A question's drawn takes sit in as many columns as keep each at least 380px wide, one on a phone; each its option above
|
|
662
|
+
its diagram, and each row's takes top-aligned. */
|
|
561
663
|
.view-questions .takes { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 380px), 1fr)); gap: 10px; align-items: start; margin: 6px 0; }
|
|
562
664
|
.view-questions .take { min-width: 0; border: 1px solid var(--line); border-radius: 12px; background: var(--bg); padding: 10px; }
|
|
563
665
|
.view-questions .take:has(input:checked) { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
|
|
564
666
|
.view-questions .take .opt, .view-questions .take .opt:has(input:checked) { border: 0; padding: 0; margin: 0; background: none; }
|
|
565
|
-
/* view-questions.js sets a frame's height to its page's once measured; until then it shows nothing, so a take that turns
|
|
566
|
-
its question into the full-width layout never flashes cut off. */
|
|
567
|
-
.view-questions .take-shot { position: relative; display: block; margin-top: 8px; height: 360px; border: 1px solid var(--line); border-radius: 10px;
|
|
568
|
-
overflow: hidden; transition: height .15s ease; }
|
|
569
|
-
.view-questions .take-shot iframe { width: 100%; height: 100%; border: 0; background: var(--bg); }
|
|
570
|
-
.view-questions .take-shot.measuring { transition: none; }
|
|
571
|
-
.view-questions .take-shot.measuring iframe { visibility: hidden; }
|
|
572
|
-
.view-questions .take-shot.measuring::before { content: 'Loading take…'; position: absolute; inset: 0; display: grid; place-items: center;
|
|
573
|
-
color: var(--muted); font-size: 12.5px; }
|
|
574
|
-
.view-questions:has(.takes-full) main { max-width: none; }
|
|
575
|
-
.view-questions .takes-full { grid-template-columns: minmax(0, 1fr); }
|
|
576
|
-
.view-questions .take-choices { display: flex; flex-wrap: wrap; gap: 8px; }
|
|
577
|
-
.view-questions .take-choices .opt { flex: 1 1 160px; margin: 0; }
|
|
578
|
-
.view-questions .take-choices .opt[aria-current="true"] { border-color: var(--accent); }
|
|
579
|
-
.view-questions .takes-full .take { padding: 0; border: 0; }
|
|
580
|
-
.view-questions .takes-full .take-shot { margin-top: 0; transition: none; }
|
|
581
667
|
|
|
582
668
|
/* A take with nothing to see: boxes and arrows, then what it means in practice. */
|
|
583
669
|
.view-questions .flow { margin: 10px 0 4px; }
|
|
@@ -628,7 +714,7 @@ main > * { transition: opacity .25s ease; }
|
|
|
628
714
|
.view-frame .alone { white-space: nowrap; font-size: 13px; }
|
|
629
715
|
|
|
630
716
|
@media (max-width: 899px) {
|
|
631
|
-
:root:has(body > .top, body.has-sidebar > :not(.sidebar) > .top)
|
|
717
|
+
:root:has(body > .top, body.has-sidebar > :not(.sidebar) > .top) {
|
|
632
718
|
--app-bottom: calc(49px + max(4px, env(safe-area-inset-bottom)));
|
|
633
719
|
}
|
|
634
720
|
body > .top, body.has-sidebar > :not(.sidebar) > .top {
|
|
@@ -636,7 +722,7 @@ main > * { transition: opacity .25s ease; }
|
|
|
636
722
|
border-bottom: 0; border-top: 1px solid var(--line); padding-top: 4px; padding-bottom: max(4px, env(safe-area-inset-bottom));
|
|
637
723
|
}
|
|
638
724
|
.top .nav #refresh, .top .nav a.icon, .top .nav .arch-bulb { min-width: 44px; min-height: 44px; }
|
|
639
|
-
body > main, body.has-sidebar > :not(.sidebar) > main { padding-top: max(16px, env(safe-area-inset-top)); padding-bottom: calc(96px + var(--app-bottom, 0px) + env(safe-area-inset-bottom)); }
|
|
725
|
+
body > main, body.has-sidebar > :not(.sidebar) > main, body.has-sidebar > :not(.sidebar) > .split > main { padding-top: max(16px, env(safe-area-inset-top)); padding-bottom: calc(96px + var(--app-bottom, 0px) + env(safe-area-inset-bottom)); }
|
|
640
726
|
.view-frame:not(.own-header) { padding-bottom: var(--app-bottom, 0px); }
|
|
641
727
|
.sheet { bottom: max(0px, calc(var(--app-bottom, 0px) - var(--kb, 0px)));
|
|
642
728
|
max-height: calc(var(--vh, 100dvh) + var(--kb, 0px) - max(var(--app-bottom, 0px), var(--kb, 0px)) - env(safe-area-inset-top) - 12px); }
|
|
@@ -661,21 +747,18 @@ main > * { transition: opacity .25s ease; }
|
|
|
661
747
|
.lk-over, .lk-over > main { display: contents; }
|
|
662
748
|
|
|
663
749
|
.tk-section { margin: 10px 0; }
|
|
664
|
-
/* The Tickets source row's live state
|
|
750
|
+
/* The Tickets source row's live state (dialogs.js ticketsControl keyState). */
|
|
665
751
|
.tk-status { display: flex; align-items: center; gap: 8px; margin: 8px 0 0; font-size: 13px; color: var(--muted); }
|
|
666
752
|
.tk-status b { font-weight: 600; color: var(--text); }
|
|
667
753
|
.tk-status .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--line); flex: none; }
|
|
668
754
|
.tk-status.on .dot { background: var(--accent); }
|
|
669
755
|
.tk-status.on b { color: var(--accent); }
|
|
670
|
-
.tk-inline { margin: 6px 0 10px; border: 1px solid var(--accent); border-radius: 10px; padding: 8px 10px; background: var(--accent-soft); }
|
|
671
|
-
.tk-inline .tk-ask { margin: 2px 0 6px; font-size: 13px; }
|
|
672
|
-
.tk-inline .hub-view main { padding: 0; }
|
|
673
756
|
.tk-seg { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 4px; padding: 4px; margin: 8px 0; border: 1px solid var(--line); border-radius: 9px; background: var(--chip); }
|
|
674
757
|
.tk-seg button { min-width: 0; min-height: 44px; padding: 6px 4px; border: 1px solid transparent; border-radius: 6px; background: transparent; color: var(--muted); font: inherit; font-size: 13px; cursor: pointer; }
|
|
675
758
|
.tk-seg button[aria-pressed="true"] { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); font-weight: 600; }
|
|
676
|
-
.ask-seg { grid-template-columns: repeat(2, minmax(0, 1fr)); margin: 10px 0 0; }
|
|
677
|
-
.ask-choice-help { margin: 4px 2px 0; }
|
|
678
759
|
.tk-seg button:focus-visible { outline: 2px solid var(--accent); outline-offset: -3px; }
|
|
760
|
+
.landing-seg button { display: flex; flex-direction: column; align-items: center; gap: 4px; padding: 8px 6px; text-align: center; }
|
|
761
|
+
.landing-seg .sub { font-weight: 400; opacity: .8; line-height: 1.25; }
|
|
679
762
|
.tk-grid { display: grid; gap: 8px; grid-template-columns: minmax(0, 1fr); }
|
|
680
763
|
@media (min-width: 560px) { .tk-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr); } }
|
|
681
764
|
.tk-field { display: block; min-width: 0; }
|
|
@@ -735,6 +818,39 @@ button[aria-busy="true"]:is([data-card-bump], [data-bump]) svg { fill: currentCo
|
|
|
735
818
|
.main-log-actions { display: flex; justify-content: flex-end; margin-top: 12px; }
|
|
736
819
|
.main-log-actions button { display: inline-flex; align-items: center; gap: 7px; min-height: 40px; padding: 6px 18px; }
|
|
737
820
|
#mainLogReason { color: var(--color-notice); overflow-wrap: anywhere; }
|
|
821
|
+
/* The reader sheet (app-reader.js): a builder's log or notes, 85% of the height from the bottom. Its body scrolls
|
|
822
|
+
down only: every line wraps (#252). */
|
|
823
|
+
.reader-sheet { height: 85dvh; max-height: 85dvh; padding: 0; overflow: hidden; }
|
|
824
|
+
.reader-sheet[open] { display: flex; flex-direction: column; }
|
|
825
|
+
.reader-head { flex: none; display: flex; align-items: center; gap: 8px; padding: 8px 8px 8px 14px; border-bottom: 1px solid var(--line); }
|
|
826
|
+
.reader-head h2 { flex: none; margin: 0; font-size: 15px; }
|
|
827
|
+
.reader-ref { flex: 1; min-width: 0; font-size: 12px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
828
|
+
.reader-tools { flex: none; display: inline-flex; align-items: center; gap: 6px; }
|
|
829
|
+
.reader-tools:empty { display: none; }
|
|
830
|
+
.reader-tools button { height: 32px; padding: 0 12px; border-radius: 999px; font-size: 13px; }
|
|
831
|
+
.reader-tools button[aria-pressed="true"] { color: var(--accent); background: var(--chip); }
|
|
832
|
+
.reader-status { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; color: var(--muted); }
|
|
833
|
+
.reader-status::before { content: ''; width: 7px; height: 7px; border-radius: 50%; background: var(--muted); }
|
|
834
|
+
.reader-status.on { color: var(--accent); }
|
|
835
|
+
.reader-status.on::before { background: var(--accent); animation: reader-pulse 1.4s ease-in-out infinite; }
|
|
836
|
+
@keyframes reader-pulse { 50% { opacity: .35; } }
|
|
837
|
+
.reader-body { flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden; overscroll-behavior: contain; padding: 6px 0 max(12px, env(safe-area-inset-bottom)); }
|
|
838
|
+
.reader-body > .muted { padding: 8px 14px; margin: 0; }
|
|
839
|
+
.reader-row { padding: 5px 14px; font-size: 13.5px; line-height: 1.45; white-space: pre-wrap; overflow-wrap: anywhere; min-width: 0; }
|
|
840
|
+
.reader-row.text { padding-top: 9px; }
|
|
841
|
+
.reader-row.end { margin: 6px 14px 0; padding: 9px 11px; border: 1px solid var(--line); border-radius: 10px; background: var(--chip); }
|
|
842
|
+
.reader-row.sys, .reader-row.out { color: var(--muted); font-size: 12.5px; }
|
|
843
|
+
.reader-row.out { padding-left: 28px; font: 11.5px/1.45 ui-monospace, SFMono-Regular, Menlo, monospace; }
|
|
844
|
+
.reader-row.tool { font: 12px/1.45 ui-monospace, SFMono-Regular, Menlo, monospace; }
|
|
845
|
+
.reader-tag { display: inline-block; margin-right: 6px; padding: 0 6px; border-radius: 6px; background: var(--chip); color: var(--accent); font-size: 11px; }
|
|
846
|
+
.reader-raw, .reader-text { margin: 0; padding: 2px 14px 8px; white-space: pre-wrap; overflow-wrap: anywhere; word-break: break-word; font: 11.5px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace; }
|
|
847
|
+
.reader-md { padding: 4px 16px 12px; overflow-wrap: anywhere; line-height: 1.5; }
|
|
848
|
+
.reader-md h1 { font-size: 17px; margin: 10px 0 6px; }
|
|
849
|
+
.reader-md h2, .reader-md h3 { font-size: 15px; }
|
|
850
|
+
.reader-md pre, .reader-md code { white-space: pre-wrap; overflow-wrap: anywhere; }
|
|
851
|
+
.reader-md table { display: block; max-width: 100%; overflow-x: hidden; }
|
|
852
|
+
.reader-new { position: absolute; left: 50%; bottom: max(14px, env(safe-area-inset-bottom)); transform: translateX(-50%); border: 0; border-radius: 999px; padding: 7px 14px; background: var(--accent); color: var(--on-accent); font-size: 13px; box-shadow: 0 4px 14px rgba(0,0,0,.25); }
|
|
853
|
+
.reader-new[hidden] { display: none; }
|
|
738
854
|
|
|
739
855
|
/* The Auto Review lane (ui-cards.js reviewLane): its cards read like the board's, and Posted earlier's lines like a fold's. */
|
|
740
856
|
.rv-card, .rv-line { border-top: 1px solid var(--line); }
|
|
@@ -756,3 +872,46 @@ button[aria-busy="true"]:is([data-card-bump], [data-bump]) svg { fill: currentCo
|
|
|
756
872
|
.rv-links a { color: var(--accent); text-decoration: none; }
|
|
757
873
|
.rv-acts { display: flex; flex-wrap: wrap; gap: 8px; }
|
|
758
874
|
.view-questions .bar #qstatus .try-spin { color: var(--accent); margin-right: 6px; }
|
|
875
|
+
|
|
876
|
+
/* Needs you (app-needs.js): a deck at the top of the board on a phone; from 900px a pane beside the lanes, its lines over
|
|
877
|
+
Waiting on you (docs/adr/2026-11-05-0408-needs-you-is-a-deck-on-a-phone-and-a-pane-on-a-desktop.md). */
|
|
878
|
+
.needs-pane { display: none; }
|
|
879
|
+
.needs-deck { margin: 0 0 12px; border: 1px solid color-mix(in srgb, var(--color-notice) 45%, var(--line)); border-radius: 14px;
|
|
880
|
+
background: color-mix(in srgb, var(--color-notice) 7%, var(--panel)); overflow: hidden; }
|
|
881
|
+
.deck-head { display: flex; align-items: center; gap: 8px; padding: 10px 14px 4px; }
|
|
882
|
+
.deck-head h2 { margin: 0; flex: 1; font-size: 12px; text-transform: uppercase; letter-spacing: .05em; color: var(--color-notice); }
|
|
883
|
+
.deck-n { min-width: 20px; padding: 1px 7px; border-radius: 999px; background: var(--color-notice); color: #1c1407; font-size: 12px; font-weight: 700; text-align: center; }
|
|
884
|
+
.deck-card { padding: 2px 14px 12px; min-width: 0; overflow-wrap: anywhere; }
|
|
885
|
+
.deck-what { margin: 0 0 2px; font-size: 12px; color: var(--muted); }
|
|
886
|
+
.deck-card h3 { margin: 0 0 4px; font-size: 15px; line-height: 1.3; }
|
|
887
|
+
.deck-card h3 a { color: inherit; text-decoration: none; }
|
|
888
|
+
.deck-card .ctx { margin: 0 0 10px; font-size: 13px; color: var(--muted); }
|
|
889
|
+
.deck-proto { margin: 0 0 10px; color: var(--accent); }
|
|
890
|
+
.deck-opts { display: flex; flex-direction: column; gap: 6px; }
|
|
891
|
+
.deck-opts button { text-align: left; border-radius: 10px; padding: 10px 12px; font-size: 14px; }
|
|
892
|
+
.deck-opts button.rec { border-color: var(--accent); }
|
|
893
|
+
.deck-opts .rec-word { color: var(--accent); font-weight: 500; font-size: 12px; margin-left: 4px; }
|
|
894
|
+
.deck-opts small { display: block; color: var(--muted); font-size: 12.5px; }
|
|
895
|
+
.deck-prompt { margin: 0; padding: 0; list-style: none; }
|
|
896
|
+
.deck-prompt li.prompt { padding: 8px 10px; background: var(--panel); border: 1px solid var(--line); border-radius: 8px; }
|
|
897
|
+
.deck-acts { display: flex; flex-wrap: wrap; gap: 8px; }
|
|
898
|
+
.deck-bar { display: flex; align-items: center; gap: 10px; padding: 0 14px 10px; }
|
|
899
|
+
.deck-dots { flex: 1; display: flex; flex-wrap: wrap; gap: 5px; }
|
|
900
|
+
.deck-dots i { width: 7px; height: 7px; border-radius: 50%; background: var(--line); }
|
|
901
|
+
.deck-dots i.on { background: var(--color-notice); }
|
|
902
|
+
.deck-bar button { border-radius: 999px; padding: 5px 12px; font-size: 13px; }
|
|
903
|
+
.deck-more { display: flex; align-items: center; justify-content: space-between; min-height: 46px; padding: 10px 14px; border-top: 1px solid color-mix(in srgb, var(--color-notice) 28%, var(--line));
|
|
904
|
+
background: color-mix(in srgb, var(--color-notice) 14%, var(--panel)); color: var(--text); font-weight: 600; font-size: 14px; text-decoration: none; }
|
|
905
|
+
.deck-more::after { content: '›'; color: var(--accent); font-size: 18px; }
|
|
906
|
+
@media (min-width: 900px) {
|
|
907
|
+
.split { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: start; }
|
|
908
|
+
.split > main { max-width: none; margin: 0; }
|
|
909
|
+
.needs-deck { display: none; }
|
|
910
|
+
/* The board's + sits at the bottom right of the left pane: the pane ends at the middle of the space right of the sidebar. */
|
|
911
|
+
.view-board .fab { right: calc(50% - var(--sidebar-w, 0px) / 2 + var(--fab-edge)); }
|
|
912
|
+
body.has-sidebar { --sidebar-w: 272px; }
|
|
913
|
+
html.sb-collapsed body.has-sidebar { --sidebar-w: 0px; }
|
|
914
|
+
.needs-pane { display: block; position: sticky; top: 56px; height: calc(100vh - 56px); overflow-y: auto; overscroll-behavior: contain; padding: 12px 16px 24px; border-left: 1px solid var(--line); }
|
|
915
|
+
.needs-pane .needs-questions main { padding: 0; max-width: none; }
|
|
916
|
+
.needs-pane .waiting { margin: 0 0 12px; }
|
|
917
|
+
}
|