@repobit/dex-system-design 0.24.18 → 0.24.19

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 (26) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/package.json +4 -4
  3. package/src/components/ai-guardian-demo.stories.js +454 -33
  4. package/src/components/bento-grid/bento-grid.css.js +12 -1
  5. package/src/components/bento-grid/bento-grid.js +59 -1
  6. package/src/components/bento-grid/bento-grid.stories.js +45 -0
  7. package/src/components/comparison-panel/comparison-panel.css.js +52 -1
  8. package/src/components/comparison-panel/comparison-panel.js +6 -1
  9. package/src/components/compatibility-table/compatibility-table.css.js +29 -13
  10. package/src/components/compatibility-table/compatibility-table.js +13 -7
  11. package/src/components/cta-banner/cta-banner.css.js +11 -0
  12. package/src/components/cta-banner/cta-banner.js +7 -0
  13. package/src/components/footer/footer-lp.css.js +10 -21
  14. package/src/components/footer/footer-lp.js +3 -18
  15. package/src/components/footer/footer-nav-menu.css.js +0 -2
  16. package/src/components/footer/footer.css.js +18 -35
  17. package/src/components/footer/footer.js +5 -1
  18. package/src/components/header/header-code.css.js +208 -10
  19. package/src/components/header/header-code.js +148 -5
  20. package/src/components/header/header-code.stories.js +83 -27
  21. package/src/components/page-switcher/page-switcher.js +1 -1
  22. package/src/components/paragraph/paragraph.js +6 -0
  23. package/src/components/quick-answer/quick-answer.css.js +2 -0
  24. package/src/components/quick-answer/quick-answer.js +1 -1
  25. package/src/components/terminal/terminal-message.css.js +153 -13
  26. package/src/components/terminal/terminal-message.js +37 -11
