@conduction/docusaurus-preset 2.3.0 → 2.3.1

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@conduction/docusaurus-preset",
3
- "version": "2.3.0",
3
+ "version": "2.3.1",
4
4
  "scripts": {
5
5
  "prepack": "node scripts/prepack-bundle-css.js"
6
6
  },
@@ -82,25 +82,21 @@ export default function AppMock({app, size = 'md', sidebar = null, caption = fal
82
82
  );
83
83
  }
84
84
  const {Component, label} = variant;
85
- // The `sidebar` prop renders any node as a Nextcloud-style overlay
86
- // panel pinned to the right edge of the frame. Typically a
87
- // <SidebarMock kind="..." />; the SidebarMock component automatically
88
- // drops its standalone chrome via the `embedded` flag we pass here.
89
- // Anything else (custom JSX, an image, etc.) renders verbatim inside
90
- // the overlay slot.
85
+ // The `sidebar` prop is forwarded to the variant Component, which
86
+ // renders it as a flex sibling of `.col` inside the variant's
87
+ // `.body`, taking the `.detail` slot. SidebarMock children get
88
+ // `embedded: true` so they drop their standalone .smFrame chrome
89
+ // and render as the bare `.detail.rich` panel that slots into
90
+ // .body. Variants that don't accept a sidebar prop (e.g. MyDash)
91
+ // ignore it; this keeps the change additive.
91
92
  const renderedSidebar = React.isValidElement(sidebar)
92
93
  ? React.cloneElement(sidebar, { embedded: true })
93
94
  : sidebar;
