@genesislcap/ai-assistant 15.29.0 → 15.30.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.
@@ -742,6 +742,14 @@
742
742
  "module": "./utils/cost-session-history"
743
743
  }
744
744
  },
745
+ {
746
+ "kind": "js",
747
+ "name": "ResolvedDebugLogNoteConfig",
748
+ "declaration": {
749
+ "name": "ResolvedDebugLogNoteConfig",
750
+ "module": "./utils/resolve-debug-log-note"
751
+ }
752
+ },
745
753
  {
746
754
  "kind": "js",
747
755
  "name": "ModelTagAppearance",
@@ -2847,6 +2855,78 @@
2847
2855
  "default": "false",
2848
2856
  "description": "True while `downloadDebugLog` is building the log (GENC-1351 §5.8). Drives the\ndownload button's disabled + spinner state — the lifetime-stitch path is async\n(a provider `loadDiagnostics` round-trip), so without feedback a click looks\nlike nothing happened. Per-instance and transient (not shared/persisted): each\nelement has its own settings modal."
2849
2857
  },
2858
+ {
2859
+ "kind": "field",
2860
+ "name": "submittingDebugLog",
2861
+ "type": {
2862
+ "text": "boolean"
2863
+ },
2864
+ "default": "false",
2865
+ "description": "True while `submitDebugLog` is building and handing off the log. Same role as\n`downloadingDebugLog` for the Send button: the lifetime-stitch and the host's\n`send` callback are async, so the button needs a visible in-flight state."
2866
+ },
2867
+ {
2868
+ "kind": "field",
2869
+ "name": "debugLogSubmitResult",
2870
+ "type": {
2871
+ "text": "'sent' | 'error' | null"
2872
+ },
2873
+ "default": "null",
2874
+ "description": "Outcome of the last log submission, shown briefly on the button ('Sent' /\n'Failed — retry') then cleared by `setDebugLogSubmitResult`'s timer. `null` when idle."
2875
+ },
2876
+ {
2877
+ "kind": "field",
2878
+ "name": "debugLogSubmitResultTimer",
2879
+ "type": {
2880
+ "text": "ReturnType<typeof setTimeout> | undefined"
2881
+ },
2882
+ "privacy": "private",
2883
+ "description": "Timer that clears `debugLogSubmitResult` back to idle."
2884
+ },
2885
+ {
2886
+ "kind": "field",
2887
+ "name": "debugLogComposeOpen",
2888
+ "type": {
2889
+ "text": "boolean"
2890
+ },
2891
+ "default": "false",
2892
+ "description": "Whether the agent-log compose box (note + Send/Cancel) is open. Opened by the row's\nSend button when `debugLogSubmit.note` is not `false`; closed by Cancel or a\nsuccessful send. Stays open after a failure so the typed note is not lost."
2893
+ },
2894
+ {
2895
+ "kind": "field",
2896
+ "name": "debugLogNote",
2897
+ "type": {
2898
+ "text": "string"
2899
+ },
2900
+ "default": "''",
2901
+ "description": "The note typed in the compose box, raw (trimmed only at submit time)."
2902
+ },
2903
+ {
2904
+ "kind": "field",
2905
+ "name": "debugLogNoteEl",
2906
+ "type": {
2907
+ "text": "HTMLElement | undefined"
2908
+ },
2909
+ "description": "Bound to the compose box's text-area via the template ref, for focus on open."
2910
+ },
2911
+ {
2912
+ "kind": "field",
2913
+ "name": "debugLogSubmitResultFlashMs",
2914
+ "default": "4000",
2915
+ "description": "How long 'Sent' shows before idle. Overridable so tests need not wait 4 seconds.",
2916
+ "type": {
2917
+ "text": "number"
2918
+ }
2919
+ },
2920
+ {
2921
+ "kind": "field",
2922
+ "name": "debugLogSubmitGeneration",
2923
+ "type": {
2924
+ "text": "number"
2925
+ },
2926
+ "privacy": "private",
2927
+ "default": "0",
2928
+ "description": "Bumped by `resetDebugLogSubmitState`. An in-flight `submitDebugLog` captures it and\ndrops its continuation when a reset (disconnect, session switch, Clear) happened\nwhile it awaited — otherwise the stale submission would write state, arm a timer on\na torn-down element, or report 'Sent' into a session it never belonged to."
2929
+ },
2850
2930
  {
2851
2931
  "kind": "field",
2852
2932
  "name": "settingsModalTab",
@@ -4099,6 +4179,105 @@
4099
4179
  "description": "Whether session token usage should render on the Usage tab.",
4100
4180
  "readonly": true
4101
4181
  },
4182
+ {
4183
+ "kind": "field",
4184
+ "name": "settingsAgentLogSectionVisible",
4185
+ "type": {
4186
+ "text": "boolean"
4187
+ },
4188
+ "description": "Whether the settings \"Agent log\" section renders — shown when either action is\nenabled: the download button (`allowDebugDownload`) or the host-transport Send\nbutton (`debugLogSubmit`). Each button is additionally gated on its own flag\ninside the section, so a host can enable one without the other.",
4189
+ "readonly": true
4190
+ },
4191
+ {
4192
+ "kind": "field",
4193
+ "name": "debugLogNoteConfig",
4194
+ "type": {
4195
+ "text": "ResolvedDebugLogNoteConfig | null"
4196
+ },
4197
+ "description": "The resolved compose-box settings for the agent-log Send button, or `null` when the\nhost opted out (`debugLogSubmit.note: false`) and the button sends on first click.",
4198
+ "readonly": true
4199
+ },
4200
+ {
4201
+ "kind": "field",
4202
+ "name": "debugLogNoteMissing",
4203
+ "type": {
4204
+ "text": "boolean"
4205
+ },
4206
+ "description": "Whether the typed note counts as empty — the ONE emptiness rule, shared by the\ncompose box's disabled state and its \"required\" hint so the two cannot drift apart.",
4207
+ "readonly": true
4208
+ },
4209
+ {
4210
+ "kind": "field",
4211
+ "name": "debugLogSubmitLabel",
4212
+ "type": {
4213
+ "text": "string"
4214
+ },
4215
+ "description": "The Send button's idle label, as the host configured it.",
4216
+ "readonly": true
4217
+ },
4218
+ {
4219
+ "kind": "field",
4220
+ "name": "debugLogSubmitButtonLabel",
4221
+ "type": {
4222
+ "text": "string"
4223
+ },
4224
+ "description": "Label on the agent-log row's Send button. While the compose box is open the row\nbutton is just the (disabled) trigger, so it keeps its idle label; otherwise it\nreflects the in-flight / flashed outcome of the last submission.",
4225
+ "readonly": true
4226
+ },
4227
+ {
4228
+ "kind": "field",
4229
+ "name": "debugLogComposeHint",
4230
+ "type": {
4231
+ "text": "string"
4232
+ },
4233
+ "description": "The compose box's footer hint: a failure first, then the \"required\" nudge, else the\nlive counter. Visual only — the same information reaches assistive technology via\n`debugLogNoteAriaLabel` (counter, required) and `debugLogSubmitAnnouncement` (outcome),\nbecause IDREF attributes such as `aria-describedby` cannot point across the\ndesign-system text-area's shadow boundary.",
4234
+ "readonly": true
4235
+ },
4236
+ {
4237
+ "kind": "field",
4238
+ "name": "debugLogNoteAriaLabel",
4239
+ "type": {
4240
+ "text": "string"
4241
+ },
4242
+ "description": "Accessible name for the note. Deliberately STATIC apart from \"(required)\": a name\nthat changed per keystroke would be re-read in full by NVDA on every key and never\nupdated by JAWS. The running count reaches AT through `debugLogSubmitAnnouncement`\nat the thresholds where it matters.",
4243
+ "readonly": true
4244
+ },
4245
+ {
4246
+ "kind": "field",
4247
+ "name": "debugLogSubmitAnnouncement",
4248
+ "type": {
4249
+ "text": "string"
4250
+ },
4251
+ "description": "Text for the always-present live region beside the agent-log row, so the outcome of\na submission is announced even when the compose box is closed or opted out\n(`note: false`), where the only visible change is the button label.",
4252
+ "readonly": true
4253
+ },
4254
+ {
4255
+ "kind": "field",
4256
+ "name": "debugLogRowDescription",
4257
+ "type": {
4258
+ "text": "string"
4259
+ },
4260
+ "description": "The agent-log row's description, phrased for whichever actions the host enabled.\nSend is called out as transmitting: Download keeps the log on the user's machine,\nSend hands the full conversation to wherever the host's transport delivers it.",
4261
+ "readonly": true
4262
+ },
4263
+ {
4264
+ "kind": "field",
4265
+ "name": "debugLogSendDisabled",
4266
+ "type": {
4267
+ "text": "boolean"
4268
+ },
4269
+ "description": "Whether the compose box's Send button is inert: a send is already in flight, or the\nhost made the note required and it is still blank.",
4270
+ "readonly": true
4271
+ },
4272
+ {
4273
+ "kind": "field",
4274
+ "name": "debugLogNoteCounter",
4275
+ "type": {
4276
+ "text": "string"
4277
+ },
4278
+ "description": "Live \"typed / max\" counter for the compose box.",
4279
+ "readonly": true
4280
+ },
4102
4281
  {
4103
4282
  "kind": "field",
4104
4283
  "name": "settingsCogVisible",
@@ -4293,6 +4472,127 @@
4293
4472
  }
4294
4473
  }
4295
4474
  },