@@ -14,53 +14,51 @@ export default {
14
14
  component: `
15
15
  **HeaderCode** is a hero/header variant pairing marketing copy on the left with a
16
16
  terminal-style code/demo window on the right. Unlike \`bd-header\`, it has no pricing —
17
- just eyebrow, title, description, two CTA buttons, and a slotted terminal.
17
+ just eyebrow, title, description, two CTA buttons, an optional meta row, and a slotted terminal.
18
18
 
19
19
  The terminal window — including the traffic-light titlebar dots — is owned by
20
20
  \`<bd-terminal-message>\`. \`bd-header-code\` additionally renders an optional small
21
21
  caption **below** the terminal box via \`terminal-caption\`.
22
22
 
23
+ \`variant="tint"\` swaps the plain white background for a light-blue gradient with a
24
+ dot-grid pattern, and gives the \`badge\` slot a bordered pill treatment.
25
+
23
26
  ### Usage
24
27
  \`\`\`html
25
28
  <bd-header-code
26
- eyebrow="Security for autonomous AI agents"
27
- title="Bitdefender AI Guardian"
28
- description="A security layer between your AI agents and the actions they take."
29
- terminal-caption="AI Guardian CLI · first-run setup"
29
+ variant="tint"
30
+ eyebrow="Privacy for autonomous AI agents"
31
+ title="Bitdefender VPN for AI Agents"
32
+ description="Each prompt gets a fresh, disposable container scoped to a specific location."
33
+ terminal-caption="// illustrative — every connection closes when the prompt ends"
30
34
  >
31
- <bd-button-link slot="primary-button" label="Download BETA Today" kind="primary">Download BETA Today</bd-button-link>
35
+ <span slot="badge">EXTERNAL BETA</span>
36
+ <bd-button-link slot="primary-button" label="Download for macOS" kind="primary">Download for macOS</bd-button-link>
32
37
  <bd-button-link slot="secondary-button" label="See how it works" kind="outline">See how it works</bd-button-link>
33
38
 
34
- <bd-terminal-message
35
- slot="terminal-content"
36
- show-titlebar
37
- panel-label="Welcome"
38
- icon="👋"
39
- greeting="Hi, I'm AI Guardian."
40
- intro="I keep an eye on what your AI assistant can access and do:"
41
- .items=\${["which tools it can use", "which credentials to watch", "which MCP servers to trust"]}
42
- footer-bold="Let's get started."
43
- footer="It only takes a minute, and nothing changes until you confirm it."
44
- show-cursor
45
- hint="[Enter] to continue · [esc] to cancel"
46
- ></bd-terminal-message>
39
+ <div slot="meta">…facts row…</div>
40
+
41
+ <bd-terminal-message slot="terminal-content" show-titlebar></bd-terminal-message>
47
42
  </bd-header-code>
48
43
  \`\`\`
49
44
 
50
45
  ### Attributes
51
- | Attribute | Type | Default | Description |
52
- |----------------------|--------|---------|-----------------------------------------------------|
53
- | \`eyebrow\` | String | \`""\` | Small label above the title |
54
- | \`title\` | String | \`""\` | Main heading (can be overridden via \`title\` slot) |
55
- | \`description\` | String | \`""\` | Supporting paragraph under the title |
56
- | \`terminal-caption\` | String | \`""\` | Small caption rendered below the terminal box |
46
+ | Attribute | Type | Default | Description |
47
+ |----------------------|--------|--------------|---------------------------------------------------------|
48
+ | \`eyebrow\` | String | \`""\` | Small label above the title |
49
+ | \`title\` | String | \`""\` | Main heading (can be overridden via \`title\` slot) |
50
+ | \`description\` | String | \`""\` | Supporting paragraph under the title |
51
+ | \`terminal-caption\` | String | \`""\` | Small caption rendered below the terminal box |
52
+ | \`variant\` | String | \`"default"\` | \`"default"\` or \`"tint"\` — background treatment |
57
53
 
58
54
  ### Slots
59
55
  | Slot | Description |
60
56
  |---------------------|-----------------------------------------------|
61
57
  | \`title\` | Overrides the \`title\` attribute if content is provided |
58
+ | \`badge\` | Small pill badge next to the CTAs (e.g. "AVAILABLE", "EXTERNAL BETA") |
62
59
  | \`primary-button\` | The main CTA (typically \`bd-button-link\`) |
63
60
  | \`secondary-button\` | The secondary CTA |
61
+ | \`meta\` | Freeform row under the CTAs — spec line, facts list, etc. |
64
62
  | \`terminal-content\` | Freeform content rendered on the right (typically a \`bd-terminal-message\`) |
65
63
  `
66
64
  }
@@ -70,7 +68,8 @@ caption **below** the terminal box via \`terminal-caption\`.
70
68
  eyebrow : { control: "text", table: { category: "Content" } },
71
69
  title : { control: "text", table: { category: "Content" } },
72
70
  description : { control: "text", table: { category: "Content" } },
73
- terminalCaption: { control: "text", table: { category: "Terminal" } }
71
+ terminalCaption: { control: "text", table: { category: "Terminal" } },
72
+ variant : { control: { type: "select" }, options: ["default", "tint"], table: { category: "Appearance" } }
74
73
  }
75
74
  };
76
75
 
@@ -92,6 +91,7 @@ const terminalContent = html`
92
91
 