94
95
  return (
95
96
  <div className={styles.am}>
96
97
  <figure className={[styles.figure, className].filter(Boolean).join(' ')}>
97
- <div className={[styles.frame, styles[`size-${size}`], renderedSidebar && styles.withSidebar].filter(Boolean).join(' ')}>
98
- <Component />
99
- {renderedSidebar && (
100
- <div className={styles.sidebarOverlay} aria-label="Sidebar overlay">
101
- {renderedSidebar}
102
- </div>
103
- )}
98
+ <div className={[styles.frame, styles[`size-${size}`]].filter(Boolean).join(' ')}>
99
+ <Component sidebar={renderedSidebar} />
104
100
  </div>
105
101
  {caption && <figcaption className={styles.caption}>{label}</figcaption>}
106
102
  </figure>
@@ -47,27 +47,6 @@
47
47
  .am .size-md { max-width: 720px; }
48
48
  .am .size-lg { max-width: 960px; }
49
49
 
50
- /* Sidebar overlay: when AppMock receives a `sidebar` prop, the
51
- passed JSX renders pinned to the right edge of the frame, full
52
- height, modeling a Nextcloud detail panel sliding over the app.
53
- The .withSidebar modifier on .frame is a hook for variants that
54
- want to dim the underlying canvas; today it doesn't add any
55
- styles itself. */
56
- .am .frame .sidebarOverlay {
57
- position: absolute;
58
- top: 0;
59
- right: 0;
60
- bottom: 0;
61
- width: 32%;
62
- min-width: 200px;
63
- background: white;
64
- border-left: 1px solid var(--c-cobalt-200);
65
- z-index: 2;
66
- display: flex;
67
- flex-direction: column;
68
- overflow: hidden;
69
- }
70
-
71
50
  .am .caption {
72
51
  font-family: var(--conduction-typography-font-family-code);
73
52
  font-size: 11px;
@@ -163,6 +142,55 @@
163
142
  flex-shrink: 0;
164
143
  }
165
144
 
145
+ /* Sidebar (enriched .detail) matches the real Nextcloud sidepanel:
146
+ header (icon + title + description + close), tabs, then content.
147
+ Used by SidebarMock embedded mode (slots into <body>'s flex layout
148
+ as a sibling of .col, taking the .detail slot) and by the kit
149
+ page templates section. */
150
+ .am .detail.rich { padding: 0; gap: 0; }
151
+ .am .detail.rich .sb-head {
152
+ display: flex; align-items: center; gap: 6px;
153
+ padding: 10px;
154
+ border-bottom: 1px solid var(--c-cobalt-100);
155
+ }
156
+ .am .detail.rich .sb-head .ico {
157
+ width: 16px; height: 16px;
158
+ border-radius: 50%;
159
+ background: var(--c-cobalt-50);
160
+ border: 1px solid var(--c-cobalt-200);
161
+ flex-shrink: 0;
162
+ }
163
+ .am .detail.rich .sb-head .meta {
164
+ flex: 1; display: flex; flex-direction: column; gap: 3px;
165
+ min-width: 0;
166
+ }
167
+ .am .detail.rich .sb-head .title { height: 6px; background: var(--c-cobalt-900); border-radius: 1px; width: 50%; }
168
+ .am .detail.rich .sb-head .desc { height: 3px; background: var(--c-cobalt-300); border-radius: 1px; width: 85%; }
169
+ .am .detail.rich .sb-head .close { width: 8px; height: 8px; background: var(--c-cobalt-300); flex-shrink: 0; }
170
+
171
+ .am .detail.rich .sb-tabs {
172
+ display: flex;
173
+ padding: 0 10px;
174
+ border-bottom: 1px solid var(--c-cobalt-100);
175
+ }
176
+ .am .detail.rich .sb-tab {
177
+ flex: 1; padding: 6px 0;
178
+ display: flex; flex-direction: column; align-items: center; gap: 3px;
179
+ border-bottom: 2px solid transparent;
180
+ }
181
+ .am .detail.rich .sb-tab.active { border-bottom-color: var(--c-blue-cobalt); }
182
+ .am .detail.rich .sb-tab .ico { width: 7px; height: 7px; border-radius: 50%; background: var(--c-cobalt-300); }
183
+ .am .detail.rich .sb-tab.active .ico { background: var(--c-cobalt-700); }
184
+ .am .detail.rich .sb-tab .l { height: 3px; background: var(--c-cobalt-300); width: 24px; border-radius: 1px; }
185
+ .am .detail.rich .sb-tab.active .l { background: var(--c-cobalt-700); }
186
+
187
+ .am .detail.rich .sb-body { padding: 10px; display: flex; flex-direction: column; gap: 7px; overflow: hidden; }
188
+ .am .detail.rich .sb-label { height: 4px; background: var(--c-cobalt-700); width: 40%; border-radius: 1px; }
189
+ .am .detail.rich .sb-input { height: 14px; background: white; border: 1px solid var(--c-cobalt-200); border-radius: 3px; }
190
+ .am .detail.rich .sb-filter { display: flex; flex-direction: column; gap: 4px; }
191
+ .am .detail.rich .sb-filter .lbl { height: 3px; background: var(--c-cobalt-400); width: 30%; border-radius: 1px; }
192
+ .am .detail.rich .sb-filter .field { height: 12px; background: white; border: 1px solid var(--c-cobalt-200); border-radius: 2px; }
193
+
166
194
  /* Generic content panel — white card with rounded corners. */
167
195
  .am .panel {
168
196
  background: white;
@@ -10,7 +10,7 @@
10
10
  import React from 'react';
11
11
  import styles from '../AppMock.module.css';
12
12
 
13
- export default function OpenRegisterMock() {
13
+ export default function OpenRegisterMock({ sidebar = null }) {
14
14
  return (
15
15
  <>
16
16
  <div className={styles.topbar}>
@@ -80,20 +80,25 @@ export default function OpenRegisterMock() {
80
80
  </div>
81
81
  </div>
82
82
  </div>
83
- {/* Right detail rail */}
84
- <div className={styles.detail}>
85
- <div className={styles.row + ' ' + styles.head}></div>
86
- <div className={styles.row}></div>
87
- <div className={styles.row + ' ' + styles.short}></div>
88
- <div style={{height: 8}}></div>
89
- <div className={styles.row + ' ' + styles.head}></div>
90
- <div className={styles.row + ' ' + styles.dark}></div>
91
- <div className={styles.row}></div>
92
- <div className={styles.row}></div>
93
- <div className={styles.row + ' ' + styles.short}></div>
94
- <div className={styles.row + ' ' + styles.accent}></div>
95
- <div className={styles.row + ' ' + styles.short}></div>
96
- </div>
83
+ {/* Right detail rail. When AppMock passes a `sidebar` prop
84
+ (typically a <SidebarMock kind="..." embedded />), it
85
+ renders as the rich detail rail instead of the placeholder
86
+ rows. */}
87
+ {sidebar || (
88
+ <div className={styles.detail}>
89
+ <div className={styles.row + ' ' + styles.head}></div>
90
+ <div className={styles.row}></div>
91
+ <div className={styles.row + ' ' + styles.short}></div>
92
+ <div style={{height: 8}}></div>
93
+ <div className={styles.row + ' ' + styles.head}></div>
94
+ <div className={styles.row + ' ' + styles.dark}></div>
95
+ <div className={styles.row}></div>
96
+ <div className={styles.row}></div>
97
+ <div className={styles.row + ' ' + styles.short}></div>
98
+ <div className={styles.row + ' ' + styles.accent}></div>
99
+ <div className={styles.row + ' ' + styles.short}></div>
100
+ </div>
101
+ )}
97
102
  </div>
98
103
  </>
99
104
  );
@@ -11,7 +11,7 @@
11
11
  import React from 'react';
12
12
  import styles from '../AppMock.module.css';
13
13
 
14
- export default function ProcestMock() {
14
+ export default function ProcestMock({ sidebar = null }) {
15
15
  return (
16
16
  <>
17
17
  <div className={styles.topbar}>
@@ -81,6 +81,11 @@ export default function ProcestMock() {
81
81
  </div>
82
82
  </div>
83
83
  </div>
84
+ {/* Optional sidebar (typically a <SidebarMock kind="..." />)
85
+ renders here as a flex sibling of .col, taking the .detail
86
+ slot. Procest's case detail view doesn't ship a default
87
+ detail rail, so without the prop nothing extra renders. */}
88
+ {sidebar}
84
89
  </div>
85
90
  </>
86
91
  );
@@ -8,24 +8,32 @@
8
8
  * so on). A SidebarMock variant represents one such sidebar with
9
9
  * one tab active.
10
10
  *
11
+ * Markup matches the existing .detail.rich pattern that already
12
+ * lived in the AppMock kit anatomy: a .sb-head row (icon + meta of
13
+ * title + description + close), a .sb-tabs strip (one per registered
14
+ * tab, active marker on the current one), and a .sb-body. All
15
+ * styles live in AppMock.module.css under .am .detail.rich; the
16
+ * body atoms (smKv / smPerson / smStage / smLog / smPii) live in
17
+ * SidebarMock.module.css under .am .sb-body so they only apply
18
+ * inside a sidebar.
19
+ *
11
20
  * Two render modes:
12
21
  *
13
- * STANDALONE (default): wraps the panel in <div class="am sm"> with
14
- * a .smFrame card around it. Use in kit-page specimens or marketing
15
- * copy that talks about a single sidebar surface in isolation.
22
+ * STANDALONE (default): wraps the .detail.rich panel in
23
+ * <div class="am sm"> + .smFrame so it reads as a card on the
24
+ * kit page. Use in marketing copy that talks about a single
25
+ * sidebar surface in isolation.
16
26
  *
17
27
  * <SidebarMock kind="procest-xwiki" />
18
28
  *
19
- * EMBEDDED: drops the frame so the panel slots directly into the
20
- * .sidebarOverlay slot inside an AppMock frame. Set automatically
21
- * by AppMock when the `sidebar` prop is a SidebarMock JSX element.
29
+ * EMBEDDED: drops the .smFrame wrapper, leaving just
30
+ * <div class="detail rich">…</div>. Slots into the .body flex
31
+ * layout of an AppMock variant as a sibling of .col, taking the
32
+ * detail-rail position. Set automatically by AppMock when the
33
+ * `sidebar` prop is a SidebarMock JSX element.
22
34
  *
23
35
  * <AppMock app="procest" sidebar={<SidebarMock kind="procest-xwiki" />} />
24
36
  *
25
- * Header bar (title + close) and tab strip are chassis. Body content
26
- * is per-variant: the JSX file under variants/ provides just the body
27
- * children, the chassis wraps it.
28
- *
29
37
  * Status colour map matches WidgetMock and AppMock atoms:
30
38
  * mint = stable / done / signed
31
39
  * orange = active / pending / due soon
@@ -34,9 +42,10 @@
34
42
  *
35
43
  * Props:
36
44
  * - kind: one of VARIANTS keys (required)
37
- * - embedded: boolean (default false) — drop the standalone chrome
38
- * so this can render inside
39
- * an AppMock overlay slot
45
+ * - embedded: boolean (default false) — drop the standalone
46
+ * .smFrame chrome so the
47
+ * panel slots into
48
+ * AppMock's .body layout
40
49
  * - className: string
41
50
  */
42
51
 
@@ -56,10 +65,10 @@ import NextcloudActivity from './variants/NextcloudActivity.jsx';
56
65
 
57
66
  /**
58
67
  * Each VARIANTS entry carries:
59
- * Component: the JSX that fills the body
68
+ * Component: the JSX that fills the .sb-body
60
69
  * label: human-readable name (used in caption / kit page)
61
- * tabs: ordered list of tab labels with one marked active. The
62
- * labels are decorative (kit page renders width-fixed pills)
70
+ * tabs: ordered list of tabs with one .active. The id is
71
+ * decorative (rendered as a placeholder bar in .sb-tab .l)
63
72
  * but the active flag drives the highlight.
64
73
  */
65
74
  const VARIANTS = {
@@ -162,19 +171,26 @@ export default function SidebarMock({ kind, embedded = false, className }) {
162
171
  }
163
172
  const { Component, tabs } = variant;
164
173
  const panel = (
165
- <div className={styles.smPanel}>
166
- <div className={styles.smHead}>
167
- <div className={styles.smTitle}></div>
168
- <div className={styles.smClose}></div>
174
+ <div className={[amStyles.detail, amStyles.rich].join(' ')}>
175
+ <div className={amStyles['sb-head']}>
176
+ <div className={amStyles.ico}></div>
177
+ <div className={amStyles.meta}>
178
+ <div className={amStyles.title}></div>
179
+ <div className={amStyles.desc}></div>
180
+ </div>
181
+ <div className={amStyles.close}></div>
169
182
  </div>
170
183
  {tabs && tabs.length > 0 && (
171
- <div className={styles.smTabs}>
184
+ <div className={amStyles['sb-tabs']}>
172
185
  {tabs.map((t, i) => (
173
- <div key={t.id || i} className={[styles.smTab, t.active && styles.smTabActive].filter(Boolean).join(' ')}></div>
186
+ <div key={t.id || i} className={[amStyles['sb-tab'], t.active && amStyles.active].filter(Boolean).join(' ')}>
187
+ <div className={amStyles.ico}></div>
188
+ <div className={amStyles.l}></div>
189
+ </div>
174
190
  ))}
175
191
  </div>
176
192
  )}
177
- <div className={styles.smBody}>
193
+ <div className={amStyles['sb-body']}>
178
194
  <Component />
179
195
  </div>
180
196
  </div>
@@ -1,29 +1,34 @@
1
1
  /**
2
2
  * <SidebarMock /> styles.
3
3
  *
4
- * Models the Nextcloud right-side detail panel (the surface where
5
- * apps register tabs: Activity, Comments, plus app-specific extensions
6
- * like Procest's xWiki tab or DocuDesk's Signatures tab).
4
+ * The sidebar chassis (.detail.rich, .sb-head, .sb-tabs, .sb-body and
5
+ * its built-in atoms .sb-input / .sb-filter / .sb-label) lives in
6
+ * AppMock/AppMock.module.css. SidebarMock reuses that module so the
7
+ * panel renders identically whether it is embedded inside an AppMock
8
+ * (taking the .detail slot in .body's flex layout) or rendered
9
+ * standalone for kit-page specimens.
7
10
  *
8
- * Two render modes share the same panel internals:
11
+ * What lives here:
9
12
  *
10
- * 1. STANDALONE (default): the panel renders inside <div class="am sm">
11
- * with .smFrame around it (white card, shadow, border-radius). Used
12
- * in kit-page specimens and inline marketing copy.
13
+ * .smFrame — the standalone wrapper card (white box, shadow,
14
+ * radius, fixed size). Used only when rendering the
15
+ * sidebar standalone in marketing copy or kit pages;
16
+ * embedded mode skips it so the panel slots into
17
+ * .body's flex layout untouched.
13
18
  *
14
- * 2. EMBEDDED: the panel renders inside an <AppMock>'s .sidebarOverlay
15
- * via the AppMock `sidebar` prop. The overlay positions absolutely
16
- * against the right of the frame and extends full height. SidebarMock
17
- * drops the frame/shadow/radius in this mode so it slots cleanly.
18
- *
19
- * Both modes pass through the same atom toolkit defined under .smBody
20
- * here (rows, lists, kvs, log lines). Body content is per-variant.
19
+ * .am .sb-body atoms extra body-level atoms beyond what
20
+ * AppMock.module.css already provides under .sb-body
21
+ * (.sb-input, .sb-filter, .sb-label). The atoms here
22
+ * cover the rest of the marketing surfaces: key/value
23
+ * pairs (smKv), person rows with status pip (smPerson),
24
+ * stage timelines (smStage), log lines (smLog), and
25
+ * PII-redaction pill maps (smPii).
21
26
  */
22
27
 
23
28
  .am.sm { display: contents; }
24
29
 
25
- /* ---- Standalone chrome ---- */
26
-
30
+ /* Standalone wrapper card. Inside, the .detail.rich panel renders
31
+ identically to its embedded twin, just clipped to the smFrame box. */
27
32
  .am .smFrame {
28
33
  width: 300px;
29
34
  height: 400px;
@@ -36,110 +41,46 @@
36
41
  flex-direction: column;
37
42
  }
38
43
 
39
- /* ---- Panel internals (used in both modes) ---- */
40
-
41
- .am .smPanel {
42
- display: flex;
43
- flex-direction: column;
44
- height: 100%;
45
- min-height: 0;
46
- background: white;
47
- }
48
-
49
- /* Header: title bar plus close button. */
50
- .am .smHead {
51
- padding: 10px 12px;
52
- display: flex;
53
- align-items: center;
54
- gap: 8px;
55
- border-bottom: 1px solid var(--c-cobalt-100);
56
- flex-shrink: 0;
57
- }
58
- .am .smHead .smTitle {
59
- flex: 1;
60
- height: 5px;
61
- background: var(--c-cobalt-700);
62
- border-radius: 1px;
63
- }
64
- .am .smHead .smClose {
65
- width: 10px;
66
- height: 10px;
67
- background: var(--c-cobalt-300);
68
- border-radius: 1px;
69
- flex-shrink: 0;
70
- }
71
-
72
- /* Tab strip: each tab is a width-fixed pill. Active tab is cobalt with
73
- a 2px underline that crosses the .smTabs bottom border. */
74
- .am .smTabs {
75
- display: flex;
76
- padding: 0 12px;
77
- gap: 8px;
78
- border-bottom: 1px solid var(--c-cobalt-100);
79
- flex-shrink: 0;
80
- }
81
- .am .smTab {
82
- height: 4px;
83
- width: 28px;
84
- background: var(--c-cobalt-200);
85
- border-radius: 1px;
86
- margin: 10px 0 8px;
87
- position: relative;
88
- }
89
- .am .smTab.smTabActive {
90
- background: var(--c-blue-cobalt);
91
- }
92
- .am .smTab.smTabActive::after {
93
- content: "";
94
- position: absolute;
95
- bottom: -8px;
96
- left: -2px;
97
- right: -2px;
98
- height: 2px;
99
- background: var(--c-blue-cobalt);
100
- border-radius: 1px;
101
- }
102
-
103
- /* Body: scrolling region with stacked sections. */
104
- .am .smBody {
44
+ /* Inside .smFrame the .detail.rich child needs to fill the box; the
45
+ default .detail width: 26% rule is meant for an embedded layout so
46
+ we override here. */
47
+ .am .smFrame > .detail.rich {
48
+ width: 100%;
49
+ min-width: 0;
105
50
  flex: 1;
106
- padding: 12px;
107
- display: flex;
108
- flex-direction: column;
109
- gap: 8px;
110
- min-height: 0;
111
- overflow: hidden;
51
+ border-left: none;
112
52
  }
113
53
 
114
- /* ---- Body atoms ---- */
54
+ /* ---- Body atoms beyond the AppMock-provided sb-input / sb-filter ---- */
115
55
 
116
- /* Generic row. Defaults to a thin neutral bar. Modifiers below tweak it. */
117
- .am .smBody .row {
56
+ /* Generic row block. Sized by class modifier; defaults to thin neutral. */
57
+ .am .sb-body .row {
118
58
  height: 3px;
119
59
  background: var(--c-cobalt-200);
120
60
  border-radius: 1px;
121
61
  flex-shrink: 0;
62
+ width: 100%;
122
63
  }
123
- .am .smBody .row.head {
64
+ .am .sb-body .row.head {
124
65
  height: 5px;
125
66
  width: 55%;
126
67
  background: var(--c-cobalt-700);
127
68
  margin-bottom: 4px;
128
69
  }
129
- .am .smBody .row.short { width: 35%; }
130
- .am .smBody .row.med { width: 70%; }
131
- .am .smBody .row.dark { background: var(--c-cobalt-700); }
132
- .am .smBody .row.accent { background: var(--c-orange-knvb); }
70
+ .am .sb-body .row.short { width: 35%; }
71
+ .am .sb-body .row.med { width: 70%; }
72
+ .am .sb-body .row.dark { background: var(--c-cobalt-700); }
73
+ .am .sb-body .row.accent { background: var(--c-orange-knvb); }
133
74
 
134
- /* Section break: horizontal rule with a bit of vertical breathing. */
135
- .am .smBody .smBreak {
75
+ /* Section break: thin horizontal rule between sub-sections. */
76
+ .am .sb-body .smBreak {
136
77
  height: 1px;
137
78
  background: var(--c-cobalt-100);
138
79
  margin: 4px 0;
139
80
  }
140
81
 
141
- /* Subhead: small block-level title that introduces a section. */
142
- .am .smBody .smSub {
82
+ /* Subhead: short bold-weight bar that introduces a new section. */
83
+ .am .sb-body .smSub {
143
84
  height: 4px;
144
85
  width: 40%;
145
86
  background: var(--c-cobalt-700);
@@ -147,106 +88,113 @@
147
88
  margin-top: 4px;
148
89
  }
149
90
 
150
- /* Key-value list (used for metadata sidebars). Each row is a label +
151
- value pair. Label is a short cobalt-400 bar, value is a longer
152
- cobalt-700 bar. */
153
- .am .smBody .smKv {
91
+ /* Key-value list (used for metadata tabs). Label cobalt-400 short bar
92
+ plus longer cobalt-700 value bar on the same row. */
93
+ .am .sb-body .smKv {
154
94
  display: flex;
155
95
  align-items: center;
156
96
  gap: 8px;
157
97
  }
158
- .am .smBody .smKv .k {
98
+ .am .sb-body .smKv .k {
159
99
  height: 3px;
160
100
  width: 30%;
161
101
  background: var(--c-cobalt-400);
162
102
  border-radius: 1px;
163
103
  flex-shrink: 0;
164
104
  }
165
- .am .smBody .smKv .v {
105
+ .am .sb-body .smKv .v {
166
106
  flex: 1;
167
107
  height: 3px;
168
108
  background: var(--c-cobalt-700);
169
109
  border-radius: 1px;
170
110
  }
171
111
 
172
- /* Person row (used for signatures, comments, talk). Avatar plus two
173
- text rows plus an optional status pip on the right. */
174
- .am .smBody .smPerson {
112
+ /* Person row (signatures, comments, history). Avatar + two text rows
113
+ + optional status pip. .b/.c/.d/.e modifiers shift the avatar to
114
+ the matching family colour. .pending / .blocked modifiers shift
115
+ the pip to orange / red. */
116
+ .am .sb-body .smPerson {
175
117
  display: flex;
176
118
  align-items: center;
177
119
  gap: 6px;
178
120
  }
179
- .am .smBody .smPerson .av {
121
+ .am .sb-body .smPerson .av {
180
122
  width: 14px;
181
123
  height: 14px;
182
124
  border-radius: 50%;
183
125
  background: var(--c-mint-300);
184
126
  flex-shrink: 0;
185
127
  }
186
- .am .smBody .smPerson.b .av { background: var(--c-lavender-300); }
187
- .am .smBody .smPerson.c .av { background: var(--c-orange-knvb); }
188
- .am .smBody .smPerson.d .av { background: var(--c-forest-300); }
189
- .am .smBody .smPerson.e .av { background: var(--c-terracotta-300); }
190
- .am .smBody .smPerson .lines {
128
+ .am .sb-body .smPerson.b .av { background: var(--c-lavender-300); }
129
+ .am .sb-body .smPerson.c .av { background: var(--c-orange-knvb); }
130
+ .am .sb-body .smPerson.d .av { background: var(--c-forest-300); }
131
+ .am .sb-body .smPerson.e .av { background: var(--c-terracotta-300); }
132
+ .am .sb-body .smPerson .lines {
191
133
  flex: 1;
192
134
  display: flex;
193
135
  flex-direction: column;
194
136
  gap: 2px;
195
137
  min-width: 0;
196
138
  }
197
- .am .smBody .smPerson .l1 { height: 3px; width: 70%; background: var(--c-cobalt-700); border-radius: 1px; }
198
- .am .smBody .smPerson .l2 { height: 2px; width: 50%; background: var(--c-cobalt-300); border-radius: 1px; }
199
- .am .smBody .smPerson .pip {
139
+ .am .sb-body .smPerson .l1 { height: 3px; width: 70%; background: var(--c-cobalt-700); border-radius: 1px; }
140
+ .am .sb-body .smPerson .l2 { height: 2px; width: 50%; background: var(--c-cobalt-300); border-radius: 1px; }
141
+ .am .sb-body .smPerson .pip {
200
142
  width: 8px;
201
143
  height: 8px;
202
144
  border-radius: 50%;
203
145
  background: var(--c-mint-500);
204
146
  flex-shrink: 0;
205
147
  }
206
- .am .smBody .smPerson.pending .pip { background: var(--c-orange-knvb); }
207
- .am .smBody .smPerson.blocked .pip { background: var(--c-red-vermillion); }
148
+ .am .sb-body .smPerson.pending .pip { background: var(--c-orange-knvb); }
149
+ .am .sb-body .smPerson.blocked .pip { background: var(--c-red-vermillion); }
208
150
 
209
- /* Stage timeline: vertical list with a left-side rail and stage hexes. */
210
- .am .smBody .smStage {
151
+ /* Stage timeline (case sidebar, Timeline tab). Vertical list with a
152
+ stage hex on the left and two text rows. Modifiers .now / .late /
153
+ .todo shift the hex colour. */
154
+ .am .sb-body .smStage {
211
155
  display: flex;
212
156
  align-items: center;
213
157
  gap: 8px;
214
158
  }
215
- .am .smBody .smStage .h {
159
+ .am .sb-body .smStage .h {
216
160
  width: 10px;
217
161
  height: 11px;
218
162
  clip-path: var(--hex-pointy-top);
219
163
  background: var(--c-mint-500);
220
164
  flex-shrink: 0;
221
165
  }
222
- .am .smBody .smStage.now .h { background: var(--c-orange-knvb); }
223
- .am .smBody .smStage.todo .h { background: var(--c-cobalt-200); }
224
- .am .smBody .smStage.late .h { background: var(--c-red-vermillion); }
225
- .am .smBody .smStage .lines { flex: 1; display: flex; flex-direction: column; gap: 2px; min-width: 0; }
226
- .am .smBody .smStage .l1 { height: 3px; width: 60%; background: var(--c-cobalt-700); border-radius: 1px; }
227
- .am .smBody .smStage .l2 { height: 2px; width: 40%; background: var(--c-cobalt-300); border-radius: 1px; }
228
-
229
- /* Log line: monospace-ish row with a status colour at the start. */
230
- .am .smBody .smLog {
166
+ .am .sb-body .smStage.now .h { background: var(--c-orange-knvb); }
167
+ .am .sb-body .smStage.todo .h { background: var(--c-cobalt-200); }
168
+ .am .sb-body .smStage.late .h { background: var(--c-red-vermillion); }
169
+ .am .sb-body .smStage .lines { flex: 1; display: flex; flex-direction: column; gap: 2px; min-width: 0; }
170
+ .am .sb-body .smStage .l1 { height: 3px; width: 60%; background: var(--c-cobalt-700); border-radius: 1px; }
171
+ .am .sb-body .smStage .l2 { height: 2px; width: 40%; background: var(--c-cobalt-300); border-radius: 1px; }
172
+
173
+ /* Log line (run-detail sidebar). Short timestamp bar + message bar.
174
+ .warn / .error tint the timestamp to orange / red so the eye can
175
+ scan severity at a glance. */
176
+ .am .sb-body .smLog {
231
177
  display: flex;
232
178
  align-items: center;
233
179
  gap: 6px;
234
180
  }
235
- .am .smBody .smLog .ts { width: 22px; height: 3px; background: var(--c-cobalt-400); border-radius: 1px; flex-shrink: 0; }
236
- .am .smBody .smLog .msg { flex: 1; height: 3px; background: var(--c-cobalt-700); border-radius: 1px; }
237
- .am .smBody .smLog.warn .ts { background: var(--c-orange-knvb); }
238
- .am .smBody .smLog.error .ts { background: var(--c-red-vermillion); }
181
+ .am .sb-body .smLog .ts { width: 22px; height: 3px; background: var(--c-cobalt-400); border-radius: 1px; flex-shrink: 0; }
182
+ .am .sb-body .smLog .msg { flex: 1; height: 3px; background: var(--c-cobalt-700); border-radius: 1px; }
183
+ .am .sb-body .smLog.warn .ts { background: var(--c-orange-knvb); }
184
+ .am .sb-body .smLog.error .ts { background: var(--c-red-vermillion); }
239
185
 
240
- /* PII tag: a small inline pill for redacted content. */
241
- .am .smBody .smPiiBlock {
186
+ /* PII redaction map (DocuDesk PII tab). Inline pills marking spans
187
+ in a paragraph; .redacted = applied (red), .suggested = proposed
188
+ (orange), default = neutral text. */
189
+ .am .sb-body .smPiiBlock {
242
190
  display: flex;
243
191
  flex-wrap: wrap;
244
192
  gap: 4px;
245
193
  }
246
- .am .smBody .smPii {
194
+ .am .sb-body .smPii {
247
195
  height: 6px;
248
196
  background: var(--c-cobalt-200);
249
197
  border-radius: 1px;
250
198
  }
251
- .am .smBody .smPii.redacted { background: var(--c-red-vermillion); }
252
- .am .smBody .smPii.suggested { background: var(--c-orange-knvb); }
199
+ .am .sb-body .smPii.redacted { background: var(--c-red-vermillion); }
200
+ .am .sb-body .smPii.suggested { background: var(--c-orange-knvb); }