@1agh/maude 0.51.1 → 0.52.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.
Files changed (48) hide show
  1. package/apps/studio/api.ts +389 -14
  2. package/apps/studio/bin/_video-playwright.mjs +15 -6
  3. package/apps/studio/canvas-edit.ts +141 -20
  4. package/apps/studio/canvas-lib.tsx +61 -0
  5. package/apps/studio/client/app.jsx +824 -121
  6. package/apps/studio/client/panels/ClipInspector.jsx +409 -0
  7. package/apps/studio/client/panels/CloudBar.jsx +12 -2
  8. package/apps/studio/client/panels/TimelinePanel.jsx +1775 -430
  9. package/apps/studio/client/panels/timeline-media-cache.js +274 -0
  10. package/apps/studio/client/panels/timeline-parse.js +46 -1
  11. package/apps/studio/client/panels/timeline-scale.js +64 -0
  12. package/apps/studio/client/report-bug.jsx +15 -15
  13. package/apps/studio/client/styles/3-shell-maude.css +446 -3
  14. package/apps/studio/client/styles/4-components-maude.css +55 -0
  15. package/apps/studio/client/styles/4-components.css +0 -83
  16. package/apps/studio/clip-ops.ts +1980 -0
  17. package/apps/studio/cloud/endpoints.ts +88 -17
  18. package/apps/studio/credential-grammar.ts +100 -0
  19. package/apps/studio/debug-bundle.ts +12 -0
  20. package/apps/studio/dist/client.bundle.js +2048 -2048
  21. package/apps/studio/dist/styles.css +1 -1
  22. package/apps/studio/exporters/video.ts +49 -10
  23. package/apps/studio/http.ts +113 -6
  24. package/apps/studio/ripple.ts +335 -0
  25. package/apps/studio/sync/hub-link.ts +3 -3
  26. package/apps/studio/sync/hubs-config.ts +32 -0
  27. package/apps/studio/sync/workspace-signin.ts +8 -4
  28. package/apps/studio/test/_helpers.ts +5 -3
  29. package/apps/studio/test/canvas-create-api.test.ts +8 -2
  30. package/apps/studio/test/canvas-origin-gate.test.ts +20 -0
  31. package/apps/studio/test/clip-addressing.test.ts +7 -6
  32. package/apps/studio/test/clip-ops.test.ts +836 -0
  33. package/apps/studio/test/cloud-endpoints.test.ts +37 -2
  34. package/apps/studio/test/comments-api.test.ts +49 -0
  35. package/apps/studio/test/credential-grammar.test.ts +107 -0
  36. package/apps/studio/test/read-only-role.test.ts +95 -0
  37. package/apps/studio/test/ripple.test.ts +197 -0
  38. package/apps/studio/test/timeline-scale.test.ts +65 -0
  39. package/apps/studio/test/workspace-signin.test.ts +4 -1
  40. package/apps/studio/whats-new.json +35 -0
  41. package/cli/commands/share.mjs +8 -4
  42. package/cli/lib/ddr-to-kgai.mjs +6 -1
  43. package/cli/lib/ddr-to-kgai.test.mjs +1 -2
  44. package/cli/lib/hubs-config.mjs +15 -1
  45. package/cli/lib/hubs-config.test.mjs +19 -0
  46. package/cli/lib/share-plan.mjs +5 -1
  47. package/cli/lib/share-plan.test.mjs +11 -2
  48. package/package.json +8 -8