4475
+ {
4476
+ "kind": "method",
4477
+ "name": "submitDebugLog",
4478
+ "return": {
4479
+ "type": {
4480
+ "text": "Promise<void>"
4481
+ }
4482
+ },
4483
+ "description": "Hand the agent log to the host's `ui.debugLogSubmit.send` callback — the Send\nbutton next to Download. Reuses `buildDownloadLog`, so the submitted log is\nbyte-identical to what Download saves (lifetime-stitched when the provider\npersists diagnostics). The assistant is vendor-agnostic: the callback owns the\ntransport (Sentry feedback, a support API, an upload endpoint). Outcome lands in\n`debugLogSubmitResult` so the button can flash 'Sent'/'Failed'; failures also go\nto the logger with the cause."
4484
+ },
4485
+ {
4486
+ "kind": "field",
4487
+ "name": "debugLogAgentName",
4488
+ "type": {
4489
+ "text": "string"
4490
+ },
4491
+ "privacy": "private",
4492
+ "description": "The agent name stamped on the log: the active agent, else the header title.",
4493
+ "readonly": true
4494
+ },
4495
+ {
4496
+ "kind": "method",
4497
+ "name": "debugLogFilename",
4498
+ "privacy": "private",
4499
+ "return": {
4500
+ "type": {
4501
+ "text": "string"
4502
+ }
4503
+ },
4504
+ "description": "Filename for the agent log — the ONE derivation Download saves under and Send hands\nto the host, so `ChatDebugLogSubmission.filename`'s \"same stem as the download\"\npromise is enforced rather than relying on two copies agreeing."
4505
+ },
4506
+ {
4507
+ "kind": "method",
4508
+ "name": "resetDebugLogSubmitState",
4509
+ "privacy": "private",
4510
+ "return": {
4511
+ "type": {
4512
+ "text": "void"
4513
+ }
4514
+ },
4515
+ "description": "Back to idle: nothing in flight, no flash, no open compose box, no note. Called on\ndisconnect and on a session switch / Clear (a note typed against one conversation\nmust not caption the next one's log). On disconnect — the\nflash timer would otherwise fire against a torn-down element, and clearing ONLY the\ntimer would strand `debugLogSubmitResult` at 'sent'/'error' for good on a pop-out /\npop-in (nothing else resets it), with the box remounting open on a stale note."
4516
+ },
4517
+ {
4518
+ "kind": "method",
4519
+ "name": "openDebugLogCompose",
4520
+ "return": {
4521
+ "type": {
4522
+ "text": "void"
4523
+ }
4524
+ },
4525
+ "description": "The row's Send button. With a compose box configured (the default) it opens the box\nand focuses the note so the user can caption the log; with `note: false` it sends\nstraight away, as before."
4526
+ },
4527
+ {
4528
+ "kind": "method",
4529
+ "name": "noteDebugLogInput",
4530
+ "return": {
4531
+ "type": {
4532
+ "text": "void"
4533
+ }
4534
+ },
4535
+ "parameters": [
4536
+ {
4537
+ "name": "value",
4538
+ "type": {
4539
+ "text": "string"
4540
+ }
4541
+ }
4542
+ ],
4543
+ "description": "The note's `@input`: track the text, and let typing dismiss a standing failure."
4544
+ },
4545
+ {
4546
+ "kind": "method",
4547
+ "name": "cancelDebugLogCompose",
4548
+ "return": {
4549
+ "type": {
4550
+ "text": "void"
4551
+ }
4552
+ },
4553
+ "description": "Close the compose box and discard the typed note."
4554
+ },
4555
+ {
4556
+ "kind": "method",
4557
+ "name": "restoreDebugLogTriggerFocus",
4558
+ "privacy": "private",
4559
+ "return": {
4560
+ "type": {
4561
+ "text": "void"
4562
+ }
4563
+ },
4564
+ "description": "Closing the compose box unmounts the focused text-area, which drops focus to the\ndocument body and strands keyboard and screen-reader users. Hand it back to the row's\nSend button — next frame, once the `when` block has torn down and the button, disabled\nwhile the box was open, is interactive again."
4565
+ },
4566
+ {
4567
+ "kind": "method",
4568
+ "name": "restoreDebugLogRetryFocus",
4569
+ "privacy": "private",
4570
+ "return": {
4571
+ "type": {
4572
+ "text": "void"
4573
+ }
4574
+ },
4575
+ "description": "After a FAILED send the controls come back but the element that started the send\nwas disabled meanwhile, so focus has already dropped to the document body. Put it\nwhere the retry happens: the note when the box is open, else the row trigger."
4576
+ },
4577
+ {
4578
+ "kind": "method",
4579
+ "name": "setDebugLogSubmitResult",
4580
+ "privacy": "private",
4581
+ "return": {
4582
+ "type": {
4583
+ "text": "void"
4584
+ }
4585
+ },
4586
+ "parameters": [
4587
+ {
4588
+ "name": "result",
4589
+ "type": {
4590
+ "text": "'sent' | 'error'"
4591
+ }
4592
+ }
4593
+ ],
4594
+ "description": "Record the submit outcome. 'sent' flashes and falls back to idle; 'error' PERSISTS\nuntil the user acts (types, reopens the box, cancels, or retries) — a failure that\nsilently reverted to the counter after four seconds left no trace it had happened."
4595
+ },
4296
4596
  {
4297
4597
  "kind": "method",
4298
4598
  "name": "buildDownloadLog",
@@ -7567,6 +7867,117 @@
7567
7867
  }
7568
7868
  ]
7569
7869
  },