93
92
  const render = (args) => html`
94
93
  <bd-header-code
94
+ variant=${args.variant}
95
95
  eyebrow=${args.eyebrow}
96
96
  title=${args.title}
97
97
  description=${args.description}
@@ -122,6 +122,7 @@ const render = (args) => html`
122
122
  export const Default = {
123
123
  name: "Default — AI Guardian",
124
124
  args: {
125
+ variant : "default",
125
126
  eyebrow : "Security for autonomous AI agents",
126
127
  title : "Bitdefender AI Guardian",
127
128
  description : "A security layer between your AI agents and the actions they take — policies, guardrails, and monitoring that let agents run safely.",
@@ -137,9 +138,60 @@ export const Default = {
137
138
  }
138
139
  };
139
140
 
141
+ export const TintVariant = {
142
+ name: "Tint Variant — VPN",
143
+ args: {
144
+ variant : "tint",
145
+ eyebrow : "Privacy for autonomous AI agents",
146
+ title : "Bitdefender VPN for AI Agents",
147
+ description : "Each prompt gets a fresh, disposable container scoped to a specific location, so your agent's traffic isn't tied to your home connection or your personal IP.",
148
+ terminalCaption: "// illustrative — every connection closes when the prompt ends"
149
+ },
150
+ render: (args) => html`
151
+ <bd-header-code
152
+ variant=${args.variant}
153
+ eyebrow=${args.eyebrow}
154
+ title=${args.title}
155
+ description=${args.description}
156
+ terminal-caption=${args.terminalCaption}
157
+ >
158
+ <span slot="breadcrumb">Bitdefender AI</span>
159
+ <span slot="breadcrumb">vpn-for-agents</span>
160
+
161
+ <bd-button-link slot="primary-button" label="Download for macOS" kind="primary" size="md" font-size="18px" font-weight="600">Download for macOS</bd-button-link>
162
+ <bd-button-link slot="secondary-button" label="See how it works" kind="primary-outline" size="md" font-size="18px" font-weight="600">See how it works</bd-button-link>
163
+ <span slot="badge">EXTERNAL BETA</span>
164
+
165
+ <bd-terminal-message
166
+ slot="terminal-content"
167
+ show-titlebar
168
+ .lines=${[
169
+ { type: "strong", text: "VPN for AI Agents · connection log" },
170
+ { type: "sep" },
171
+ { type: "dim", text: "MCP vpn_connect(location: frankfurt) [Open]" },
172
+ { type: "dim", text: "REQUEST agent reaches insurer-compare.com [Server IP]" },
173
+ { type: "dim", text: "NETWORK hotel Wi-Fi, unencrypted [Protected]" },
174
+ { type: "dim", text: "MCP vpn_safefetch(location: frankfurt, url:" },
175
+ { type: "dim", text: " insurer-compare.com) [Scanned]" },
176
+ { type: "dim", text: "MCP vpn_disconnect(location: frankfurt)" },
177
+ { type: "dim", text: " — prompt ends [Closed, session cleared]" }
178
+ ]}
179
+ ></bd-terminal-message>
180
+ </bd-header-code>
181
+ `,
182
+ parameters: {
183
+ docs: {
184
+ description: {
185
+ story: "`variant=\"tint\"` swaps the plain background for the light-blue gradient + dot-grid treatment, and the badge slot renders as a bordered pill. The floating annotation callouts seen in the reference design (\"exit: frankfurt · server IP\", \"tunnel closed — session cleared\") aren't reproduced here — they'd need to be a feature of `bd-terminal-message` itself, which isn't in scope for `bd-header-code`."
186
+ }
187
+ }
188
+ }
189
+ };
190
+
140
191
  export const NoEyebrow = {
141
192
  name: "No Eyebrow",
142
193
  args: {
194
+ variant : "default",
143
195
  eyebrow : "",
144
196
  title : "Bitdefender AI Guardian",
145
197
  description : "A security layer between your AI agents and the actions they take.",
@@ -158,6 +210,7 @@ export const NoEyebrow = {
158
210
  export const SingleButton = {
159
211
  name: "Single CTA",
160
212
  args: {
213
+ variant : "default",
161
214
  eyebrow : "Security for autonomous AI agents",
162
215
  title : "Bitdefender AI Guardian",
163
216
  description : "A security layer between your AI agents and the actions they take.",
@@ -165,6 +218,7 @@ export const SingleButton = {
165
218
  },
166
219
  render: (args) => html`
167
220
  <bd-header-code
221
+ variant=${args.variant}
168
222
  eyebrow=${args.eyebrow}
169
223
  title=${args.title}
170
224
  description=${args.description}
@@ -192,6 +246,7 @@ export const SingleButton = {
192
246
  export const NoCaption = {
193
247
  name: "No Caption",
194
248
  args: {
249
+ variant : "default",
195
250
  eyebrow : "Security for autonomous AI agents",
196
251
  title : "Bitdefender AI Guardian",
197
252
  description : "A security layer between your AI agents and the actions they take.",
@@ -210,6 +265,7 @@ export const NoCaption = {
210
265
  export const Playground = {
211
266
  name: "Playground",
212
267
  args: {
268
+ variant : "default",
213
269
  eyebrow : "Security for autonomous AI agents",
214
270
  title : "Bitdefender AI Guardian",
215
271
  description : "A security layer between your AI agents and the actions they take — policies, guardrails, and monitoring that let agents run safely.",
@@ -219,7 +275,7 @@ export const Playground = {
219
275
  parameters: {
220
276
  docs: {
221
277
  description: {
222
- story: "Fully interactive story — use the Controls panel to edit eyebrow, title, description, and terminal caption live."
278
+ story: "Fully interactive story — use the Controls panel to edit eyebrow, title, description, variant, and terminal caption live."
223
279
  }
224
280
  }
225
281
  }
@@ -19,7 +19,7 @@ class BdPageSwitcher extends LitElement {
19
19
  render() {
20
20
  return html`
21
21
  <div class="inner">
22
- <bd-ai-icon class="logo" width="126" height="24"></bd-ai-icon>
22
+ <bd-ai-icon class="logo" width="200" height="24"></bd-ai-icon>
23
23
 
24
24
  <nav aria-label="Product navigation">
25
25
  ${this.items.map(({ title, href, active }) => html`
@@ -10,6 +10,8 @@ export class BdP extends LitElement {
10
10
  paddingTop : { type: String },
11
11
  fontFamily : { type: String, attribute: "font-family" },
12
12
  fontWeight : { type: String, attribute: "font-weight" },
13
+ fontSize : { type: String, attribute: "font-size" },
14
+ letterSpacing: { type: String, attribute: "letter-spacing" },
13
15
  color : { type: String }
14
16
  };
15
17
 
@@ -21,6 +23,8 @@ export class BdP extends LitElement {
21
23
  this.paddingTop = "";
22
24
  this.fontFamily = "";
23
25
  this.fontWeight = "";
26
+ this.fontSize = "";
27
+ this.letterSpacing = "";
24
28
  this.color = "";
25
29
  }
26
30
 
@@ -60,6 +64,8 @@ export class BdP extends LitElement {
60
64
  if (this.paddingTop) styles.push(`padding-top: ${this.paddingTop};`);
61
65
  if (this.fontFamily) styles.push(`font-family: ${this.fontFamily};`);
62
66
  if (this.fontWeight) styles.push(`font-weight: ${this.fontWeight};`);
67
+ if (this.fontSize) styles.push(`font-size: ${this.fontSize};`);
68
+ if (this.letterSpacing) styles.push(`letter-spacing: ${this.letterSpacing};`);
63
69
 
64
70
  const validColor = this._getValidColor(this.color);
65
71
  if (validColor) styles.push(`color: ${validColor};`);
@@ -4,6 +4,8 @@ export default css`
4
4
  :host {
5
5
  display: block;
6
6
  font-family: var(--typography-fontFamily-sans);
7
+ line-height: 1.55;
8
+
7
9
  }
8
10
 
9
11
  .bd-quickanswer-container {
@@ -30,7 +30,7 @@ class QuickAnswer extends LitElement {
30
30
  `
31
31
  : nothing}
32
32
 
33
- <bd-p kind="normal" class="bd-quickanswer-text">
33
+ <bd-p kind="large" class="bd-quickanswer-text">
34
34
  <slot name="text">${this.text}</slot>
35
35
  </bd-p>
36
36
 
@@ -11,6 +11,12 @@ export default css`
11
11
  box-sizing: border-box;
12
12
  }
13
13
 
14
+ /* Tighter host padding for the "flush" variant, used where the terminal
15
+ sits over decorative rings/a 3D scene (e.g. the VPN hero). */
16
+ :host([variant="flush"]) {
17
+ padding: 18px 20px;
18
+ }
19
+
14
20
  /* === TITLEBAR (traffic-light dots only, no label) === */
15
21
  .bd-terminalmsg-titlebar {
16
22
  display: flex;
@@ -47,6 +53,15 @@ export default css`
47
53
  padding: var(--spacing-20) var(--spacing-20) calc(var(--spacing-20) + var(--spacing-8));
48
54
  }
49
55
 
56
+ /* "flush" variant: the host's own box already reads as the terminal's
57
+ edge (no titlebar dots above it to visually separate an inner panel),
58
+ so the inner panel's own border is redundant — drop it and let the
59
+ panel's padding still apply. */
60
+ :host([variant="flush"]) .bd-terminalmsg-panel {
61
+ border: none;
62
+ padding: 0;
63
+ }
64
+
50
65
  /* Top "legend": text sitting on the top border line, background matching the
51
66
  panel's own bg color masks the border behind the text. */
52
67
  .bd-terminalmsg-panel-label {
@@ -107,21 +122,30 @@ export default css`
107
122
  font-weight: var(--typography-fontWeight-bold, 700);
108
123
  }
109
124
 
110
- /* === TYPED-LINE API (bd-terminal-message .lines=...) ===
111
- A literal sequence of terminal lines, each with its own semantic
112
- color/weight — for content like:
113
- $ npx skills add bitdefender/agent-skill-scanner → cmd
114
- ✓ agent-skill-scanner installed → ok
115
- ──────────────────────────────── → sep
116
- > scan the my-skill skill for security risks → ask
117
- ──────────────────────────────── → sep
118
- # Skill Scan: my-skill → strong
119
- - Severity: CLEAN → dim
120
- - Scan Date: 2026-06-15 → dim
121
- No security findings detected. → dim
122
- */
125
+ /* === CAPTION — small dim note inside the panel, below everything else
126
+ (lines/greeting/footer), e.g. "// illustrative — every connection
127
+ closes when the prompt ends". Sits inside the black box, unlike
128
+ bd-header-code's terminal-caption which renders below the whole card. */
129
+ .bd-terminalmsg-caption {
130
+ color: rgba(255, 255, 255, 0.35);
131
+ font-size: var(--typography-fontSize-xs);
132
+ margin-top: var(--spacing-16);
133
+ padding-top: var(--spacing-12);
134
+ border-top: 1px solid rgba(255, 255, 255, 0.08);
135
+ }
136
+
137
+ /* === TYPED-LINE API (bd-terminal-message .lines=...) === */
123
138
  .bd-terminalmsg-lines {
124
139
  display: block;
140
+ /* Container query context: the row layout below reacts to the
141
+ terminal's own rendered width, not the viewport's. This matters
142
+ because the terminal is often much narrower than the screen (e.g.
143
+ inside the VPN hero's tilted 3D scene) — a viewport-based media
144
+ query never fires there, even though the row is visually cramped,
145
+ which was squeezing the text column to near-zero width and
146
+ breaking it character by character. */
147
+ container-type: inline-size;
148
+ container-name: bd-terminalmsg-lines;
125
149
  }
126
150
 
127
151
  .bd-terminalmsg-l-cmd {
@@ -158,4 +182,120 @@ export default css`
158
182
  border-top: 1px solid rgba(255, 255, 255, 0.12);
159
183
  margin: var(--spacing-8) 0;
160
184
  }
185
+
186
+ /* === "title" line — bold header row with an optional "● LIVE" indicator,
187
+ e.g. "VPN for AI Agents · connection log" === */
188
+ .bd-terminalmsg-l-title {
189
+ display: flex;
190
+ align-items: center;
191
+ justify-content: space-between;
192
+ gap: var(--spacing-12);
193
+ color: var(--color-neutral-0, #fff);
194
+ font-weight: var(--typography-fontWeight-bold, 700);
195
+ padding-bottom: var(--spacing-16);
196
+ }
197
+
198
+ .bd-terminalmsg-live {
199
+ display: inline-flex;
200
+ align-items: center;
201
+ gap: var(--spacing-4, 4px);
202
+ color: #27c93f;
203
+ font-size: var(--typography-fontSize-xs);
204
+ font-weight: var(--typography-fontWeight-bold, 700);
205
+ letter-spacing: 0.05em;
206
+ flex-shrink: 0;
207
+ }
208
+
209
+ .bd-terminalmsg-live-dot {
210
+ width: 6px;
211
+ height: 6px;
212
+ border-radius: 50%;
213
+ background: #27c93f;
214
+ }
215
+
216
+ /* === "row" line — label / text / colored badge, 3-column layout.
217
+ Text wraps onto further lines while label and badge stay pinned. === */
218
+ .bd-terminalmsg-l-row {
219
+ display: grid;
220
+ grid-template-columns: 72px 1fr auto;
221
+ align-items: start;
222
+ column-gap: var(--spacing-12);
223
+ padding: var(--spacing-8) 0;
224
+ }
225
+
226
+ /* "flush" variant: each row gets its own hairline top border, standing
227
+ in for the panel border removed above and separating rows from each
228
+ other. The first row would otherwise show this border flush against
229
+ the host's own top padding, which reads fine here — no exception
230
+ needed. */
231
+ :host([variant="flush"]) .bd-terminalmsg-l-row {
232
+ border-top: 1px solid #ffffff17;
233
+ }
234
+
235
+ .bd-terminalmsg-l-row-label {
236
+ color: rgba(255, 255, 255, 0.35);
237
+ text-transform: uppercase;
238
+ font-size: var(--typography-fontSize-xs);
239
+ letter-spacing: 0.05em;
240
+ padding-top: 2px;
241
+ }
242
+
243
+ .bd-terminalmsg-l-row-text {
244
+ color: rgba(255, 255, 255, 0.85);
245
+ word-break: break-word;
246
+ }
247
+
248
+ .bd-terminalmsg-badge {
249
+ display: inline-flex;
250
+ align-items: center;
251
+ padding: 2px var(--spacing-12, 10px);
252
+ border-radius: var(--radius-full, 999px);
253
+ font-size: var(--typography-fontSize-xs);
254
+ font-weight: var(--typography-fontWeight-bold, 600);
255
+ white-space: nowrap;
256
+ margin-top: 1px;
257
+ }
258
+
259
+ .bd-terminalmsg-badge--green {
260
+ background: rgba(39, 201, 63, 0.15);
261
+ color: #27c93f;
262
+ }
263
+
264
+ .bd-terminalmsg-badge--blue {
265
+ background: rgba(122, 184, 255, 0.15);
266
+ color: #7ab8ff;
267
+ }
268
+
269
+ .bd-terminalmsg-badge--amber {
270
+ background: rgba(217, 119, 6, 0.2);
271
+ color: #f5a524;
272
+ }
273
+
274
+ .bd-terminalmsg-badge--neutral {
275
+ background: rgba(255, 255, 255, 0.12);
276
+ color: rgba(255, 255, 255, 0.75);
277
+ }
278
+
279
+ /* Below ~360px of the terminal's OWN width (not the viewport's), stack
280
+ label / text / badge vertically instead of forcing three columns into
281
+ too little space. Uses a container query, keyed to .bd-terminalmsg-lines
282
+ above, so this triggers based on the terminal's real rendered size,
283
+ which is what a viewport-based @media query could not do here — the
284
+ terminal is often much narrower than the screen (e.g. tilted inside
285
+ the VPN hero's 3D scene), so @media never fired even though the row
286
+ was visually cramped. */
287
+ @container bd-terminalmsg-lines (max-width: 360px) {
288
+ .bd-terminalmsg-l-row {
289
+ grid-template-columns: 1fr;
290
+ row-gap: var(--spacing-4, 4px);
291
+ }
292
+
293
+ .bd-terminalmsg-l-row-label {
294
+ padding-top: 0;
295
+ }
296
+
297
+ .bd-terminalmsg-badge {
298
+ justify-self: start;
299
+ }
300
+ }
161
301
  `;
@@ -20,12 +20,16 @@ class TerminalMessage extends LitElement {
20
20
  footerBold : { type: String, attribute: "footer-bold" },
21
21
  showCursor : { type: Boolean, attribute: "show-cursor" },
22
22
  hint : { type: String },
23
- // New: raw typed-line API, for terminals that are a literal sequence of
24
- // command/result lines (unlike greeting/intro/items, which model a
25
- // single chat-style message). Each entry: { type, text }.
26
- // type: "cmd" | "ok" | "ask" | "strong" | "dim" | "sep" | "space"
27
- // "sep" and "space" ignore `text`.
28
- lines : { type: Array }
23
+ lines : { type: Array },
24
+ caption : { type: String },
25
+ // "default" (existing look: optional titlebar dots, bordered panel,
26
+ // standard host padding) | "flush" — used where the terminal sits over
27
+ // decorative rings/a 3D scene (e.g. the VPN hero): hides the titlebar
28
+ // dots regardless of show-titlebar, drops the inner panel's own
29
+ // border (the host's outer box already reads as the terminal's edge),
30
+ // gives each "row" line a hairline top border instead, and tightens
31
+ // the host's own padding.
32
+ variant : { type: String, reflect: true }
29
33
  };
30
34
 
31
35
  static styles = [tokens, terminalMessageCSS];
@@ -44,9 +48,12 @@ class TerminalMessage extends LitElement {
44
48
  this.showCursor = false;
45
49
  this.hint = "";
46
50
  this.lines = [];
51
+ this.caption = "";
52
+ this.variant = "default";
47
53
  }
48
54
 
49
55
  _renderTitlebar() {
56
+ if (this.variant === "flush") return nothing;
50
57
  if (!this.showTitlebar) return nothing;
51
58
  return html`
52
59
  <div class="bd-terminalmsg-titlebar">
@@ -57,10 +64,6 @@ class TerminalMessage extends LitElement {
57
64
  `;
58
65
  }
59
66
 
60
- // Splits the hint text on bracketed key labels like "[Enter]" or "[esc]" and
61
- // wraps each one in a <strong> so it renders bold + white, while the rest of
62
- // the text keeps the dim hint color. Works with the plain string prop as-is —
63
- // no need to pass markup through `hint`.
64
67
  _renderHint() {
65
68
  if (!this.hint) return nothing;
66
69
 
@@ -82,7 +85,7 @@ class TerminalMessage extends LitElement {
82
85
 
83
86
  return html`
84
87
  <div class="bd-terminalmsg-lines">
85
- ${this.lines.map(({ type, text }) => {
88
+ ${this.lines.map(({ type, text, label, badge, badgeColor, live }) => {
86
89
  switch (type) {
87
90
  case "sep":
88
91
  return html`<hr class="bd-terminalmsg-l-sep" />`;
@@ -98,6 +101,25 @@ class TerminalMessage extends LitElement {
98
101
  return html`<div class="bd-terminalmsg-l-strong">${text}</div>`;
99
102
  case "dim":
100
103
  return html`<div class="bd-terminalmsg-l-dim">${text}</div>`;
104
+ case "title":
105
+ return html`
106
+ <div class="bd-terminalmsg-l-title">
107
+ <span>${text}</span>
108
+ ${live
109
+ ? html`<span class="bd-terminalmsg-live"><span class="bd-terminalmsg-live-dot"></span>LIVE</span>`
110
+ : nothing}
111
+ </div>
112
+ `;
113
+ case "row":
114
+ return html`
115
+ <div class="bd-terminalmsg-l-row">
116
+ <span class="bd-terminalmsg-l-row-label">${label}</span>
117
+ <span class="bd-terminalmsg-l-row-text">${text}</span>
118
+ ${badge
119
+ ? html`<span class="bd-terminalmsg-badge bd-terminalmsg-badge--${badgeColor || "neutral"}">${badge}</span>`
120
+ : nothing}
121
+ </div>
122
+ `;
101
123
  default:
102
124
  return html`<div class="bd-terminalmsg-l-dim">${text}</div>`;
103
125
  }
@@ -158,6 +180,10 @@ class TerminalMessage extends LitElement {
158
180
  : nothing}
159
181
 
160
182
  <slot></slot>
183
+
184
+ ${this.caption
185
+ ? html`<div class="bd-terminalmsg-caption">${this.caption}</div>`
186
+ : nothing}
161
187
  </div>
162
188
 
163
189
  ${this._renderHint()}