@@ -1680,6 +1680,240 @@ body.st-scrubbing, body.st-scrubbing * { cursor: ew-resize !important; user-sele
1680
1680
  .tl-title { font-family: var(--font-display); font-weight: 600; font-size: var(--type-md); color: var(--fg-0); }
1681
1681
  .tl-spacer { flex: 1; }
1682
1682
  .tl-meta { font-family: var(--font-mono); font-size: var(--type-xs); color: var(--fg-2); white-space: nowrap; }
1683
+ /* Task 4 — zoom slider in the transport head. */
1684
+ .tl-zoom { width: 90px; accent-color: var(--accent); }
1685
+ /* Task 4 — labels stay pinned while the scaled track scrolls horizontally. */
1686
+ .tl-row-label { position: sticky; left: 0; z-index: 3; background: var(--bg-1); }
1687
+ /* Task 5 — the three-band storyline layout. */
1688
+ .tl-band-tag {
1689
+ font-family: var(--font-mono);
1690
+ font-size: 9px;
1691
+ letter-spacing: 0.08em;
1692
+ text-transform: uppercase;
1693
+ color: var(--fg-3);
1694
+ }
1695
+ .tl-band-tag--story { color: var(--fg-1); font-weight: 600; }
1696
+ .tl-row--storyline { height: 44px; }
1697
+ .tl-row--overlay { height: 24px; }
1698
+ .tl-row--overlay .tl-seq-block { top: 2px; bottom: 2px; }
1699
+ .tl-storyline-track .tl-seq-block.tl-beat { border-radius: 0; border-right-width: 0; }
1700
+ .tl-storyline-track .tl-seq-block.tl-beat:first-child { border-top-left-radius: var(--radius-sm); border-bottom-left-radius: var(--radius-sm); }
1701
+ /* ⧓ seam chip between storyline beats (read-only until transition edit lands). */
1702
+ .tl-seam {
1703
+ position: absolute;
1704
+ top: 50%;
1705
+ transform: translateY(-50%);
1706
+ width: 24px;
1707
+ height: 24px;
1708
+ display: grid;
1709
+ place-items: center;
1710
+ border-radius: 50%;
1711
+ background: var(--bg-0);
1712
+ border: 1px solid var(--accent-muted, var(--accent));
1713
+ color: var(--fg-1);
1714
+ font-size: 13px;
1715
+ line-height: 1;
1716
+ padding: 0;
1717
+ cursor: pointer;
1718
+ z-index: 2;
1719
+ pointer-events: auto;
1720
+ transition: transform var(--dur-1, 120ms) var(--ease-out, ease), border-color var(--dur-1, 120ms) ease;
1721
+ }
1722
+ .tl-seam:hover { transform: translateY(-50%) scale(1.12); border-color: var(--accent); color: var(--accent); }
1723
+ /* WKWebView-safe shell prompt modal (window.prompt is a no-op in Tauri). */
1724
+ .st-prompt { width: 420px; max-width: 90vw; }
1725
+ .st-prompt .st-input {
1726
+ width: 100%;
1727
+ box-sizing: border-box;
1728
+ padding: 8px 10px;
1729
+ border-radius: var(--radius-sm);
1730
+ border: 1px solid var(--bg-3);
1731
+ background: var(--bg-0);
1732
+ color: var(--fg-0);
1733
+ font-size: var(--type-sm);
1734
+ outline: none;
1735
+ }
1736
+ .st-prompt .st-input:focus { border-color: var(--accent); }
1737
+ /* Task 23 — timeline comment pins (💬 strip above the ruler). */
1738
+ .tl-comments-strip { position: absolute; top: -2px; left: 0; right: 0; height: 18px; z-index: 5; pointer-events: none; }
1739
+ .tl-comment-pin {
1740
+ position: absolute;
1741
+ top: 0;
1742
+ width: 16px;
1743
+ height: 16px;
1744
+ display: grid;
1745
+ place-items: center;
1746
+ border: none;
1747
+ background: none;
1748
+ font-size: 11px;
1749
+ cursor: pointer;
1750
+ pointer-events: auto;
1751
+ filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.4));
1752
+ }
1753
+ .tl-comment-pin.is-resolved { opacity: 0.4; }
1754
+ .tl-comment-pin.is-detached::after {
1755
+ content: '!';
1756
+ position: absolute;
1757
+ top: -3px;
1758
+ right: -3px;
1759
+ font-size: 8px;
1760
+ color: #ef4444;
1761
+ font-weight: 700;
1762
+ }
1763
+ .tlci-comment-text { margin: 0; font-size: var(--type-sm); color: var(--fg-0); line-height: 1.5; white-space: pre-wrap; }
1764
+ /* Task 21 — AI placeholder blocks: dashed accent slate. */
1765
+ .tl-seq-block[data-kind="placeholder"] {
1766
+ border-style: dashed;
1767
+ border-color: var(--accent);
1768
+ background: color-mix(in oklab, var(--accent) 12%, var(--bg-2));
1769
+ }
1770
+ .tl-kind[data-kind="placeholder"] { color: var(--accent); background: color-mix(in oklab, var(--accent) 18%, var(--bg-3)); }
1771
+ /* Task 17 — "+" affordance on hard-cut seams. Sits ABOVE the lane so it never
1772
+ collides with trim handles / replace buttons at block edges. */
1773
+ .tl-seam-add {
1774
+ opacity: 0;
1775
+ top: -12px;
1776
+ transform: none;
1777
+ width: 22px;
1778
+ height: 22px;
1779
+ cursor: pointer;
1780
+ background: var(--bg-1);
1781
+ transition: opacity var(--dur-1, 120ms) ease, border-color var(--dur-1, 120ms) ease;
1782
+ }
1783
+ .tl-seam-add svg { display: block; }
1784
+ .tl-storyline-track:hover .tl-seam-add { opacity: 0.85; }
1785
+ .tl-seam-add:hover { opacity: 1; transform: none; border-color: var(--accent); color: var(--accent); }
1786
+ /* Inspector text tab */
1787
+ .tlci-textarea {
1788
+ width: 100%;
1789
+ box-sizing: border-box;
1790
+ resize: vertical;
1791
+ padding: 6px 8px;
1792
+ border-radius: var(--radius-sm);
1793
+ border: 1px solid var(--bg-3);
1794
+ background: var(--bg-0);
1795
+ color: var(--fg-0);
1796
+ font-size: var(--type-sm);
1797
+ font-family: inherit;
1798
+ }
1799
+ .tlci-textarea:focus { outline: none; border-color: var(--accent); }
1800
+ /* Task 9 — the clip inspector popover (Speed · Audio · Crop · Grade · Transition). */
1801
+ .tlci {
1802
+ position: fixed;
1803
+ z-index: 90;
1804
+ width: 264px;
1805
+ background: var(--bg-1);
1806
+ border: 1px solid var(--bg-3);
1807
+ border-radius: var(--radius-md);
1808
+ box-shadow: 0 12px 32px rgba(0, 0, 0, 0.35);
1809
+ font-size: var(--type-sm);
1810
+ }
1811
+ /* DS voice (components-inspector-controls / .st-cp-*): mono uppercase micro-
1812
+ labels, hairline --border-subtle separations, squared segments over pill
1813
+ chips, --accent-tint for the active state (dogfood 2026-07-30, image #30). */
1814
+ .tlci-head { display: flex; align-items: center; gap: var(--space-2); padding: 7px 10px; cursor: grab; border-bottom: 1px solid var(--border-subtle, var(--bg-3)); }
1815
+ .tlci-title { font-family: var(--font-mono); font-size: var(--type-xs); text-transform: uppercase; letter-spacing: var(--tracking-wide, 0.08em); color: var(--fg-2); flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1816
+ .tlci-x { border: none; background: none; color: var(--fg-2); font-size: 14px; cursor: pointer; padding: 0 4px; }
1817
+ .tlci-x:hover { color: var(--fg-0); }
1818
+ .tlci-tabs { display: flex; margin: 8px 10px 0; border: 1px solid var(--border-subtle, var(--bg-3)); border-radius: var(--radius-sm); overflow: hidden; background: var(--bg-2); }
1819
+ .tlci-tab { flex: 1; border: none; border-right: 1px solid var(--border-subtle, var(--bg-3)); background: transparent; color: var(--fg-2); font-family: var(--font-mono); font-size: var(--type-xs); text-transform: lowercase; padding: 5px 2px; cursor: pointer; }
1820
+ .tlci-tab:last-child { border-right: 0; }
1821
+ .tlci-tab:hover:not(.is-on) { background: var(--bg-4, var(--bg-3)); }
1822
+ .tlci-tab.is-on { background: var(--accent-tint, var(--bg-3)); color: var(--fg-0); }
1823
+ .tlci-body { padding: 10px; display: flex; flex-direction: column; gap: 8px; }
1824
+ .tlci-row { display: flex; align-items: center; gap: 8px; }
1825
+ .tlci-lbl { width: 76px; flex: none; color: var(--fg-2); font-family: var(--font-mono); font-size: var(--type-xs); text-transform: uppercase; letter-spacing: var(--tracking-wide, 0.08em); }
1826
+ .tlci-presets { display: flex; flex-wrap: wrap; gap: 4px; }
1827
+ .tlci-chip { border: 1px solid var(--border-subtle, var(--bg-3)); background: var(--bg-2); color: var(--fg-1); font-family: var(--font-mono); font-size: var(--type-xs); padding: 3px 8px; border-radius: var(--radius-sm); cursor: pointer; }
1828
+ .tlci-chip:hover:not(.is-on) { background: var(--bg-4, var(--bg-3)); color: var(--fg-0); }
1829
+ .tlci-chip.is-on { background: var(--accent-tint, var(--bg-3)); border-color: var(--accent); color: var(--fg-0); }
1830
+ .tlci-btn { border: 1px solid var(--border-subtle, var(--bg-3)); background: var(--bg-2); color: var(--fg-0); font-family: var(--font-mono); font-size: var(--type-xs); padding: 5px 10px; border-radius: var(--radius-sm); cursor: pointer; align-self: flex-start; }
1831
+ .tlci-btn:hover { border-color: var(--accent); background: var(--bg-4, var(--bg-3)); }
1832
+ .tlci-note { margin: 0; color: var(--fg-3); font-size: 10px; line-height: 1.5; }
1833
+ /* Phase 2 — block chips (speed / mute) + the left in-point trim handle. */
1834
+ .tl-chip { position: relative; z-index: 1; font-family: var(--font-mono); font-size: 9px; padding: 0 4px; border-radius: 3px; background: var(--bg-0); color: var(--fg-1); border: 1px solid var(--bg-3); margin-right: 3px; }
1835
+ .tl-seq-trim-in {
1836
+ position: absolute;
1837
+ top: 0;
1838
+ bottom: 0;
1839
+ width: 7px;
1840
+ cursor: ew-resize;
1841
+ z-index: 3;
1842
+ border-radius: 2px;
1843
+ }
1844
+ .tl-seq-trim-in:hover { background: color-mix(in oklab, var(--accent) 50%, transparent); }
1845
+ /* Task 8 — live trim/move delta tooltip; red at a clamp (source bounds / 1f). */
1846
+ .tl-trim-tip {
1847
+ position: absolute;
1848
+ top: -20px;
1849
+ padding: 1px 6px;
1850
+ border-radius: 4px;
1851
+ background: var(--bg-0);
1852
+ border: 1px solid var(--accent-muted, var(--accent));
1853
+ color: var(--fg-0);
1854
+ font-family: var(--font-mono);
1855
+ font-size: 10px;
1856
+ white-space: nowrap;
1857
+ z-index: 6;
1858
+ pointer-events: none;
1859
+ }
1860
+ .tl-trim-tip.is-clamped { border-color: #ef4444; color: #ef4444; }
1861
+ /* Task 7 — filmstrip thumbnails behind the clip label + real waveforms. */
1862
+ .tl-strip {
1863
+ position: absolute;
1864
+ inset: 0;
1865
+ display: flex;
1866
+ overflow: hidden;
1867
+ border-radius: inherit;
1868
+ opacity: 0.55;
1869
+ pointer-events: none;
1870
+ }
1871
+ .tl-strip img { flex: 1 1 0; min-width: 0; object-fit: cover; height: 100%; }
1872
+ .tl-seq-block .tl-kind, .tl-seq-block .tl-seq-name { position: relative; z-index: 1; }
1873
+ .tl-wave-real { fill: currentColor; stroke: none; opacity: 0.85; }
1874
+ /* Task 6 — magnetic reorder: siblings glide to their preview slots, the
1875
+ dragged beat floats above. */
1876
+ /* superseded by the tokenised rule below */
1877
+ .tl-seq-block.is-dragging { z-index: 4; opacity: 0.85; cursor: grabbing; }
1878
+ /* Task 6 — file-drop insertion caret. */
1879
+ .tl-drop-caret {
1880
+ position: absolute;
1881
+ top: -2px;
1882
+ bottom: -2px;
1883
+ width: 2px;
1884
+ background: var(--accent);
1885
+ border-radius: 1px;
1886
+ z-index: 5;
1887
+ pointer-events: none;
1888
+ }
1889
+ .tl-drop-caret::before {
1890
+ content: '';
1891
+ position: absolute;
1892
+ top: -3px;
1893
+ left: -3px;
1894
+ width: 8px;
1895
+ height: 8px;
1896
+ border-radius: 50%;
1897
+ background: var(--accent);
1898
+ }
1899
+ /* Task 3 — selected clip: the same accent outline vocabulary as canvas
1900
+ selection, so "selected" means one thing everywhere. */
1901
+ .tl-seq-block.is-selected {
1902
+ outline: 2px solid var(--accent);
1903
+ outline-offset: -1px;
1904
+ z-index: 2;
1905
+ }
1906
+ /* Long-comp badge — comp length beyond the 900-frame safe export tier. */
1907
+ .tl-long-badge {
1908
+ font-family: var(--font-mono);
1909
+ font-size: var(--type-xs);
1910
+ color: var(--accent);
1911
+ border: 1px solid color-mix(in oklab, var(--accent) 45%, transparent);
1912
+ border-radius: 4px;
1913
+ padding: 0 6px;
1914
+ white-space: nowrap;
1915
+ cursor: help;
1916
+ }
1683
1917
  .tl-x { appearance: none; border: none; background: transparent; color: var(--fg-2); font-size: 16px; line-height: 1; cursor: pointer; padding: 2px 6px; border-radius: var(--radius-xs); }
1684
1918
  .tl-x:hover { color: var(--fg-1); background: var(--bg-3); }
1685
1919
  .tl-empty { padding: var(--space-4); color: var(--fg-2); font-size: var(--type-sm); line-height: 1.5; }
@@ -1976,15 +2210,16 @@ body.st-scrubbing, body.st-scrubbing * { cursor: ew-resize !important; user-sele
1976
2210
  /* text inputs — the maude DS .input/.textarea recipe (lifted from the canvas-side
1977
2211
  * _components.css, which isn't in the client bundle → my fields fell back to native).
1978
2212
  * Scoped to the github dialogs so it can't collide with the shell's .st-search/.st-field. */
1979
- .gi-dialog .input, .cp-dialog .input, .gi-dialog .textarea, .cp-dialog .textarea {
2213
+ .gi-dialog .input, .cp-dialog .input, .gi-dialog .textarea, .cp-dialog .textarea, .rb-dialog .textarea {
1980
2214
  font-family: var(--font-body); font-size: var(--type-sm); color: var(--fg-0);
1981
2215
  background: var(--bg-3); border: 1px solid var(--border-default); border-radius: var(--radius-sm);
1982
2216
  padding: var(--space-3) var(--space-4); width: 100%;
1983
2217
  transition: border-color var(--dur-soft) var(--ease-out), box-shadow var(--dur-soft) var(--ease-out);
1984
2218
  }
1985
2219
  .gi-dialog .input::placeholder, .cp-dialog .input::placeholder,
1986
- .gi-dialog .textarea::placeholder, .cp-dialog .textarea::placeholder { color: var(--fg-3); }
1987
- .gi-dialog .input:focus, .cp-dialog .input:focus, .gi-dialog .textarea:focus, .cp-dialog .textarea:focus {
2220
+ .gi-dialog .textarea::placeholder, .cp-dialog .textarea::placeholder,
2221
+ .rb-dialog .textarea::placeholder { color: var(--fg-3); }
2222
+ .gi-dialog .input:focus, .cp-dialog .input:focus, .gi-dialog .textarea:focus, .cp-dialog .textarea:focus, .rb-dialog .textarea:focus {
1988
2223
  outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-tint);
1989
2224
  }
1990
2225
  .cp-dialog .textarea { resize: vertical; min-height: 76px; }
@@ -2405,3 +2640,211 @@ body.st-scrubbing, body.st-scrubbing * { cursor: ew-resize !important; user-sele
2405
2640
  }
2406
2641
 
2407
2642
  }
2643
+
2644
+ /* ── enhanced-video-editing visual pass (FCP/iMovie proportions) ──────────── */
2645
+ .tl-row--storyline { height: 64px; }
2646
+ .tl-row--overlay { height: 36px; }
2647
+ .tl-row--overlay .tl-seq-block { top: 3px; bottom: 3px; }
2648
+ .tl-storyline-track .tl-seq-block { border-radius: 6px; }
2649
+ .tl-storyline-track .tl-seq-block.tl-beat { border-right: 1px solid var(--bg-0); }
2650
+ /* Filmstrip fills the block; identity moves into a small scrimmed chip. */
2651
+ .tl-strip { opacity: 1; }
2652
+ .tl-seq-block .tl-seq-name {
2653
+ position: absolute;
2654
+ left: 6px;
2655
+ bottom: 4px;
2656
+ max-width: calc(100% - 12px);
2657
+ overflow: hidden;
2658
+ text-overflow: ellipsis;
2659
+ white-space: nowrap;
2660
+ font-size: 10px;
2661
+ padding: 1px 6px;
2662
+ border-radius: 3px;
2663
+ background: rgba(0, 0, 0, 0.55);
2664
+ color: #fff;
2665
+ z-index: 1;
2666
+ }
2667
+ .tl-seq-block .tl-kind { position: absolute; top: 4px; left: 6px; z-index: 1; }
2668
+ /* Overlay layers read FCP-purple; audio stays green via data-kind. */
2669
+ .tl-row--overlay .tl-seq-block[data-kind="video"],
2670
+ .tl-row--overlay .tl-seq-block[data-kind="image"] {
2671
+ border-color: color-mix(in oklch, #8b5cf6 55%, var(--accent-muted));
2672
+ background: color-mix(in oklch, #8b5cf6 16%, var(--bg-2));
2673
+ }
2674
+ /* Ruler: quieter frame ticks, prominent second ticks. */
2675
+ .tl-ruler { height: 20px; border-bottom: 1px solid var(--bg-3); }
2676
+ .tl-tick { background: none; bottom: auto; width: 0; border-left: 1px solid var(--bg-3); height: 6px; top: 14px; }
2677
+ .tl-tick.is-major { height: 12px; top: 8px; border-left-color: var(--fg-3); }
2678
+ .tl-tick-label { top: -12px; left: 3px; font-size: 9px; color: var(--fg-3); }
2679
+ .tl-tick.is-major .tl-tick-label { color: var(--fg-2); }
2680
+ /* Playhead: strong line + grab head, FCP style. */
2681
+ .tl-playhead { width: 2px; background: var(--accent); }
2682
+ .tl-playhead::before {
2683
+ content: '';
2684
+ position: absolute;
2685
+ top: -1px;
2686
+ left: -5px;
2687
+ width: 12px;
2688
+ height: 10px;
2689
+ background: var(--accent);
2690
+ clip-path: polygon(0 0, 100% 0, 100% 45%, 50% 100%, 0 45%);
2691
+ }
2692
+ .tl-tracks { padding-top: 24px; min-height: 100%; }
2693
+
2694
+ /* ── Debate-driven UX pass: figure/ground, identity, predictive feedback ──── */
2695
+ /* One dominant lane: the storyline is an inset trough; overlays recede. */
2696
+ .tl-storyline-track {
2697
+ background: color-mix(in oklab, var(--fg-0) 7%, var(--bg-2));
2698
+ box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.18);
2699
+ border-radius: var(--radius-sm);
2700
+ }
2701
+ .tl-row--overlay .tl-row-track { background: color-mix(in oklab, var(--bg-2) 55%, var(--bg-1)); }
2702
+ .tl-row--audio .tl-row-track { background: color-mix(in oklab, #22c55e 6%, var(--bg-1)); }
2703
+ /* Blocks read as physical objects: stronger fill + inner top highlight. */
2704
+ .tl-seq-block {
2705
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.28), 0 1px 2px rgba(0, 0, 0, 0.12);
2706
+ }
2707
+ .tl-storyline-track .tl-seq-block.tl-beat {
2708
+ background: color-mix(in oklab, #0ea5e9 22%, var(--bg-1));
2709
+ border-color: color-mix(in oklab, #0ea5e9 60%, var(--bg-3));
2710
+ }
2711
+ /* Lane identity: V1/V2/A1 chips in a left-aligned gutter. */
2712
+ .tl-row-label { justify-content: flex-start; padding-left: 6px; gap: 5px; }
2713
+ .tl-lane-id {
2714
+ font-family: var(--font-mono);
2715
+ font-size: 9px;
2716
+ font-weight: 700;
2717
+ color: var(--fg-2);
2718
+ border: 1px solid var(--bg-3);
2719
+ border-radius: 3px;
2720
+ padding: 0 4px;
2721
+ background: var(--bg-2);
2722
+ }
2723
+ .tl-lane-id--story { color: var(--fg-0); border-color: var(--accent); background: color-mix(in oklab, var(--accent) 14%, var(--bg-2)); }
2724
+ .tl-lane-id--audio { color: #15803d; border-color: color-mix(in oklab, #22c55e 45%, var(--bg-3)); }
2725
+ /* Dogfood 2026-07-30 — vertical layer reorder: the V-chip is the drag handle. */
2726
+ .tl-lane-id--grab { cursor: grab; touch-action: none; }
2727
+ .tl-lane-id--grab:hover { border-color: var(--accent); color: var(--fg-0); }
2728
+ .tl-row.is-layer-dragging { opacity: 0.6; }
2729
+ .tl-row.is-layer-dragging .tl-lane-id--grab { cursor: grabbing; }
2730
+ .tl-row.is-layer-target {
2731
+ box-shadow: inset 0 0 0 1px var(--accent);
2732
+ background: color-mix(in oklab, var(--accent) 8%, transparent);
2733
+ }
2734
+ /* Comment tool armed: the whole track area places pins. */
2735
+ .tl-panel.is-commenting .tl-row-track,
2736
+ .tl-panel.is-commenting .tl-seq-block,
2737
+ .tl-panel.is-commenting .tl-ruler { cursor: crosshair; }
2738
+ /* In-place 💬 badge pinned ON a clip at the comment's frame offset. */
2739
+ .tl-clip-pin {
2740
+ position: absolute;
2741
+ top: -7px;
2742
+ width: 16px;
2743
+ height: 16px;
2744
+ display: grid;
2745
+ place-items: center;
2746
+ font-size: 11px;
2747
+ line-height: 1;
2748
+ cursor: pointer;
2749
+ z-index: 4;
2750
+ filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.45));
2751
+ }
2752
+ .tl-clip-pin.is-resolved { opacity: 0.4; }
2753
+ /* Expand chevron on a decomposable storyline beat (old scene components). */
2754
+ .tl-beat-expand {
2755
+ position: absolute;
2756
+ left: 3px;
2757
+ top: 3px;
2758
+ width: 15px;
2759
+ height: 15px;
2760
+ display: grid;
2761
+ place-items: center;
2762
+ font-size: 9px;
2763
+ color: var(--fg-2);
2764
+ background: color-mix(in oklab, var(--bg-0) 70%, transparent);
2765
+ border-radius: 3px;
2766
+ cursor: pointer;
2767
+ z-index: 3;
2768
+ }
2769
+ .tl-beat-expand:hover { color: var(--fg-0); background: var(--bg-0); }
2770
+ /* Image overlays show the still itself. */
2771
+ .tl-strip--img img { flex: 1 1 auto; width: 100%; object-fit: cover; }
2772
+ /* Dragged beat LIFTS (grabbing hand, shadow, slight scale) — compositor-only. */
2773
+ .tl-seq-block.is-dragging {
2774
+ cursor: grabbing;
2775
+ opacity: 0.95;
2776
+ transform: scale(1.02);
2777
+ box-shadow: 0 6px 18px rgba(0, 0, 0, 0.3);
2778
+ z-index: 6;
2779
+ }
2780
+ /* Neighbour shuffle + drops ride the DS motion tokens, not hardcoded ms. */
2781
+ .tl-storyline-track.is-reordering .tl-seq-block:not(.is-dragging) {
2782
+ transition: left var(--dur-2, 160ms) var(--ease-out, ease-out);
2783
+ }
2784
+ /* Vertical layer-move target: the storyline glows while a clip hovers over it. */
2785
+ .tl-storyline-track.is-drop-target {
2786
+ outline: 2px dashed var(--accent);
2787
+ outline-offset: -2px;
2788
+ background: color-mix(in oklab, var(--accent) 10%, var(--bg-2));
2789
+ }
2790
+ /* Snap confirmation: momentary accent rule at the latched frame. */
2791
+ .tl-snapline {
2792
+ position: absolute;
2793
+ top: 18px;
2794
+ bottom: 0;
2795
+ width: 1px;
2796
+ background: var(--accent);
2797
+ box-shadow: 0 0 6px var(--accent);
2798
+ z-index: 5;
2799
+ pointer-events: none;
2800
+ animation: tl-snap-pulse 0.35s var(--ease-out, ease-out);
2801
+ }
2802
+ @keyframes tl-snap-pulse {
2803
+ 0% { opacity: 1; }
2804
+ 100% { opacity: 0.25; }
2805
+ }
2806
+ /* Playhead carries its own timecode. */
2807
+ .tl-playhead-time {
2808
+ position: absolute;
2809
+ top: -2px;
2810
+ left: 8px;
2811
+ font-family: var(--font-mono);
2812
+ font-size: 9px;
2813
+ color: var(--bg-0);
2814
+ background: var(--accent);
2815
+ border-radius: 3px;
2816
+ padding: 0 4px;
2817
+ white-space: nowrap;
2818
+ }
2819
+ /* Affordances visible at REST (promote on hover) — zero-opacity told nothing. */
2820
+ .tl-seq-resize, .tl-seq-trim-in {
2821
+ opacity: 0.35;
2822
+ background: color-mix(in oklab, var(--fg-0) 18%, transparent);
2823
+ border-radius: 2px;
2824
+ }
2825
+ .tl-seq-resize:hover, .tl-seq-trim-in:hover { opacity: 1; background: var(--accent); }
2826
+ .tl-seam { opacity: 0.8; }
2827
+ /* The dead space below the lanes IS the new-layer drop target. */
2828
+ .tl-newlayer-zone {
2829
+ flex: 1;
2830
+ min-height: 44px;
2831
+ margin-top: 6px;
2832
+ border: 1.5px dashed var(--bg-3);
2833
+ border-radius: var(--radius-sm);
2834
+ display: flex;
2835
+ align-items: center;
2836
+ color: var(--fg-3);
2837
+ font-size: var(--type-xs);
2838
+ font-family: var(--font-mono);
2839
+ transition: border-color var(--dur-2, 160ms) var(--ease-out, ease-out), background var(--dur-2, 160ms) var(--ease-out, ease-out);
2840
+ }
2841
+ .tl-newlayer-zone.is-active, .tl-panel.is-drop .tl-newlayer-zone {
2842
+ border-color: var(--accent);
2843
+ color: var(--fg-1);
2844
+ background: color-mix(in oklab, var(--accent) 7%, transparent);
2845
+ }
2846
+ @media (prefers-reduced-motion: reduce) {
2847
+ .tl-snapline { animation: none; }
2848
+ .tl-storyline-track.is-reordering .tl-seq-block:not(.is-dragging) { transition: none; }
2849
+ .tl-newlayer-zone { transition: none; }
2850
+ }
@@ -71,4 +71,59 @@
71
71
  .maude .callout--warn { border-left-color: var(--status-warn); }
72
72
  .maude .callout--error { border-left-color: var(--status-error); }
73
73
 
74
+ /* ── Report-a-Bug dialog (feature-bug-report-button) ─────────────────────────
75
+ * Rides the shared .st-scrim/.st-dialog shell (3-shell-maude.css); rb-* covers
76
+ * only what the shell doesn't: the consent checklist, screenshot tiles, and
77
+ * the redaction overlay. Same DS voice as the generate/github dialogs —
78
+ * body-font copy, mono uppercase section heads, accent focus rings. */
79
+ .rb-dialog { width: 560px; }
80
+ .rb-dialog .rb-body { max-height: 68vh; overflow-y: auto; }
81
+ .rb-dialog .rb-label { font-family: var(--font-body); font-size: var(--type-sm); font-weight: 600; color: var(--fg-0); }
82
+ /* base field styling joins the shared .gi-dialog/.cp-dialog recipe in
83
+ * 3-shell-maude.css (F3 — one source for field + focus ring); only the
84
+ * rb-specific sizing lives here. */
85
+ .rb-dialog .textarea { resize: vertical; min-height: 96px; }
86
+ .rb-dialog .rb-hint { font-family: var(--font-body); font-size: var(--type-xs); color: var(--fg-2); margin: 0; }
87
+ .rb-dialog .rb-error { font-family: var(--font-body); font-size: var(--type-sm); color: var(--status-error); margin: 0; }
88
+ .rb-dialog .rb-section { display: flex; flex-direction: column; gap: var(--space-2); }
89
+ .rb-dialog .rb-section-hd {
90
+ display: flex; align-items: center; justify-content: space-between;
91
+ font-family: var(--font-mono); font-size: var(--type-xs);
92
+ letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--fg-2);
93
+ }
94
+ .rb-dialog .rb-check { display: flex; gap: var(--space-3); align-items: baseline; cursor: pointer; font-family: var(--font-body); font-size: var(--type-sm); color: var(--fg-1); }
95
+ .rb-dialog .rb-check input { accent-color: var(--accent); }
96
+ .rb-dialog .rb-check code { font-family: var(--font-mono); font-size: var(--type-xs); color: var(--fg-0); background: var(--bg-3); border-radius: var(--radius-xs); padding: 1px 5px; overflow-wrap: anywhere; }
97
+ .rb-dialog .rb-details summary { cursor: pointer; color: var(--fg-2); font-size: var(--type-xs); }
98
+ .rb-dialog .rb-log {
99
+ max-height: 160px; overflow: auto; margin: var(--space-2) 0 0;
100
+ font-family: var(--font-mono); font-size: var(--type-xs); color: var(--fg-1);
101
+ background: var(--bg-0); border: 1px solid var(--border-subtle); border-radius: var(--radius-sm);
102
+ padding: var(--space-3); white-space: pre-wrap; word-break: break-all;
103
+ }
104
+ .rb-dialog .rb-shots { display: flex; flex-wrap: wrap; gap: var(--space-3); }
105
+ .rb-dialog .rb-shot { display: flex; flex-direction: column; gap: var(--space-1); }
106
+ .rb-dialog .rb-shot-box {
107
+ position: relative; max-width: 260px; overflow: hidden;
108
+ border: 1px solid var(--border-default); border-radius: var(--radius-sm);
109
+ background: var(--bg-3); user-select: none;
110
+ }
111
+ .rb-dialog .rb-shot-box img { display: block; max-width: 100%; height: auto; }
112
+ .rb-dialog .rb-shot-box.is-redacting { cursor: crosshair; box-shadow: 0 0 0 3px var(--accent-tint); border-color: var(--accent); }
113
+ .rb-dialog .rb-shot-box.is-redacting img { pointer-events: none; }
114
+ .rb-dialog .rb-redact-rect { position: absolute; background: #000; pointer-events: none; }
115
+ .rb-dialog .rb-shot-actions { display: flex; gap: var(--space-3); }
116
+ .rb-dialog .rb-link {
117
+ appearance: none; background: transparent; border: 0; padding: 0; cursor: pointer;
118
+ font-size: var(--type-xs); font-family: var(--font-body);
119
+ color: var(--accent); text-decoration: underline; text-underline-offset: 2px;
120
+ text-decoration-color: var(--accent-muted, var(--accent));
121
+ }
122
+ .rb-dialog .rb-link:hover, .rb-dialog .rb-link.is-on { color: var(--accent-hover, var(--accent)); }
123
+ .rb-dialog .rb-actions { display: flex; justify-content: flex-end; gap: var(--space-3); margin-top: var(--space-2); }
124
+ .rb-dialog .rb-primary { background: var(--accent); border-color: var(--accent); color: var(--accent-fg); }
125
+ .rb-dialog .rb-primary:hover:not(:disabled) { background: var(--accent-hover, var(--accent)); border-color: var(--accent-hover, var(--accent)); }
126
+ .rb-dialog .st-btn:focus-visible,
127
+ .rb-dialog .st-iconbtn:focus-visible { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-tint); }
128
+
74
129
  }
@@ -1876,86 +1876,3 @@
1876
1876
  gap: 6px;
1877
1877
  }
1878
1878
 
1879
- /* ----- Report-a-Bug dialog (feature-bug-report-button) -----
1880
- Reuses the help-modal shell; rb-* covers the consent checklist, screenshot
1881
- tiles, and the redaction overlay. Same DS voice: hard edges, mono, tokens. */
1882
- .rb-modal { width: min(640px, 100%); }
1883
- .rb-body { display: flex; flex-direction: column; gap: var(--u-s-3); }
1884
- .rb-label { font-weight: 700; color: var(--u-fg-0); }
1885
- .rb-desc {
1886
- width: 100%;
1887
- resize: vertical;
1888
- background: var(--u-bg-0);
1889
- border: 1px solid var(--u-border);
1890
- color: var(--u-fg-0);
1891
- font-family: var(--u-font-mono);
1892
- font-size: var(--type-xs);
1893
- padding: var(--u-s-2);
1894
- }
1895
- .rb-desc:focus-visible { outline: none; box-shadow: var(--shadow-focus); }
1896
- .rb-hint { color: var(--u-fg-2); }
1897
- .rb-error { color: var(--u-danger, #c0392b); }
1898
- .rb-section { display: flex; flex-direction: column; gap: var(--u-s-1); }
1899
- .rb-section-hd {
1900
- display: flex;
1901
- align-items: center;
1902
- justify-content: space-between;
1903
- font-weight: 700;
1904
- color: var(--u-fg-0);
1905
- text-transform: uppercase;
1906
- letter-spacing: var(--tracking-sku);
1907
- font-size: 10px;
1908
- }
1909
- .rb-check { display: flex; gap: var(--u-s-2); align-items: baseline; cursor: pointer; }
1910
- .rb-check input { accent-color: var(--u-accent, currentColor); }
1911
- .rb-check code { color: var(--u-fg-0); }
1912
- .rb-details summary { cursor: pointer; color: var(--u-fg-2); }
1913
- .rb-log {
1914
- max-height: 160px;
1915
- overflow: auto;
1916
- background: var(--u-bg-0);
1917
- border: 1px solid var(--u-border);
1918
- padding: var(--u-s-2);
1919
- white-space: pre-wrap;
1920
- word-break: break-all;
1921
- }
1922
- .rb-shots { display: flex; flex-wrap: wrap; gap: var(--u-s-2); }
1923
- .rb-shot { display: flex; flex-direction: column; gap: 4px; }
1924
- .rb-shot-box {
1925
- position: relative;
1926
- max-width: 260px;
1927
- border: 1px solid var(--u-border);
1928
- background: var(--u-bg-0);
1929
- user-select: none;
1930
- }
1931
- .rb-shot-box img { display: block; max-width: 100%; height: auto; }
1932
- .rb-shot-box.is-redacting { cursor: crosshair; }
1933
- .rb-shot-box.is-redacting img { pointer-events: none; }
1934
- .rb-redact-rect { position: absolute; background: #000; pointer-events: none; }
1935
- .rb-shot-actions { display: flex; gap: var(--u-s-2); }
1936
- .rb-link {
1937
- background: transparent;
1938
- border: none;
1939
- padding: 0;
1940
- color: var(--u-fg-1);
1941
- text-decoration: underline;
1942
- cursor: pointer;
1943
- font-family: var(--u-font-mono);
1944
- font-size: var(--type-xs);
1945
- }
1946
- .rb-link:hover, .rb-link.is-on { color: var(--u-fg-0); }
1947
- .rb-actions { display: flex; justify-content: flex-end; gap: var(--u-s-2); margin-top: var(--u-s-2); }
1948
- .rb-btn {
1949
- background: var(--u-bg-2);
1950
- border: 1px solid var(--u-fg-0);
1951
- color: var(--u-fg-0);
1952
- font-family: var(--u-font-mono);
1953
- font-size: var(--type-xs);
1954
- padding: var(--u-s-1) var(--u-s-3);
1955
- cursor: pointer;
1956
- }
1957
- .rb-btn:hover { background: var(--u-bg-3); }
1958
- .rb-btn:focus-visible { outline: none; box-shadow: var(--shadow-focus); }
1959
- .rb-btn[disabled] { opacity: 0.5; cursor: not-allowed; }
1960
- .rb-primary { background: var(--u-fg-0); color: var(--u-bg-0); }
1961
- .rb-primary:hover { background: var(--u-fg-1); }