7870
+ {
7871
+ "kind": "javascript-module",
7872
+ "path": "src/utils/resolve-debug-log-note.ts",
7873
+ "declarations": [
7874
+ {
7875
+ "kind": "variable",
7876
+ "name": "DEBUG_LOG_NOTE_DEFAULT_MAX_LENGTH",
7877
+ "type": {
7878
+ "text": "number"
7879
+ },
7880
+ "default": "500",
7881
+ "description": "Default cap on the user's note. Short by design — it is a caption for the log, not a report."
7882
+ },
7883
+ {
7884
+ "kind": "variable",
7885
+ "name": "DEBUG_LOG_NOTE_DEFAULT_PLACEHOLDER",
7886
+ "type": {
7887
+ "text": "string"
7888
+ },
7889
+ "default": "'What were you doing, or what went wrong? (optional)'",
7890
+ "description": "Default prompt in the empty note."
7891
+ },
7892
+ {
7893
+ "kind": "variable",
7894
+ "name": "DEBUG_LOG_NOTE_REQUIRED_PLACEHOLDER",
7895
+ "type": {
7896
+ "text": "string"
7897
+ },
7898
+ "default": "'What were you doing, or what went wrong?'",
7899
+ "description": "The same prompt for a `required` note — \"(optional)\" would contradict the disabled Send."
7900
+ },
7901
+ {
7902
+ "kind": "function",
7903
+ "name": "resolveDebugLogNoteConfig",
7904
+ "return": {
7905
+ "type": {
7906
+ "text": "ResolvedDebugLogNoteConfig | null"
7907
+ }
7908
+ },
7909
+ "parameters": [
7910
+ {
7911
+ "name": "config",
7912
+ "type": {
7913
+ "text": "ChatDebugLogSubmitConfig | undefined"
7914
+ }
7915
+ }
7916
+ ],
7917
+ "description": "Resolve `debugLogSubmit.note` — `undefined`/`true` mean \"compose box with defaults\",\n`false` means \"no compose box, send on first click\" (→ `null`), and an object customises\nthe box. Keeps the template free of the boolean-or-object dance."
7918
+ },
7919
+ {
7920
+ "kind": "function",
7921
+ "name": "normalizeDebugLogNote",
7922
+ "return": {
7923
+ "type": {
7924
+ "text": "string | undefined"
7925
+ }
7926
+ },
7927
+ "parameters": [
7928
+ {
7929
+ "name": "note",
7930
+ "type": {
7931
+ "text": "string"
7932
+ }
7933
+ }
7934
+ ],
7935
+ "description": "Normalise the typed note for the submission: trimmed, and `undefined` when empty so a\nhost can `message ?? fallback` without checking for whitespace."
7936
+ }
7937
+ ],
7938
+ "exports": [
7939
+ {
7940
+ "kind": "js",
7941
+ "name": "DEBUG_LOG_NOTE_DEFAULT_MAX_LENGTH",
7942
+ "declaration": {
7943
+ "name": "DEBUG_LOG_NOTE_DEFAULT_MAX_LENGTH",
7944
+ "module": "src/utils/resolve-debug-log-note.ts"
7945
+ }
7946
+ },
7947
+ {
7948
+ "kind": "js",
7949
+ "name": "DEBUG_LOG_NOTE_DEFAULT_PLACEHOLDER",
7950
+ "declaration": {
7951
+ "name": "DEBUG_LOG_NOTE_DEFAULT_PLACEHOLDER",
7952
+ "module": "src/utils/resolve-debug-log-note.ts"
7953
+ }
7954
+ },
7955
+ {
7956
+ "kind": "js",
7957
+ "name": "DEBUG_LOG_NOTE_REQUIRED_PLACEHOLDER",
7958
+ "declaration": {
7959
+ "name": "DEBUG_LOG_NOTE_REQUIRED_PLACEHOLDER",
7960
+ "module": "src/utils/resolve-debug-log-note.ts"
7961
+ }
7962
+ },
7963
+ {
7964
+ "kind": "js",
7965
+ "name": "resolveDebugLogNoteConfig",
7966
+ "declaration": {
7967
+ "name": "resolveDebugLogNoteConfig",
7968
+ "module": "src/utils/resolve-debug-log-note.ts"
7969
+ }
7970
+ },
7971
+ {
7972
+ "kind": "js",
7973
+ "name": "normalizeDebugLogNote",
7974
+ "declaration": {
7975
+ "name": "normalizeDebugLogNote",
7976
+ "module": "src/utils/resolve-debug-log-note.ts"
7977
+ }
7978
+ }
7979
+ ]
7980
+ },
7570
7981
  {
7571
7982
  "kind": "javascript-module",
7572
7983
  "path": "src/utils/resolve-preference-baseline.ts",
@@ -13081,7 +13492,7 @@
13081
13492
  {
13082
13493
  "kind": "variable",
13083
13494
  "name": "settingsModalStyles",
13084
- "default": "css`\n /*\n * Section headings come from the shared fragment the package also exports, so a host titling\n * its own slotted section applies the same rule rather than a copy of it.\n */\n ${assistantSettingsSectionTitleStyles}\n\n *,\n *::before,\n *::after {\n box-sizing: border-box;\n }\n\n .settings-modal {\n --ai-tier-badge-bg-mix: 14%;\n --ai-tier-badge-text-lighten: 18%;\n }\n\n .settings-modal::part(dialog) {\n max-width: 620px;\n width: calc(100vw - 48px);\n max-height: calc(100vh - 48px);\n padding: 0;\n }\n\n .settings-modal::part(content) {\n display: flex;\n flex-direction: column;\n min-height: 0;\n padding: 0;\n width: 100%;\n }\n\n .settings-modal::part(top) {\n padding: calc(var(--design-unit) * 4px) calc(var(--design-unit) * 5px);\n border-bottom: 1px solid var(--neutral-stroke-rest);\n }\n\n .settings-modal::part(bottom) {\n padding: calc(var(--design-unit) * 4px) calc(var(--design-unit) * 5px);\n border-top: 1px solid var(--neutral-stroke-rest);\n border-bottom-left-radius: var(--card-border-radius, calc(var(--control-corner-radius) * 1px));\n border-bottom-right-radius: var(--card-border-radius, calc(var(--control-corner-radius) * 1px));\n background-color: var(--neutral-layer-2);\n }\n\n .settings-modal-header {\n display: flex;\n align-items: center;\n min-width: 0;\n }\n\n .settings-modal-title {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: calc(var(--design-unit) * 2px);\n color: var(--neutral-foreground-rest);\n }\n\n .settings-modal-content {\n display: flex;\n flex-direction: column;\n min-height: 0;\n flex: 1 1 auto;\n }\n\n .settings-modal-tabs::part(tablist) {\n border-bottom: 0;\n padding: 0 calc(var(--design-unit) * 5px);\n column-gap: calc(var(--design-unit) * 5px);\n }\n\n .settings-modal-tabs::part(activeIndicator) {\n height: 2px;\n }\n\n .settings-modal-tab {\n padding: 0;\n font-weight: 600;\n gap: 6px;\n }\n\n .settings-modal-tab[aria-selected='true'] {\n color: var(--neutral-foreground-rest);\n }\n\n .settings-modal-tabs::part(tabpanel) {\n border-top: 1px solid var(--neutral-stroke-rest);\n }\n\n .settings-modal-tab-panel {\n display: flex;\n flex-direction: column;\n min-height: 0;\n flex: 1 1 auto;\n padding: 0;\n border-radius: 0;\n }\n\n .settings-modal-tab-panel[hidden] {\n display: none !important;\n }\n\n .settings-modal-body {\n overflow-y: auto;\n padding: 0 calc(var(--design-unit) * 5px) calc(var(--design-unit) * 2px);\n max-height: min(60vh, 520px);\n }\n\n .settings-modal-section {\n padding: calc(var(--design-unit) * 5px) 0;\n border-bottom: 1px solid var(--neutral-stroke-rest);\n }\n\n .settings-modal-section:last-child {\n border-bottom: none;\n }\n\n /*\n * Only the spacing. Everything else about this heading comes from the exported fragment\n * above, which the assistant and its hosts share; margin is deliberately not in there,\n * since the gap below a heading depends on the layout around it.\n */\n .ai-settings-section-title {\n margin: 0 0 calc(var(--design-unit) * 3px);\n }\n\n .settings-modal-section-note {\n margin: calc(var(--design-unit) * -2px) 0 calc(var(--design-unit) * 3px);\n font-size: 12px;\n line-height: 1.5;\n color: var(--neutral-foreground-hint);\n }\n\n .settings-modal-section-body {\n display: flex;\n flex-direction: column;\n gap: calc(var(--design-unit) * 4px);\n }\n\n .settings-toggle-row {\n display: flex;\n align-items: flex-start;\n gap: calc(var(--design-unit) * 3px);\n padding: 0 0 calc(var(--design-unit) * 4px) 0;\n border-bottom: 1px solid var(--neutral-stroke-rest);\n }\n\n .settings-toggle-row:last-child {\n border-bottom: none;\n padding-bottom: calc(var(--design-unit) * 1px);\n }\n\n .settings-toggle-row.is-stacked {\n flex-direction: column;\n gap: calc(var(--design-unit) * 2px);\n }\n\n /*\n * For rows whose control is a button rather than a switch. The base row top-aligns, which suits\n * a switch (it lands level with the title), but a button is tall enough that top-aligning leaves\n * it above the title-plus-description block it acts on.\n */\n .settings-toggle-row.is-centered {\n align-items: center;\n }\n\n .settings-animation-list {\n display: flex;\n flex-direction: column;\n width: 100%;\n border: 1px solid var(--neutral-stroke-rest);\n border-radius: calc(var(--control-corner-radius) * 1.2px);\n padding: calc(var(--design-unit) * 2px);\n gap: calc(var(--design-unit) * 2px);\n }\n\n .settings-animation-list .settings-toggle-row {\n border: 0;\n }\n\n .settings-animation-category {\n display: flex;\n flex-direction: column;\n gap: calc(var(--design-unit) * 4px);\n }\n\n .settings-animation-category-label {\n font-weight: 600;\n color: var(--neutral-foreground-hint);\n }\n\n .settings-toggle-row + .settings-animation-category-label {\n border-top: 1px solid var(--neutral-stroke-rest);\n padding-top: calc(var(--design-unit) * 2px);\n }\n\n .settings-animation-option {\n padding: 0;\n margin: 0;\n }\n\n .settings-animation-option:last-child {\n border-bottom: none;\n padding-bottom: calc(var(--design-unit) * 2px);\n }\n\n .settings-toggle-text {\n flex: 1;\n min-width: 0;\n }\n\n .settings-toggle-title {\n font-size: 14px;\n font-weight: 500;\n color: var(--neutral-foreground-rest);\n }\n\n .settings-toggle-desc {\n font-size: 12px;\n color: var(--neutral-foreground-hint);\n line-height: 1.5;\n max-width: 92%;\n }\n\n .settings-toggle-control {\n flex: 0 0 auto;\n min-width: 0;\n }\n\n .settings-toggle-control-wide {\n width: 100%;\n max-width: 280px;\n }\n\n .settings-toggle-row.is-stacked .settings-toggle-desc {\n max-width: none;\n }\n\n .settings-toggle-row.is-stacked .settings-toggle-control-wide {\n width: 100%;\n max-width: none;\n }\n\n /*\n * Sub-heading over the provider toggle group. Unlike the section headings it sits INSIDE\n * .settings-modal-section-body, so the parent's 4-unit flex gap already separates it from the\n * first toggle — and flex does not collapse margins, so the shared rule's 3-unit margin-bottom\n * would add to that gap rather than replace it, leaving the label adrift from the rows it\n * names. Zero the margin and pull back 2 of the 4 gap units, expressed in the same token so it\n * tracks if that gap changes.\n */\n .settings-app-toggles-title {\n margin: 0 0 calc(var(--design-unit) * -2px);\n }\n\n .settings-app-toggle-block {\n display: flex;\n flex-direction: column;\n gap: calc(var(--design-unit) * 1px);\n }\n\n .settings-toggle-hint {\n font-size: 12px;\n color: var(--neutral-foreground-hint);\n line-height: 1.4;\n padding-left: calc(var(--design-unit) * 1px);\n font-style: italic;\n }\n\n /*\n * The budget meter (GENC-1464) is the context indicator's money sibling and\n * shares its row anatomy 1:1, so the budget classes JOIN these rules rather\n * than restating them — one place to restyle the header/label/figures shape,\n * and the two indicators cannot drift apart. Design-system tokens only, and\n * unfallbacked: every token here ships a DS default, so a var(--x, y)\n * fallback would be dead code that hides a broken token name (#2411/#2436\n * review rule, pinned by settings-modal.styles.test.ts).\n */\n .settings-context-header,\n .settings-budget-header {\n display: flex;\n justify-content: space-between;\n gap: calc(var(--design-unit) * 2px);\n margin-bottom: calc(var(--design-unit) * 2px);\n font-size: 12px;\n }\n\n .settings-context-label,\n .settings-budget-label {\n color: var(--neutral-foreground-hint);\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n }\n\n .settings-context-tokens,\n .settings-budget-figures {\n color: var(--neutral-foreground-rest);\n }\n\n /* Freshness footer (GENC-1464): refresh button + label under the vendor\n rows, left-aligned — a footnote to the figures above it. The button's\n inline padding is pinned and cancelled by the container margin so the\n ICON GLYPH (not the button box) sits flush with the budget labels'\n left edge, whatever the density tokens say. */\n .settings-budget-toolbar {\n display: flex;\n justify-content: flex-start;\n align-items: center;\n gap: 4px;\n margin-inline-start: -4px;\n }\n\n .settings-budget-refresh::part(control) {\n padding-inline: 4px;\n }\n\n .settings-budget-updated {\n color: var(--neutral-foreground-hint);\n font-size: 11px;\n }\n\n /*\n * ONE rhythm for every meter row. The outer wrapper holds the context\n * indicator and the budget meter; the inner one holds the budget meter's\n * vendor rows — and both gap by the same 2 units (half the section body's 4)\n * so that visually identical meter rows are evenly spaced whatever mix of\n * them is on screen. Without the wrapper the context row inherits the body's\n * 4-unit gap while the vendor rows keep 2, and three identical-looking rows\n * read as an uneven 4/2/2. The wrapper renders only when at least one meter\n * does — see settingsUsageMetersTemplate for why an always-on one would cost\n * a stray gap.\n */\n .settings-usage-meters,\n .settings-budget-usage {\n display: flex;\n flex-direction: column;\n gap: calc(var(--design-unit) * 2px);\n }\n\n .settings-current-build,\n .settings-lifetime-usage {\n background: var(--neutral-layer-2);\n border: 1px solid var(--neutral-stroke-rest);\n border-radius: calc(var(--control-corner-radius) * 1.5px);\n padding: calc(var(--design-unit) * 4px);\n margin: calc(var(--design-unit) * 3px) 0;\n }\n\n /*\n * Deliberately quieter than the live block: no pulsing badge and no accent, so the eye lands\n * on what is being built now — which is why that block leads the tab and this one follows,\n * under the history heading whose rows it totals.\n */\n .settings-lifetime-usage-top {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: calc(var(--design-unit) * 2px);\n margin-bottom: calc(var(--design-unit) * 3px);\n }\n\n .settings-lifetime-label {\n font-size: 10px;\n line-height: 1;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--neutral-foreground-hint);\n }\n\n .settings-current-build-top {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: calc(var(--design-unit) * 2px);\n margin-bottom: calc(var(--design-unit) * 3px);\n }\n\n /*\n * Optically centring these 10px caps against the 14px project name beside them. Flex offers\n * only two alignments and neither lands it, because a box centre and a text baseline are\n * different lines:\n * - align-items: center sits the badge baseline about 1.2px high\n * - align-items: baseline matches baselines, but the caps then read as bottom-aligned\n * against the name's ascenders, so the badge looks low\n * The eye wants the midpoint, so: centre the boxes, then translate down by the ~1px of\n * overshoot. This is a nudge, but it corrects a fixed relationship between two font sizes\n * rather than some neighbouring element's layout, so unlike a margin tuned to a sibling it\n * cannot rot when that sibling changes. In em, so it tracks the badge text.\n *\n * display: block, not inline-flex: a flex container has no text baseline of its own and\n * synthesizes one from its first child, which here is the dot, an empty span. As a block box\n * the badge takes the baseline of its first line, i.e. the text.\n */\n .settings-live-badge {\n display: block;\n font-size: 10px;\n line-height: 1;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--accent-fill-rest);\n white-space: nowrap;\n transform: translateY(0.1em);\n }\n\n .settings-live-dot {\n display: inline-block;\n width: 7px;\n height: 7px;\n\n /* Replaces the flex gap the badge no longer has. */\n margin-right: calc(var(--design-unit) * 1px);\n\n /* Centres the dot on the text beside it without disturbing that text's baseline. */\n vertical-align: middle;\n border-radius: 50%;\n background: var(--accent-fill-rest);\n animation: settings-live-pulse 1.6s ease-out infinite;\n }\n\n @keyframes settings-live-pulse {\n 0% {\n box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent-fill-rest) 55%, transparent);\n }\n\n 70% {\n box-shadow: 0 0 0 7px transparent;\n }\n\n 100% {\n box-shadow: 0 0 0 0 transparent;\n }\n }\n\n .settings-current-build-name {\n font-size: 14px;\n line-height: 1;\n font-weight: 600;\n }\n\n /*\n * Cost and the token buckets side by side: one number in its own box, the four buckets\n * sharing the box next to it. Stretch, so the two are the same height however tall the 22px\n * cost value makes the left one.\n */\n .settings-usage-row {\n display: flex;\n flex-wrap: wrap;\n align-items: stretch;\n gap: calc(var(--design-unit) * 3px);\n margin-bottom: calc(var(--design-unit) * 3px);\n }\n\n .settings-usage-row-tokens {\n display: flex;\n flex: 1 1 auto;\n min-width: 0;\n }\n\n .settings-build-stat {\n min-width: 0;\n background: var(--neutral-layer-1);\n border: 1px solid var(--neutral-stroke-rest);\n border-radius: calc(var(--control-corner-radius) * 1px);\n padding: calc(var(--design-unit) * 3px);\n }\n\n .settings-build-stat-label {\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--neutral-foreground-hint);\n }\n\n .settings-build-stat-value {\n font-size: 22px;\n font-weight: 700;\n margin-top: calc(var(--design-unit) * 1px);\n color: var(--neutral-foreground-rest);\n }\n\n .settings-build-stat-value .prefix,\n .settings-build-stat-value .suffix {\n color: var(--accent-fill-rest);\n }\n\n /*\n * Per-bucket token split, beneath the headline cost. Small paired label/value cells\n * rather than four more stat cards: they are the detail behind the cost above, so they\n * have to read as subordinate to it rather than compete with it. The four buckets ARE\n * the token figure now — there is no merged total anywhere for them to break down.\n */\n .settings-token-breakdown {\n display: flex;\n flex-direction: column;\n\n /*\n * Tight against the buckets below. One design unit rather than two, because each bucket\n * separates its own label from its value by only 2px — at two units the title sat four\n * times further from the bucket labels than they sit from their own numbers, which read\n * as a gap between unrelated blocks instead of a heading over its content.\n */\n gap: calc(var(--design-unit) * 1px);\n margin-bottom: calc(var(--design-unit) * 3px);\n padding: calc(var(--design-unit) * 2px) calc(var(--design-unit) * 3px);\n background: var(--neutral-layer-1);\n border: 1px solid var(--neutral-stroke-rest);\n border-radius: calc(var(--control-corner-radius) * 1px);\n }\n\n /*\n * Titles the box, because nothing else in it named the unit. Same styling and position as\n * the cost box's label, so two boxes sitting side by side are titled the same way; the\n * hierarchy against the bucket labels comes from position, not a second type size.\n */\n .settings-token-breakdown-label {\n font-size: 10px;\n line-height: 1;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--neutral-foreground-hint);\n }\n\n .settings-token-buckets {\n display: flex;\n flex-wrap: wrap;\n gap: calc(var(--design-unit) * 4px);\n }\n\n .settings-token-bucket {\n display: flex;\n\n /*\n * min-content (not 0) so a bucket cannot be shrunk narrower than its own unbreakable label.\n * With the label set to nowrap, a zero minimum would overflow it into the next column instead\n * of wrapping — so the container's flex-wrap takes over and moves a bucket to a second row,\n * which is the degradation we want when the modal is dragged narrow.\n */\n min-width: min-content;\n flex-direction: column;\n gap: 2px;\n }\n\n .settings-token-bucket-label {\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--neutral-foreground-hint);\n\n /*\n * One line, always. The rate marker is a separate inline box after collapsible whitespace, so\n * a wrappable label gives it a break opportunity of its own — in a narrow column it orphaned\n * onto line 2, which also pushed that bucket's value a line below the other three and broke\n * the row of figures. nowrap removes every break opportunity in the label, the space before\n * the marker included, so no glue character is needed.\n */\n white-space: nowrap;\n }\n\n .settings-token-bucket-value {\n font-size: 13px;\n font-weight: 600;\n color: var(--neutral-foreground-rest);\n }\n\n /*\n * The price-direction marker on a cache bucket's label — down for reads (a fraction of the\n * uncached input rate), up for writes (a premium over it). Three tiers, so a bucket with no\n * marker is the reference rate rather than an unlabelled fourth case.\n *\n * Carried by the label rather than the value, which is what this used to do: cache reads are\n * usually the largest bucket by a wide margin in an agentic session, so the value was muted to\n * stop the biggest number reading as the dominant cost driver. That priced the treatment to the\n * wrong thing — a dimmed 0 (every Gemini cache write) looked disabled next to a normal 0, and a\n * rate is a property of the bucket, not of this turn's figure.\n *\n * Sized down and nudged up rather than tinted: the label is already the hint colour, so a\n * dimmer marker would vanish and a brighter one would out-shout the word it qualifies.\n */\n .settings-token-bucket-rate {\n font-size: 8px;\n line-height: 1;\n vertical-align: 0.15em;\n letter-spacing: 0;\n }\n\n /*\n * Usage-row overrides. Placed after the base rules they refine rather than up beside\n * .settings-usage-row itself, because stylelint's no-descending-specificity rejects a\n * compound selector appearing before the plain one it overrides.\n */\n\n /* Sized by its content; the buckets take the rest, since four cells need the width. */\n .settings-usage-row > .settings-build-stat {\n flex: 0 1 auto;\n }\n\n .settings-usage-row .settings-token-breakdown {\n flex: 1 1 auto;\n\n /* The row owns the spacing now; this centres the column against the taller cost box. */\n justify-content: center;\n margin-bottom: 0;\n }\n\n /*\n * Basis auto, not 0: a zero basis splits the row into four equal columns, so CACHE WRITE is\n * squeezed exactly as hard as INPUT despite being twice the label. Sizing from content gives the\n * long labels the room their text needs and lets the short ones concede it, which is what makes\n * white-space: nowrap above safe — every column starts at least as wide as its own content,\n * then shares the slack. Still grows and shrinks, so the four stay flush edge to edge.\n */\n .settings-usage-row .settings-token-bucket {\n flex: 1 1 auto;\n }\n\n .settings-model-tags {\n display: flex;\n flex-wrap: wrap;\n gap: calc(var(--design-unit) * 2px);\n }\n\n .settings-model-tag {\n font-size: 11px;\n font-weight: 600;\n padding: 3px 9px;\n border-radius: 20px;\n font-family: ui-monospace, monospace;\n border: 1px solid var(--neutral-stroke-rest);\n }\n\n .settings-model-tag,\n .settings-cost-history-icon {\n --model-tag-color: var(--neutral-foreground-rest);\n\n background: color-mix(\n in srgb,\n var(--model-tag-color) var(--ai-tier-badge-bg-mix),\n var(--neutral-layer-1)\n );\n border-color: color-mix(in srgb, var(--model-tag-color) 20%, var(--neutral-layer-1));\n color: color-mix(in srgb, var(--model-tag-color), white var(--ai-tier-badge-text-lighten));\n }\n\n .settings-cost-history-title {\n font-size: 11px;\n text-transform: uppercase;\n letter-spacing: 0.08em;\n color: var(--neutral-foreground-hint);\n font-weight: 600;\n margin: calc(var(--design-unit) * 4px) 0 calc(var(--design-unit) * 2px);\n }\n\n /*\n * The heading labels the lifetime card as well as the rows, so the card gives up its own top\n * margin and the gap becomes the heading's alone. Adjacent siblings collapse to the LARGER of\n * the two margins, so leaving both would space the caps 3 units off the block they label while\n * the rows below sit at 2 — reading as though the heading belonged to neither.\n */\n .settings-cost-history-title + .settings-lifetime-usage {\n margin-top: 0;\n }\n\n .settings-cost-history {\n display: flex;\n flex-direction: column;\n gap: calc(var(--design-unit) * 2px);\n padding-bottom: calc(var(--design-unit) * 2px);\n }\n\n .settings-cost-history-icon {\n flex: 0 0 auto;\n width: 36px;\n height: 36px;\n border-radius: calc(var(--control-corner-radius) * 1px);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n font-size: 16px;\n font-weight: 700;\n border: 1px solid var(--neutral-stroke-rest);\n }\n\n .settings-cost-history-row {\n display: flex;\n flex-direction: column;\n background: var(--neutral-layer-1);\n border: 1px solid var(--neutral-stroke-rest);\n border-radius: calc(var(--control-corner-radius) * 1.5px);\n padding: calc(var(--design-unit) * 4px);\n }\n\n .settings-cost-history-row-content {\n display: flex;\n align-items: flex-start;\n gap: calc(var(--design-unit) * 2px);\n }\n\n /*\n * All of these carry a ?hidden binding, and all declare display: flex — which silently beat the\n * UA [hidden] { display: none } rule, because author-origin declarations outrank user-agent\n * origin whatever the specificity. Without this, showTokens: false still rendered the full\n * breakdown in the lifetime block, the live block and every history row, and an empty row list\n * still occupied its padding under the lifetime total. Sibling elements that hide correctly do\n * so only by declaring no display at all. Same treatment as .settings-modal-tab-panel[hidden]\n * near the top of this file.\n */\n .settings-usage-row-tokens[hidden],\n .settings-cost-history[hidden],\n .settings-cost-history-row-content[hidden] {\n display: none !important;\n }\n\n /*\n * The buckets inside a history row drop the panel treatment they carry in the summary\n * blocks — the row is already a bordered card, and a second box inside it reads as a\n * nested panel. The adjacent-sibling rule above supplies the separator instead.\n */\n .settings-cost-history-row-breakdown .settings-token-breakdown {\n flex: 1 1 auto;\n margin-bottom: 0;\n padding: 0;\n background: none;\n border: none;\n }\n\n .settings-cost-history-row-content + .settings-cost-history-row-content {\n border-top: 1px solid var(--neutral-stroke-rest);\n margin-top: calc(var(--design-unit) * 2px);\n padding-top: calc(var(--design-unit) * 2px);\n }\n\n .settings-cost-history-row-body {\n flex: 1 1 auto;\n min-width: 0;\n display: flex;\n gap: calc(var(--design-unit) * 2px);\n justify-content: space-between;\n }\n\n /*\n * Holds the cost and the delete button as one centred pair. The button used to be a sibling\n * of the whole row body, kept in place by a -2px nudge tuned for when the metrics column had\n * two lines (cost plus a merged token total). Dropping that second line left the nudge\n * compensating for nothing. Centring the two against each other needs no magic number and\n * cannot drift again if the metrics content changes.\n *\n * NB this rule previously set align-items with no display:flex, so it had no effect at all.\n */\n .settings-cost-history-row-right {\n display: flex;\n align-items: center;\n gap: calc(var(--design-unit) * 1px);\n flex: 0 0 auto;\n }\n\n .settings-cost-history-row-cost,\n .settings-cost-history-row-title {\n font-size: 14px;\n font-weight: 600;\n color: var(--neutral-foreground-rest);\n min-width: 0;\n }\n\n .settings-cost-history-row-metrics {\n display: flex;\n flex-direction: column;\n flex: 0 0 auto;\n font-size: 13px;\n font-family: ui-monospace, monospace;\n color: var(--neutral-foreground-rest);\n white-space: nowrap;\n }\n\n .settings-cost-history-row-date {\n font-size: 12px;\n color: var(--neutral-foreground-hint);\n }\n\n .settings-cost-history-delete {\n flex: 0 0 auto;\n color: var(--neutral-foreground-hint);\n }\n\n .settings-cost-history-delete:hover {\n color: var(--error-color);\n }\n\n .settings-cost-history ::slotted(*) {\n display: block;\n }\n\n .settings-modal-footer {\n width: 100%;\n }\n\n .settings-done-button {\n margin-left: auto;\n }\n\n .settings-modal-footer-actions {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: calc(var(--design-unit) * 2px);\n width: 100%;\n }\n\n .settings-disclaimer {\n font-size: 12px;\n color: var(--neutral-foreground-hint);\n max-width: 60%;\n line-height: 1.4;\n }\n\n /*\n * Inline spinner shown in the \"Download agent log\" button while the log builds\n * (GENC-1351 §5.8) — the lifetime-stitch path is an async provider round-trip.\n * Sized to the button label and tinted with currentColor so it tracks the\n * button's text colour in every appearance / theme.\n */\n [part='download-button'] .download-spinner {\n display: inline-block;\n width: 12px;\n height: 12px;\n margin-right: calc(var(--design-unit) * 1px);\n vertical-align: -1px;\n border: 2px solid currentColor;\n border-right-color: transparent;\n border-radius: 50%;\n animation: download-spin 0.6s linear infinite;\n }\n\n @keyframes download-spin {\n to {\n transform: rotate(360deg);\n }\n }\n`",
13495
+ "default": "css`\n /*\n * Section headings come from the shared fragment the package also exports, so a host titling\n * its own slotted section applies the same rule rather than a copy of it.\n */\n ${assistantSettingsSectionTitleStyles}\n\n *,\n *::before,\n *::after {\n box-sizing: border-box;\n }\n\n .settings-modal {\n --ai-tier-badge-bg-mix: 14%;\n --ai-tier-badge-text-lighten: 18%;\n }\n\n .settings-modal::part(dialog) {\n max-width: 620px;\n width: calc(100vw - 48px);\n max-height: calc(100vh - 48px);\n padding: 0;\n }\n\n .settings-modal::part(content) {\n display: flex;\n flex-direction: column;\n min-height: 0;\n padding: 0;\n width: 100%;\n }\n\n .settings-modal::part(top) {\n padding: calc(var(--design-unit) * 4px) calc(var(--design-unit) * 5px);\n border-bottom: 1px solid var(--neutral-stroke-rest);\n }\n\n .settings-modal::part(bottom) {\n padding: calc(var(--design-unit) * 4px) calc(var(--design-unit) * 5px);\n border-top: 1px solid var(--neutral-stroke-rest);\n border-bottom-left-radius: var(--card-border-radius, calc(var(--control-corner-radius) * 1px));\n border-bottom-right-radius: var(--card-border-radius, calc(var(--control-corner-radius) * 1px));\n background-color: var(--neutral-layer-2);\n }\n\n .settings-modal-header {\n display: flex;\n align-items: center;\n min-width: 0;\n }\n\n .settings-modal-title {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: calc(var(--design-unit) * 2px);\n color: var(--neutral-foreground-rest);\n }\n\n .settings-modal-content {\n display: flex;\n flex-direction: column;\n min-height: 0;\n flex: 1 1 auto;\n }\n\n .settings-modal-tabs::part(tablist) {\n border-bottom: 0;\n padding: 0 calc(var(--design-unit) * 5px);\n column-gap: calc(var(--design-unit) * 5px);\n }\n\n .settings-modal-tabs::part(activeIndicator) {\n height: 2px;\n }\n\n .settings-modal-tab {\n padding: 0;\n font-weight: 600;\n gap: 6px;\n }\n\n .settings-modal-tab[aria-selected='true'] {\n color: var(--neutral-foreground-rest);\n }\n\n .settings-modal-tabs::part(tabpanel) {\n border-top: 1px solid var(--neutral-stroke-rest);\n }\n\n .settings-modal-tab-panel {\n display: flex;\n flex-direction: column;\n min-height: 0;\n flex: 1 1 auto;\n padding: 0;\n border-radius: 0;\n }\n\n .settings-modal-tab-panel[hidden] {\n display: none !important;\n }\n\n .settings-modal-body {\n overflow-y: auto;\n padding: 0 calc(var(--design-unit) * 5px) calc(var(--design-unit) * 2px);\n max-height: min(60vh, 520px);\n }\n\n .settings-modal-section {\n padding: calc(var(--design-unit) * 5px) 0;\n border-bottom: 1px solid var(--neutral-stroke-rest);\n }\n\n .settings-modal-section:last-child {\n border-bottom: none;\n }\n\n /*\n * Only the spacing. Everything else about this heading comes from the exported fragment\n * above, which the assistant and its hosts share; margin is deliberately not in there,\n * since the gap below a heading depends on the layout around it.\n */\n .ai-settings-section-title {\n margin: 0 0 calc(var(--design-unit) * 3px);\n }\n\n .settings-modal-section-note {\n margin: calc(var(--design-unit) * -2px) 0 calc(var(--design-unit) * 3px);\n font-size: 12px;\n line-height: 1.5;\n color: var(--neutral-foreground-hint);\n }\n\n .settings-modal-section-body {\n display: flex;\n flex-direction: column;\n gap: calc(var(--design-unit) * 4px);\n }\n\n .settings-toggle-row {\n display: flex;\n align-items: flex-start;\n gap: calc(var(--design-unit) * 3px);\n padding: 0 0 calc(var(--design-unit) * 4px) 0;\n border-bottom: 1px solid var(--neutral-stroke-rest);\n }\n\n .settings-toggle-row:last-child {\n border-bottom: none;\n padding-bottom: calc(var(--design-unit) * 1px);\n }\n\n .settings-toggle-row.is-stacked {\n flex-direction: column;\n gap: calc(var(--design-unit) * 2px);\n }\n\n /*\n * For rows whose control is a button rather than a switch. The base row top-aligns, which suits\n * a switch (it lands level with the title), but a button is tall enough that top-aligning leaves\n * it above the title-plus-description block it acts on.\n */\n .settings-toggle-row.is-centered {\n align-items: center;\n }\n\n .settings-animation-list {\n display: flex;\n flex-direction: column;\n width: 100%;\n border: 1px solid var(--neutral-stroke-rest);\n border-radius: calc(var(--control-corner-radius) * 1.2px);\n padding: calc(var(--design-unit) * 2px);\n gap: calc(var(--design-unit) * 2px);\n }\n\n .settings-animation-list .settings-toggle-row {\n border: 0;\n }\n\n .settings-animation-category {\n display: flex;\n flex-direction: column;\n gap: calc(var(--design-unit) * 4px);\n }\n\n .settings-animation-category-label {\n font-weight: 600;\n color: var(--neutral-foreground-hint);\n }\n\n .settings-toggle-row + .settings-animation-category-label {\n border-top: 1px solid var(--neutral-stroke-rest);\n padding-top: calc(var(--design-unit) * 2px);\n }\n\n .settings-animation-option {\n padding: 0;\n margin: 0;\n }\n\n .settings-animation-option:last-child {\n border-bottom: none;\n padding-bottom: calc(var(--design-unit) * 2px);\n }\n\n .settings-toggle-text {\n flex: 1;\n min-width: 0;\n }\n\n .settings-toggle-title {\n font-size: 14px;\n font-weight: 500;\n color: var(--neutral-foreground-rest);\n }\n\n .settings-toggle-desc {\n font-size: 12px;\n color: var(--neutral-foreground-hint);\n line-height: 1.5;\n max-width: 92%;\n }\n\n .settings-toggle-control {\n flex: 0 0 auto;\n min-width: 0;\n }\n\n .settings-toggle-control-wide {\n width: 100%;\n max-width: 280px;\n }\n\n .settings-toggle-row.is-stacked .settings-toggle-desc {\n max-width: none;\n }\n\n .settings-toggle-row.is-stacked .settings-toggle-control-wide {\n width: 100%;\n max-width: none;\n }\n\n /*\n * Sub-heading over the provider toggle group. Unlike the section headings it sits INSIDE\n * .settings-modal-section-body, so the parent's 4-unit flex gap already separates it from the\n * first toggle — and flex does not collapse margins, so the shared rule's 3-unit margin-bottom\n * would add to that gap rather than replace it, leaving the label adrift from the rows it\n * names. Zero the margin and pull back 2 of the 4 gap units, expressed in the same token so it\n * tracks if that gap changes.\n */\n .settings-app-toggles-title {\n margin: 0 0 calc(var(--design-unit) * -2px);\n }\n\n .settings-app-toggle-block {\n display: flex;\n flex-direction: column;\n gap: calc(var(--design-unit) * 1px);\n }\n\n .settings-toggle-hint {\n font-size: 12px;\n color: var(--neutral-foreground-hint);\n line-height: 1.4;\n padding-left: calc(var(--design-unit) * 1px);\n font-style: italic;\n }\n\n /*\n * The budget meter (GENC-1464) is the context indicator's money sibling and\n * shares its row anatomy 1:1, so the budget classes JOIN these rules rather\n * than restating them — one place to restyle the header/label/figures shape,\n * and the two indicators cannot drift apart. Design-system tokens only, and\n * unfallbacked: every token here ships a DS default, so a var(--x, y)\n * fallback would be dead code that hides a broken token name (#2411/#2436\n * review rule, pinned by settings-modal.styles.test.ts).\n */\n .settings-context-header,\n .settings-budget-header {\n display: flex;\n justify-content: space-between;\n gap: calc(var(--design-unit) * 2px);\n margin-bottom: calc(var(--design-unit) * 2px);\n font-size: 12px;\n }\n\n .settings-context-label,\n .settings-budget-label {\n color: var(--neutral-foreground-hint);\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n }\n\n .settings-context-tokens,\n .settings-budget-figures {\n color: var(--neutral-foreground-rest);\n }\n\n /* Freshness footer (GENC-1464): refresh button + label under the vendor\n rows, left-aligned — a footnote to the figures above it. The button's\n inline padding is pinned and cancelled by the container margin so the\n ICON GLYPH (not the button box) sits flush with the budget labels'\n left edge, whatever the density tokens say. */\n .settings-budget-toolbar {\n display: flex;\n justify-content: flex-start;\n align-items: center;\n gap: 4px;\n margin-inline-start: -4px;\n }\n\n .settings-budget-refresh::part(control) {\n padding-inline: 4px;\n }\n\n .settings-budget-updated {\n color: var(--neutral-foreground-hint);\n font-size: 11px;\n }\n\n /*\n * ONE rhythm for every meter row. The outer wrapper holds the context\n * indicator and the budget meter; the inner one holds the budget meter's\n * vendor rows — and both gap by the same 2 units (half the section body's 4)\n * so that visually identical meter rows are evenly spaced whatever mix of\n * them is on screen. Without the wrapper the context row inherits the body's\n * 4-unit gap while the vendor rows keep 2, and three identical-looking rows\n * read as an uneven 4/2/2. The wrapper renders only when at least one meter\n * does — see settingsUsageMetersTemplate for why an always-on one would cost\n * a stray gap.\n */\n .settings-usage-meters,\n .settings-budget-usage {\n display: flex;\n flex-direction: column;\n gap: calc(var(--design-unit) * 2px);\n }\n\n .settings-current-build,\n .settings-lifetime-usage {\n background: var(--neutral-layer-2);\n border: 1px solid var(--neutral-stroke-rest);\n border-radius: calc(var(--control-corner-radius) * 1.5px);\n padding: calc(var(--design-unit) * 4px);\n margin: calc(var(--design-unit) * 3px) 0;\n }\n\n /*\n * Deliberately quieter than the live block: no pulsing badge and no accent, so the eye lands\n * on what is being built now — which is why that block leads the tab and this one follows,\n * under the history heading whose rows it totals.\n */\n .settings-lifetime-usage-top {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: calc(var(--design-unit) * 2px);\n margin-bottom: calc(var(--design-unit) * 3px);\n }\n\n .settings-lifetime-label {\n font-size: 10px;\n line-height: 1;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--neutral-foreground-hint);\n }\n\n .settings-current-build-top {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: calc(var(--design-unit) * 2px);\n margin-bottom: calc(var(--design-unit) * 3px);\n }\n\n /*\n * Optically centring these 10px caps against the 14px project name beside them. Flex offers\n * only two alignments and neither lands it, because a box centre and a text baseline are\n * different lines:\n * - align-items: center sits the badge baseline about 1.2px high\n * - align-items: baseline matches baselines, but the caps then read as bottom-aligned\n * against the name's ascenders, so the badge looks low\n * The eye wants the midpoint, so: centre the boxes, then translate down by the ~1px of\n * overshoot. This is a nudge, but it corrects a fixed relationship between two font sizes\n * rather than some neighbouring element's layout, so unlike a margin tuned to a sibling it\n * cannot rot when that sibling changes. In em, so it tracks the badge text.\n *\n * display: block, not inline-flex: a flex container has no text baseline of its own and\n * synthesizes one from its first child, which here is the dot, an empty span. As a block box\n * the badge takes the baseline of its first line, i.e. the text.\n */\n .settings-live-badge {\n display: block;\n font-size: 10px;\n line-height: 1;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--accent-fill-rest);\n white-space: nowrap;\n transform: translateY(0.1em);\n }\n\n .settings-live-dot {\n display: inline-block;\n width: 7px;\n height: 7px;\n\n /* Replaces the flex gap the badge no longer has. */\n margin-right: calc(var(--design-unit) * 1px);\n\n /* Centres the dot on the text beside it without disturbing that text's baseline. */\n vertical-align: middle;\n border-radius: 50%;\n background: var(--accent-fill-rest);\n animation: settings-live-pulse 1.6s ease-out infinite;\n }\n\n @keyframes settings-live-pulse {\n 0% {\n box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent-fill-rest) 55%, transparent);\n }\n\n 70% {\n box-shadow: 0 0 0 7px transparent;\n }\n\n 100% {\n box-shadow: 0 0 0 0 transparent;\n }\n }\n\n .settings-current-build-name {\n font-size: 14px;\n line-height: 1;\n font-weight: 600;\n }\n\n /*\n * Cost and the token buckets side by side: one number in its own box, the four buckets\n * sharing the box next to it. Stretch, so the two are the same height however tall the 22px\n * cost value makes the left one.\n */\n .settings-usage-row {\n display: flex;\n flex-wrap: wrap;\n align-items: stretch;\n gap: calc(var(--design-unit) * 3px);\n margin-bottom: calc(var(--design-unit) * 3px);\n }\n\n .settings-usage-row-tokens {\n display: flex;\n flex: 1 1 auto;\n min-width: 0;\n }\n\n .settings-build-stat {\n min-width: 0;\n background: var(--neutral-layer-1);\n border: 1px solid var(--neutral-stroke-rest);\n border-radius: calc(var(--control-corner-radius) * 1px);\n padding: calc(var(--design-unit) * 3px);\n }\n\n .settings-build-stat-label {\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--neutral-foreground-hint);\n }\n\n .settings-build-stat-value {\n font-size: 22px;\n font-weight: 700;\n margin-top: calc(var(--design-unit) * 1px);\n color: var(--neutral-foreground-rest);\n }\n\n .settings-build-stat-value .prefix,\n .settings-build-stat-value .suffix {\n color: var(--accent-fill-rest);\n }\n\n /*\n * Per-bucket token split, beneath the headline cost. Small paired label/value cells\n * rather than four more stat cards: they are the detail behind the cost above, so they\n * have to read as subordinate to it rather than compete with it. The four buckets ARE\n * the token figure now — there is no merged total anywhere for them to break down.\n */\n .settings-token-breakdown {\n display: flex;\n flex-direction: column;\n\n /*\n * Tight against the buckets below. One design unit rather than two, because each bucket\n * separates its own label from its value by only 2px — at two units the title sat four\n * times further from the bucket labels than they sit from their own numbers, which read\n * as a gap between unrelated blocks instead of a heading over its content.\n */\n gap: calc(var(--design-unit) * 1px);\n margin-bottom: calc(var(--design-unit) * 3px);\n padding: calc(var(--design-unit) * 2px) calc(var(--design-unit) * 3px);\n background: var(--neutral-layer-1);\n border: 1px solid var(--neutral-stroke-rest);\n border-radius: calc(var(--control-corner-radius) * 1px);\n }\n\n /*\n * Titles the box, because nothing else in it named the unit. Same styling and position as\n * the cost box's label, so two boxes sitting side by side are titled the same way; the\n * hierarchy against the bucket labels comes from position, not a second type size.\n */\n .settings-token-breakdown-label {\n font-size: 10px;\n line-height: 1;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--neutral-foreground-hint);\n }\n\n .settings-token-buckets {\n display: flex;\n flex-wrap: wrap;\n gap: calc(var(--design-unit) * 4px);\n }\n\n .settings-token-bucket {\n display: flex;\n\n /*\n * min-content (not 0) so a bucket cannot be shrunk narrower than its own unbreakable label.\n * With the label set to nowrap, a zero minimum would overflow it into the next column instead\n * of wrapping — so the container's flex-wrap takes over and moves a bucket to a second row,\n * which is the degradation we want when the modal is dragged narrow.\n */\n min-width: min-content;\n flex-direction: column;\n gap: 2px;\n }\n\n .settings-token-bucket-label {\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--neutral-foreground-hint);\n\n /*\n * One line, always. The rate marker is a separate inline box after collapsible whitespace, so\n * a wrappable label gives it a break opportunity of its own — in a narrow column it orphaned\n * onto line 2, which also pushed that bucket's value a line below the other three and broke\n * the row of figures. nowrap removes every break opportunity in the label, the space before\n * the marker included, so no glue character is needed.\n */\n white-space: nowrap;\n }\n\n .settings-token-bucket-value {\n font-size: 13px;\n font-weight: 600;\n color: var(--neutral-foreground-rest);\n }\n\n /*\n * The price-direction marker on a cache bucket's label — down for reads (a fraction of the\n * uncached input rate), up for writes (a premium over it). Three tiers, so a bucket with no\n * marker is the reference rate rather than an unlabelled fourth case.\n *\n * Carried by the label rather than the value, which is what this used to do: cache reads are\n * usually the largest bucket by a wide margin in an agentic session, so the value was muted to\n * stop the biggest number reading as the dominant cost driver. That priced the treatment to the\n * wrong thing — a dimmed 0 (every Gemini cache write) looked disabled next to a normal 0, and a\n * rate is a property of the bucket, not of this turn's figure.\n *\n * Sized down and nudged up rather than tinted: the label is already the hint colour, so a\n * dimmer marker would vanish and a brighter one would out-shout the word it qualifies.\n */\n .settings-token-bucket-rate {\n font-size: 8px;\n line-height: 1;\n vertical-align: 0.15em;\n letter-spacing: 0;\n }\n\n /*\n * Usage-row overrides. Placed after the base rules they refine rather than up beside\n * .settings-usage-row itself, because stylelint's no-descending-specificity rejects a\n * compound selector appearing before the plain one it overrides.\n */\n\n /* Sized by its content; the buckets take the rest, since four cells need the width. */\n .settings-usage-row > .settings-build-stat {\n flex: 0 1 auto;\n }\n\n .settings-usage-row .settings-token-breakdown {\n flex: 1 1 auto;\n\n /* The row owns the spacing now; this centres the column against the taller cost box. */\n justify-content: center;\n margin-bottom: 0;\n }\n\n /*\n * Basis auto, not 0: a zero basis splits the row into four equal columns, so CACHE WRITE is\n * squeezed exactly as hard as INPUT despite being twice the label. Sizing from content gives the\n * long labels the room their text needs and lets the short ones concede it, which is what makes\n * white-space: nowrap above safe — every column starts at least as wide as its own content,\n * then shares the slack. Still grows and shrinks, so the four stay flush edge to edge.\n */\n .settings-usage-row .settings-token-bucket {\n flex: 1 1 auto;\n }\n\n .settings-model-tags {\n display: flex;\n flex-wrap: wrap;\n gap: calc(var(--design-unit) * 2px);\n }\n\n .settings-model-tag {\n font-size: 11px;\n font-weight: 600;\n padding: 3px 9px;\n border-radius: 20px;\n font-family: ui-monospace, monospace;\n border: 1px solid var(--neutral-stroke-rest);\n }\n\n .settings-model-tag,\n .settings-cost-history-icon {\n --model-tag-color: var(--neutral-foreground-rest);\n\n background: color-mix(\n in srgb,\n var(--model-tag-color) var(--ai-tier-badge-bg-mix),\n var(--neutral-layer-1)\n );\n border-color: color-mix(in srgb, var(--model-tag-color) 20%, var(--neutral-layer-1));\n color: color-mix(in srgb, var(--model-tag-color), white var(--ai-tier-badge-text-lighten));\n }\n\n .settings-cost-history-title {\n font-size: 11px;\n text-transform: uppercase;\n letter-spacing: 0.08em;\n color: var(--neutral-foreground-hint);\n font-weight: 600;\n margin: calc(var(--design-unit) * 4px) 0 calc(var(--design-unit) * 2px);\n }\n\n /*\n * The heading labels the lifetime card as well as the rows, so the card gives up its own top\n * margin and the gap becomes the heading's alone. Adjacent siblings collapse to the LARGER of\n * the two margins, so leaving both would space the caps 3 units off the block they label while\n * the rows below sit at 2 — reading as though the heading belonged to neither.\n */\n .settings-cost-history-title + .settings-lifetime-usage {\n margin-top: 0;\n }\n\n .settings-cost-history {\n display: flex;\n flex-direction: column;\n gap: calc(var(--design-unit) * 2px);\n padding-bottom: calc(var(--design-unit) * 2px);\n }\n\n .settings-cost-history-icon {\n flex: 0 0 auto;\n width: 36px;\n height: 36px;\n border-radius: calc(var(--control-corner-radius) * 1px);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n font-size: 16px;\n font-weight: 700;\n border: 1px solid var(--neutral-stroke-rest);\n }\n\n .settings-cost-history-row {\n display: flex;\n flex-direction: column;\n background: var(--neutral-layer-1);\n border: 1px solid var(--neutral-stroke-rest);\n border-radius: calc(var(--control-corner-radius) * 1.5px);\n padding: calc(var(--design-unit) * 4px);\n }\n\n .settings-cost-history-row-content {\n display: flex;\n align-items: flex-start;\n gap: calc(var(--design-unit) * 2px);\n }\n\n /*\n * All of these carry a ?hidden binding, and all declare display: flex — which silently beat the\n * UA [hidden] { display: none } rule, because author-origin declarations outrank user-agent\n * origin whatever the specificity. Without this, showTokens: false still rendered the full\n * breakdown in the lifetime block, the live block and every history row, and an empty row list\n * still occupied its padding under the lifetime total. Sibling elements that hide correctly do\n * so only by declaring no display at all. Same treatment as .settings-modal-tab-panel[hidden]\n * near the top of this file.\n */\n .settings-usage-row-tokens[hidden],\n .settings-cost-history[hidden],\n .settings-cost-history-row-content[hidden] {\n display: none !important;\n }\n\n /*\n * The buckets inside a history row drop the panel treatment they carry in the summary\n * blocks — the row is already a bordered card, and a second box inside it reads as a\n * nested panel. The adjacent-sibling rule above supplies the separator instead.\n */\n .settings-cost-history-row-breakdown .settings-token-breakdown {\n flex: 1 1 auto;\n margin-bottom: 0;\n padding: 0;\n background: none;\n border: none;\n }\n\n .settings-cost-history-row-content + .settings-cost-history-row-content {\n border-top: 1px solid var(--neutral-stroke-rest);\n margin-top: calc(var(--design-unit) * 2px);\n padding-top: calc(var(--design-unit) * 2px);\n }\n\n .settings-cost-history-row-body {\n flex: 1 1 auto;\n min-width: 0;\n display: flex;\n gap: calc(var(--design-unit) * 2px);\n justify-content: space-between;\n }\n\n /*\n * Holds the cost and the delete button as one centred pair. The button used to be a sibling\n * of the whole row body, kept in place by a -2px nudge tuned for when the metrics column had\n * two lines (cost plus a merged token total). Dropping that second line left the nudge\n * compensating for nothing. Centring the two against each other needs no magic number and\n * cannot drift again if the metrics content changes.\n *\n * NB this rule previously set align-items with no display:flex, so it had no effect at all.\n */\n .settings-cost-history-row-right {\n display: flex;\n align-items: center;\n gap: calc(var(--design-unit) * 1px);\n flex: 0 0 auto;\n }\n\n .settings-cost-history-row-cost,\n .settings-cost-history-row-title {\n font-size: 14px;\n font-weight: 600;\n color: var(--neutral-foreground-rest);\n min-width: 0;\n }\n\n .settings-cost-history-row-metrics {\n display: flex;\n flex-direction: column;\n flex: 0 0 auto;\n font-size: 13px;\n font-family: ui-monospace, monospace;\n color: var(--neutral-foreground-rest);\n white-space: nowrap;\n }\n\n .settings-cost-history-row-date {\n font-size: 12px;\n color: var(--neutral-foreground-hint);\n }\n\n .settings-cost-history-delete {\n flex: 0 0 auto;\n color: var(--neutral-foreground-hint);\n }\n\n .settings-cost-history-delete:hover {\n color: var(--error-color);\n }\n\n .settings-cost-history ::slotted(*) {\n display: block;\n }\n\n .settings-modal-footer {\n width: 100%;\n }\n\n .settings-done-button {\n margin-left: auto;\n }\n\n .settings-modal-footer-actions {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: calc(var(--design-unit) * 2px);\n width: 100%;\n }\n\n .settings-disclaimer {\n font-size: 12px;\n color: var(--neutral-foreground-hint);\n max-width: 60%;\n line-height: 1.4;\n }\n\n /* The agent-log row's two actions (Download / Send) side by side. */\n .agent-log-actions {\n display: flex;\n align-items: center;\n gap: calc(var(--design-unit) * 2px);\n }\n\n /*\n * Row + compose box. The row is normally the section's last child (no divider); inside\n * the wrapper it is only the last child while the box is closed, so drop the divider\n * explicitly and let the box supply its own spacing beneath the row.\n */\n .agent-log-block {\n display: flex;\n flex-direction: column;\n }\n\n .agent-log-block .settings-toggle-row {\n border-bottom: none;\n padding-bottom: calc(var(--design-unit) * 1px);\n }\n\n .agent-log-compose {\n display: flex;\n flex-direction: column;\n gap: calc(var(--design-unit) * 2px);\n margin-top: calc(var(--design-unit) * 2px);\n }\n\n .agent-log-note {\n width: 100%;\n }\n\n .agent-log-note::part(control) {\n width: 100%;\n box-sizing: border-box;\n font-size: 13px;\n line-height: 1.5;\n }\n\n .agent-log-compose-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: calc(var(--design-unit) * 3px);\n }\n\n /* Counter / validation / failure line. Hint-coloured until it carries an error. */\n .agent-log-compose-hint {\n font-size: 12px;\n color: var(--neutral-foreground-hint);\n min-width: 0;\n }\n\n /*\n * Failure state without leaning on --error-color: rapid's fixed brand red is 3.02:1 on a\n * light surface, under AA for 12px text, and the failure line is the one that most needs\n * reading. The contrast-adaptive foreground plus weight carries it; the text itself also\n * changes, so colour was never the only channel.\n */\n .agent-log-compose-hint.is-error {\n color: var(--neutral-foreground-rest);\n font-weight: 600;\n }\n\n /* Screen-reader-only live region for submission outcomes (same recipe as main.styles). */\n .visually-hidden {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n border: 0;\n }\n\n /*\n * Inline spinner shown in the agent-log buttons (Download / Send) while the log\n * builds (GENC-1351 §5.8) — the lifetime-stitch path is an async provider\n * round-trip. Sized to the button label and tinted with currentColor so it tracks\n * the button's text colour in every appearance / theme.\n */\n [part='download-button'] .download-spinner,\n [part='submit-log-button'] .download-spinner,\n [part='agent-log-send-button'] .download-spinner {\n display: inline-block;\n width: 12px;\n height: 12px;\n margin-right: calc(var(--design-unit) * 1px);\n vertical-align: -1px;\n border: 2px solid currentColor;\n border-right-color: transparent;\n border-radius: 50%;\n animation: download-spin 0.6s linear infinite;\n }\n\n @keyframes download-spin {\n to {\n transform: rotate(360deg);\n }\n }\n`",
13085
13496
  "description": "Styles for the assistant settings modal (tabs, sections, toggles, cost summary)."
13086
13497
  }
13087
13498
  ],
@@ -13124,6 +13535,29 @@
13124
13535
  ],
13125
13536
  "description": "Three-way picker for TimestampDisplay (GENC-1257).\n\nThe design system's segmented control rather than the `switch` every other row uses,\nbecause the setting genuinely has three states — and rather than hand-rolled buttons\ncarrying `role=\"radio\"`, because ARIA roles supply semantics but never behaviour:\npromising a radio group means owning roving `tabindex` and arrow-key navigation.\n\n`SegmentedControl extends FASTRadioGroup` (and `SegmentedItem extends FASTRadio`), so\nthis IS the DS radio group — it inherits the whole keyboard pattern — just skinned as\nsegments rather than dots, which is the right affordance for three short mode labels.\n\nThe usual reason to avoid a DS control here does not apply. `RadioGroup.valueChanged`\nemits `change` whenever `value` is written — including the write this template's own\nbinding performs on render, exactly the phantom-change footgun the DS switch has\n(GENC-1351 #1). It is harmless because the `timestampDisplay` setter guards on\n`preferenceUnchanged`, as every preference setter does, so a render-time echo returns early\nand never reaches the store or marks preferences user-changed."
13126
13537
  },
13538
+ {
13539
+ "kind": "function",
13540
+ "name": "agentLogSectionTemplate",
13541
+ "return": {
13542
+ "type": {
13543
+ "text": "ViewTemplate<FoundationAiAssistant>"
13544
+ }
13545
+ },
13546
+ "parameters": [
13547
+ {
13548
+ "name": "buttonTag",
13549
+ "type": {
13550
+ "text": "string"
13551
+ }
13552
+ },
13553
+ {
13554
+ "name": "textareaTag",
13555
+ "type": {
13556
+ "text": "string"
13557
+ }
13558
+ }
13559
+ ]
13560
+ },
13127
13561
  {
13128
13562
  "kind": "function",
13129
13563
  "name": "SettingsModalTemplate",
@@ -13152,6 +13586,14 @@
13152
13586
  "module": "src/components/settings-modal/settings-modal.template.ts"
13153
13587
  }
13154
13588
  },
13589
+ {
13590
+ "kind": "js",
13591
+ "name": "agentLogSectionTemplate",
13592
+ "declaration": {
13593
+ "name": "agentLogSectionTemplate",
13594
+ "module": "src/components/settings-modal/settings-modal.template.ts"
13595
+ }
13596
+ },
13155
13597
  {
13156
13598
  "kind": "js",
13157
13599
  "name": "SettingsModalTemplate",
@@ -1 +1 @@
1
- {"version":3,"file":"settings-modal.d.ts","sourceRoot":"","sources":["../../../../src/components/settings-modal/settings-modal.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"settings-modal.d.ts","sourceRoot":"","sources":["../../../../src/components/settings-modal/settings-modal.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"settings-modal.styles.d.ts","sourceRoot":"","sources":["../../../../src/components/settings-modal/settings-modal.styles.ts"],"names":[],"mappings":"AAGA,uFAAuF;AACvF,eAAO,MAAM,mBAAmB,iDAg1B/B,CAAC"}
1
+ {"version":3,"file":"settings-modal.styles.d.ts","sourceRoot":"","sources":["../../../../src/components/settings-modal/settings-modal.styles.ts"],"names":[],"mappings":"AAGA,uFAAuF;AACvF,eAAO,MAAM,mBAAmB,iDAg6B/B,CAAC"}