@quilltap/theme-storybook 1.0.65 → 1.0.67

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  All notable changes to `@quilltap/theme-storybook` will be documented in this file.
4
4
 
5
+ ## [1.0.67] - 2026-08-30
6
+
7
+ ### Added
8
+ - `.qt-range` and its two tokens (`--qt-range-accent`, `--qt-range-focus-ring`), mirroring the app's new slider class, plus a "Range Sliders" section in the `Inputs` story so a theme can be previewed against an enabled and a disabled slider.
9
+
10
+ ### Notes
11
+ - Sliders stay natively rendered. `accent-color` is what paints the filled portion of the track *and* the thumb, so it is the whole default theming story; the class sets no disabled opacity, because browsers already drop the accent on a disabled range and app call sites nest sliders inside dimmed wrappers. A theme wanting a bespoke track can override `.qt-range` with `appearance: none`, at the cost of the filled bar in Chrome and Safari.
12
+
5
13
  ## [1.0.63] - 2026-08-25
6
14
 
7
15
  ### Added
@@ -848,6 +848,28 @@ var Inputs = () => {
848
848
  ] })
849
849
  ] })
850
850
  ] }),
851
+ /* @__PURE__ */ jsxs7("section", { style: { marginBottom: "2rem" }, children: [
852
+ /* @__PURE__ */ jsx7("h3", { style: { fontSize: "1.125rem", fontWeight: 700, marginBottom: "1rem", borderBottom: "1px solid var(--color-border)", paddingBottom: "0.5rem" }, children: "Range Sliders" }),
853
+ /* @__PURE__ */ jsxs7("div", { style: { display: "flex", flexDirection: "column", gap: "1rem", maxWidth: "24rem" }, children: [
854
+ /* @__PURE__ */ jsxs7("div", { children: [
855
+ /* @__PURE__ */ jsx7("label", { className: "qt-label", htmlFor: "range1", children: "Temperature" }),
856
+ /* @__PURE__ */ jsx7("input", { type: "range", id: "range1", className: "qt-range", style: { width: "100%" }, min: 0, max: 100, defaultValue: 65 })
857
+ ] }),
858
+ /* @__PURE__ */ jsxs7("div", { children: [
859
+ /* @__PURE__ */ jsx7("label", { className: "qt-label", htmlFor: "range2", style: { color: "var(--color-muted-foreground)" }, children: "Disabled slider" }),
860
+ /* @__PURE__ */ jsx7("input", { type: "range", id: "range2", className: "qt-range", style: { width: "100%" }, min: 0, max: 100, defaultValue: 35, disabled: true })
861
+ ] })
862
+ ] }),
863
+ /* @__PURE__ */ jsxs7("p", { style: { fontSize: "0.75rem", color: "var(--color-muted-foreground)", marginTop: "0.75rem", maxWidth: "32rem" }, children: [
864
+ "Sliders render natively; ",
865
+ /* @__PURE__ */ jsx7("code", { children: "--qt-range-accent" }),
866
+ " colours both the filled portion of the track and the thumb. Overriding ",
867
+ /* @__PURE__ */ jsx7("code", { children: ".qt-range" }),
868
+ " with",
869
+ /* @__PURE__ */ jsx7("code", { children: " appearance: none" }),
870
+ " gives a theme full control of the track, but drops the filled bar in Chrome and Safari."
871
+ ] })
872
+ ] }),
851
873
  /* @__PURE__ */ jsxs7("section", { style: { marginBottom: "2rem" }, children: [
852
874
  /* @__PURE__ */ jsx7("h3", { style: { fontSize: "1.125rem", fontWeight: 700, marginBottom: "1rem", borderBottom: "1px solid var(--color-border)", paddingBottom: "0.5rem" }, children: "Links" }),
853
875
  /* @__PURE__ */ jsxs7("div", { style: { display: "flex", flexDirection: "column", gap: "0.75rem" }, children: [
@@ -1379,10 +1401,33 @@ var Dialogs = () => {
1379
1401
  ] }),
1380
1402
  /* @__PURE__ */ jsxs11("section", { children: [
1381
1403
  /* @__PURE__ */ jsx11("h3", { style: { fontSize: "1.125rem", fontWeight: 700, marginBottom: "1rem", borderBottom: "1px solid var(--color-border)", paddingBottom: "0.5rem" }, children: "Tooltip" }),
1382
- /* @__PURE__ */ jsx11("div", { style: { display: "flex", alignItems: "center", gap: "2rem" }, children: /* @__PURE__ */ jsxs11("div", { style: { position: "relative", display: "inline-block", marginTop: "2rem" }, children: [
1383
- /* @__PURE__ */ jsx11("button", { className: "qt-button qt-button-secondary", children: "Hover me" }),
1384
- /* @__PURE__ */ jsx11("div", { className: "qt-tooltip", style: { position: "absolute", left: "50%", transform: "translateX(-50%)", bottom: "100%", marginBottom: "0.5rem", display: "block" }, children: "Helpful tooltip text" })
1385
- ] }) })
1404
+ /* @__PURE__ */ jsxs11("div", { style: { display: "flex", alignItems: "flex-end", gap: "4rem", flexWrap: "wrap" }, children: [
1405
+ /* @__PURE__ */ jsxs11("div", { style: { position: "relative", display: "inline-block", marginTop: "2rem" }, children: [
1406
+ /* @__PURE__ */ jsx11("button", { className: "qt-button qt-button-secondary", children: "Hover me" }),
1407
+ /* @__PURE__ */ jsx11("div", { className: "qt-tooltip", style: { position: "absolute", left: "50%", transform: "translateX(-50%)", bottom: "100%", marginBottom: "0.5rem", display: "block" }, children: "Helpful tooltip text" })
1408
+ ] }),
1409
+ /* @__PURE__ */ jsxs11("div", { style: { position: "relative", display: "inline-block", marginTop: "14rem" }, children: [
1410
+ /* @__PURE__ */ jsx11("button", { className: "qt-button qt-button-secondary", children: "Pinned, with detail" }),
1411
+ /* @__PURE__ */ jsx11(
1412
+ "div",
1413
+ {
1414
+ className: "qt-tooltip",
1415
+ "data-interactive": "true",
1416
+ "data-pinned": "true",
1417
+ style: { position: "absolute", left: "50%", transform: "translateX(-50%)", bottom: "100%", marginBottom: "0.5rem", display: "block", width: "20rem" },
1418
+ children: /* @__PURE__ */ jsxs11("div", { className: "qt-tooltip-body", children: [
1419
+ /* @__PURE__ */ jsx11("p", { className: "qt-tooltip-title", children: "Amended" }),
1420
+ /* @__PURE__ */ jsx11("p", { children: "On reflection the author corrected this reply to match the record." }),
1421
+ /* @__PURE__ */ jsxs11("div", { className: "qt-tooltip-section", children: [
1422
+ /* @__PURE__ */ jsx11("p", { className: "qt-tooltip-section-label", children: "What looked off" }),
1423
+ /* @__PURE__ */ jsx11("p", { className: "qt-tooltip-quote", children: "The ledger excerpt returned by the document read shows a metric column." })
1424
+ ] }),
1425
+ /* @__PURE__ */ jsx11("p", { className: "qt-tooltip-hint", children: "Click the badge to pin this note; Esc dismisses it." })
1426
+ ] })
1427
+ }
1428
+ )
1429
+ ] })
1430
+ ] })
1386
1431
  ] })
1387
1432
  ] });
1388
1433
  };
@@ -2018,6 +2063,28 @@ var Chat = () => {
2018
2063
  /* @__PURE__ */ jsx14("div", { className: "qt-emoji-picker-message", children: "Couldn't load emoji" })
2019
2064
  ] }) })
2020
2065
  ] }),
2066
+ /* @__PURE__ */ jsxs14("section", { style: { marginBottom: "2rem" }, children: [
2067
+ /* @__PURE__ */ jsx14("h3", { style: { fontSize: "1.125rem", fontWeight: 700, marginBottom: "1rem", borderBottom: "1px solid var(--color-border)", paddingBottom: "0.5rem" }, children: "Answer-Confirmation Badges" }),
2068
+ /* @__PURE__ */ jsx14("p", { style: { fontSize: "0.875rem", color: "var(--color-muted-foreground)", marginBottom: "1rem" }, children: "The fact-checker's verdict on a message, shown among the message action icons. Quiet by design; the discrepancy notes live in a tooltip. Hover one to see its hover state." }),
2069
+ /* @__PURE__ */ jsxs14("div", { style: { display: "flex", alignItems: "center", gap: "0.75rem", flexWrap: "wrap" }, children: [
2070
+ /* @__PURE__ */ jsxs14("button", { className: "qt-confirmation-badge", "data-confirmation-state": "vouched", children: [
2071
+ /* @__PURE__ */ jsx14("span", { className: "qt-confirmation-badge-glyph", children: "\u2713" }),
2072
+ /* @__PURE__ */ jsx14("span", { className: "qt-confirmation-badge-label", children: "Vouched" })
2073
+ ] }),
2074
+ /* @__PURE__ */ jsxs14("button", { className: "qt-confirmation-badge", "data-confirmation-state": "amended", children: [
2075
+ /* @__PURE__ */ jsx14("span", { className: "qt-confirmation-badge-glyph", children: "\u270E" }),
2076
+ /* @__PURE__ */ jsx14("span", { className: "qt-confirmation-badge-label", children: "Amended" })
2077
+ ] }),
2078
+ /* @__PURE__ */ jsxs14("button", { className: "qt-confirmation-badge", "data-confirmation-state": "stood-by", children: [
2079
+ /* @__PURE__ */ jsx14("span", { className: "qt-confirmation-badge-glyph", children: "!" }),
2080
+ /* @__PURE__ */ jsx14("span", { className: "qt-confirmation-badge-label", children: "Stood by" })
2081
+ ] }),
2082
+ /* @__PURE__ */ jsxs14("button", { className: "qt-confirmation-badge", "data-confirmation-state": "unvetted", children: [
2083
+ /* @__PURE__ */ jsx14("span", { className: "qt-confirmation-badge-glyph", children: "\u2014" }),
2084
+ /* @__PURE__ */ jsx14("span", { className: "qt-confirmation-badge-label", children: "Unvetted" })
2085
+ ] })
2086
+ ] })
2087
+ ] }),
2021
2088
  /* @__PURE__ */ jsxs14("section", { children: [
2022
2089
  /* @__PURE__ */ jsx14("h3", { style: { fontSize: "1.125rem", fontWeight: 700, marginBottom: "1rem", borderBottom: "1px solid var(--color-border)", paddingBottom: "0.5rem" }, children: "Full Chat Layout" }),
2023
2090
  /* @__PURE__ */ jsxs14("div", { className: "qt-chat-layout", style: { height: "24rem", border: "1px solid var(--color-border)", borderRadius: "var(--radius-lg)", display: "flex", flexDirection: "column" }, children: [
package/dist/index.css CHANGED
@@ -230,6 +230,8 @@ body {
230
230
  --qt-radio-border: var(--color-border);
231
231
  --qt-radio-accent: var(--color-primary);
232
232
  --qt-radio-focus-ring: var(--color-ring);
233
+ --qt-range-accent: var(--color-primary);
234
+ --qt-range-focus-ring: var(--color-ring);
233
235
  --qt-navbar-height: 3.5rem;
234
236
  --qt-navbar-bg: var(--color-background);
235
237
  --qt-navbar-border: var(--color-border);
@@ -852,6 +854,17 @@ body {
852
854
  outline: none;
853
855
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--qt-radio-focus-ring) 35%, transparent);
854
856
  }
857
+ .qt-range {
858
+ cursor: pointer;
859
+ accent-color: var(--qt-range-accent);
860
+ }
861
+ .qt-range:focus-visible {
862
+ outline: none;
863
+ box-shadow: 0 0 0 2px color-mix(in srgb, var(--qt-range-focus-ring) 35%, transparent);
864
+ }
865
+ .qt-range:disabled {
866
+ cursor: not-allowed;
867
+ }
855
868
  .qt-badge {
856
869
  display: inline-flex;
857
870
  align-items: center;
@@ -1211,6 +1224,60 @@ body {
1211
1224
  .qt-pascal-result--info {
1212
1225
  border-left-color: var(--qt-alert-info-border);
1213
1226
  }
1227
+ .qt-confirmation-badge {
1228
+ display: inline-flex;
1229
+ align-items: center;
1230
+ gap: 0.2rem;
1231
+ padding: 0.05rem 0.4rem;
1232
+ border-radius: 0.375rem;
1233
+ border: 1px solid color-mix(in srgb, currentColor 25%, transparent);
1234
+ background: transparent;
1235
+ font: inherit;
1236
+ line-height: 1.4;
1237
+ cursor: help;
1238
+ color: var(--qt-text-secondary-fg, var(--qt-text-secondary));
1239
+ opacity: 0.8;
1240
+ -webkit-user-select: none;
1241
+ -moz-user-select: none;
1242
+ user-select: none;
1243
+ white-space: nowrap;
1244
+ transition:
1245
+ color 150ms,
1246
+ background-color 150ms,
1247
+ border-color 150ms,
1248
+ opacity 150ms;
1249
+ }
1250
+ .qt-confirmation-badge:hover,
1251
+ .qt-confirmation-badge:focus-visible {
1252
+ opacity: 1;
1253
+ border-color: color-mix(in srgb, currentColor 45%, transparent);
1254
+ background: color-mix(in srgb, var(--color-muted) 50%, transparent);
1255
+ }
1256
+ .qt-confirmation-badge[data-confirmation-state=vouched]:hover,
1257
+ .qt-confirmation-badge[data-confirmation-state=vouched]:focus-visible,
1258
+ .qt-confirmation-badge[data-confirmation-state=unvetted]:hover,
1259
+ .qt-confirmation-badge[data-confirmation-state=unvetted]:focus-visible {
1260
+ color: var(--color-foreground);
1261
+ }
1262
+ .qt-confirmation-badge:focus-visible {
1263
+ outline: 2px solid color-mix(in srgb, var(--color-foreground) 45%, transparent);
1264
+ outline-offset: 2px;
1265
+ }
1266
+ .qt-chat-message-user .qt-confirmation-badge:hover,
1267
+ .qt-chat-message-user .qt-confirmation-badge:focus-visible {
1268
+ color: var(--qt-chat-user-fg);
1269
+ background: color-mix(in srgb, var(--qt-chat-user-fg) 15%, transparent);
1270
+ }
1271
+ .qt-confirmation-badge-glyph {
1272
+ font-weight: 600;
1273
+ }
1274
+ .qt-confirmation-badge[data-confirmation-state=stood-by] {
1275
+ color: var(--qt-warning-box-fg, var(--qt-text-secondary-fg));
1276
+ opacity: 1;
1277
+ }
1278
+ .qt-confirmation-badge[data-confirmation-state=amended] {
1279
+ opacity: 1;
1280
+ }
1214
1281
  .qt-chat-system-bar {
1215
1282
  display: flex;
1216
1283
  align-items: center;
@@ -1752,6 +1819,59 @@ body {
1752
1819
  background: var(--color-muted);
1753
1820
  outline: none;
1754
1821
  }
1822
+ .qt-tooltip {
1823
+ position: fixed;
1824
+ z-index: 70;
1825
+ padding: 0.5rem 0.75rem;
1826
+ font-size: 0.75rem;
1827
+ line-height: 1.45;
1828
+ max-width: min(24rem, calc(100vw - 1rem));
1829
+ border-radius: var(--qt-popover-radius);
1830
+ background: var(--color-foreground);
1831
+ color: var(--color-background);
1832
+ border: 1px solid color-mix(in srgb, var(--color-background) 20%, transparent);
1833
+ box-shadow: var(--qt-popover-shadow);
1834
+ text-align: left;
1835
+ white-space: pre-line;
1836
+ pointer-events: none;
1837
+ }
1838
+ .qt-tooltip[data-interactive=true] {
1839
+ pointer-events: auto;
1840
+ }
1841
+ .qt-tooltip[data-pinned=true] {
1842
+ border-color: color-mix(in srgb, var(--color-background) 45%, transparent);
1843
+ }
1844
+ .qt-tooltip-anchor {
1845
+ display: inline-flex;
1846
+ align-items: center;
1847
+ }
1848
+ .qt-tooltip-body {
1849
+ max-height: 40vh;
1850
+ overflow-y: auto;
1851
+ overscroll-behavior: contain;
1852
+ }
1853
+ .qt-tooltip-title {
1854
+ font-weight: 600;
1855
+ margin-bottom: 0.15rem;
1856
+ }
1857
+ .qt-tooltip-section {
1858
+ margin-top: 0.5rem;
1859
+ }
1860
+ .qt-tooltip-section-label {
1861
+ text-transform: uppercase;
1862
+ font-size: 0.625rem;
1863
+ letter-spacing: 0.05em;
1864
+ opacity: 0.7;
1865
+ }
1866
+ .qt-tooltip-quote {
1867
+ white-space: pre-wrap;
1868
+ opacity: 0.92;
1869
+ }
1870
+ .qt-tooltip-hint {
1871
+ margin-top: 0.5rem;
1872
+ font-size: 0.625rem;
1873
+ opacity: 0.65;
1874
+ }
1755
1875
  .qt-typeahead-menu {
1756
1876
  position: absolute;
1757
1877
  z-index: 50;
package/dist/index.js CHANGED
@@ -958,6 +958,28 @@ var Inputs = () => {
958
958
  ] })
959
959
  ] })
960
960
  ] }),
961
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("section", { style: { marginBottom: "2rem" }, children: [
962
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h3", { style: { fontSize: "1.125rem", fontWeight: 700, marginBottom: "1rem", borderBottom: "1px solid var(--color-border)", paddingBottom: "0.5rem" }, children: "Range Sliders" }),
963
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "1rem", maxWidth: "24rem" }, children: [
964
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { children: [
965
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("label", { className: "qt-label", htmlFor: "range1", children: "Temperature" }),
966
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("input", { type: "range", id: "range1", className: "qt-range", style: { width: "100%" }, min: 0, max: 100, defaultValue: 65 })
967
+ ] }),
968
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { children: [
969
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("label", { className: "qt-label", htmlFor: "range2", style: { color: "var(--color-muted-foreground)" }, children: "Disabled slider" }),
970
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("input", { type: "range", id: "range2", className: "qt-range", style: { width: "100%" }, min: 0, max: 100, defaultValue: 35, disabled: true })
971
+ ] })
972
+ ] }),
973
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("p", { style: { fontSize: "0.75rem", color: "var(--color-muted-foreground)", marginTop: "0.75rem", maxWidth: "32rem" }, children: [
974
+ "Sliders render natively; ",
975
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("code", { children: "--qt-range-accent" }),
976
+ " colours both the filled portion of the track and the thumb. Overriding ",
977
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("code", { children: ".qt-range" }),
978
+ " with",
979
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("code", { children: " appearance: none" }),
980
+ " gives a theme full control of the track, but drops the filled bar in Chrome and Safari."
981
+ ] })
982
+ ] }),
961
983
  /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("section", { style: { marginBottom: "2rem" }, children: [
962
984
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h3", { style: { fontSize: "1.125rem", fontWeight: 700, marginBottom: "1rem", borderBottom: "1px solid var(--color-border)", paddingBottom: "0.5rem" }, children: "Links" }),
963
985
  /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "0.75rem" }, children: [
@@ -1489,10 +1511,33 @@ var Dialogs = () => {
1489
1511
  ] }),
1490
1512
  /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("section", { children: [
1491
1513
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h3", { style: { fontSize: "1.125rem", fontWeight: 700, marginBottom: "1rem", borderBottom: "1px solid var(--color-border)", paddingBottom: "0.5rem" }, children: "Tooltip" }),
1492
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: { display: "flex", alignItems: "center", gap: "2rem" }, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { position: "relative", display: "inline-block", marginTop: "2rem" }, children: [
1493
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { className: "qt-button qt-button-secondary", children: "Hover me" }),
1494
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "qt-tooltip", style: { position: "absolute", left: "50%", transform: "translateX(-50%)", bottom: "100%", marginBottom: "0.5rem", display: "block" }, children: "Helpful tooltip text" })
1495
- ] }) })
1514
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { display: "flex", alignItems: "flex-end", gap: "4rem", flexWrap: "wrap" }, children: [
1515
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { position: "relative", display: "inline-block", marginTop: "2rem" }, children: [
1516
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { className: "qt-button qt-button-secondary", children: "Hover me" }),
1517
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "qt-tooltip", style: { position: "absolute", left: "50%", transform: "translateX(-50%)", bottom: "100%", marginBottom: "0.5rem", display: "block" }, children: "Helpful tooltip text" })
1518
+ ] }),
1519
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { position: "relative", display: "inline-block", marginTop: "14rem" }, children: [
1520
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { className: "qt-button qt-button-secondary", children: "Pinned, with detail" }),
1521
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1522
+ "div",
1523
+ {
1524
+ className: "qt-tooltip",
1525
+ "data-interactive": "true",
1526
+ "data-pinned": "true",
1527
+ style: { position: "absolute", left: "50%", transform: "translateX(-50%)", bottom: "100%", marginBottom: "0.5rem", display: "block", width: "20rem" },
1528
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "qt-tooltip-body", children: [
1529
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "qt-tooltip-title", children: "Amended" }),
1530
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { children: "On reflection the author corrected this reply to match the record." }),
1531
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "qt-tooltip-section", children: [
1532
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "qt-tooltip-section-label", children: "What looked off" }),
1533
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "qt-tooltip-quote", children: "The ledger excerpt returned by the document read shows a metric column." })
1534
+ ] }),
1535
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "qt-tooltip-hint", children: "Click the badge to pin this note; Esc dismisses it." })
1536
+ ] })
1537
+ }
1538
+ )
1539
+ ] })
1540
+ ] })
1496
1541
  ] })
1497
1542
  ] });
1498
1543
  };
@@ -2128,6 +2173,28 @@ var Chat = () => {
2128
2173
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "qt-emoji-picker-message", children: "Couldn't load emoji" })
2129
2174
  ] }) })
2130
2175
  ] }),
2176
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("section", { style: { marginBottom: "2rem" }, children: [
2177
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h3", { style: { fontSize: "1.125rem", fontWeight: 700, marginBottom: "1rem", borderBottom: "1px solid var(--color-border)", paddingBottom: "0.5rem" }, children: "Answer-Confirmation Badges" }),
2178
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { style: { fontSize: "0.875rem", color: "var(--color-muted-foreground)", marginBottom: "1rem" }, children: "The fact-checker's verdict on a message, shown among the message action icons. Quiet by design; the discrepancy notes live in a tooltip. Hover one to see its hover state." }),
2179
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "0.75rem", flexWrap: "wrap" }, children: [
2180
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("button", { className: "qt-confirmation-badge", "data-confirmation-state": "vouched", children: [
2181
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "qt-confirmation-badge-glyph", children: "\u2713" }),
2182
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "qt-confirmation-badge-label", children: "Vouched" })
2183
+ ] }),
2184
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("button", { className: "qt-confirmation-badge", "data-confirmation-state": "amended", children: [
2185
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "qt-confirmation-badge-glyph", children: "\u270E" }),
2186
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "qt-confirmation-badge-label", children: "Amended" })
2187
+ ] }),
2188
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("button", { className: "qt-confirmation-badge", "data-confirmation-state": "stood-by", children: [
2189
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "qt-confirmation-badge-glyph", children: "!" }),
2190
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "qt-confirmation-badge-label", children: "Stood by" })
2191
+ ] }),
2192
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("button", { className: "qt-confirmation-badge", "data-confirmation-state": "unvetted", children: [
2193
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "qt-confirmation-badge-glyph", children: "\u2014" }),
2194
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "qt-confirmation-badge-label", children: "Unvetted" })
2195
+ ] })
2196
+ ] })
2197
+ ] }),
2131
2198
  /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("section", { children: [
2132
2199
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h3", { style: { fontSize: "1.125rem", fontWeight: 700, marginBottom: "1rem", borderBottom: "1px solid var(--color-border)", paddingBottom: "0.5rem" }, children: "Full Chat Layout" }),
2133
2200
  /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "qt-chat-layout", style: { height: "24rem", border: "1px solid var(--color-border)", borderRadius: "var(--radius-lg)", display: "flex", flexDirection: "column" }, children: [
package/dist/index.mjs CHANGED
@@ -21,7 +21,7 @@ import {
21
21
  ThemeComparison,
22
22
  Typography,
23
23
  Workspace
24
- } from "./chunk-TESCTXU3.mjs";
24
+ } from "./chunk-IAVNW2EO.mjs";
25
25
  import "./chunk-WUKYLWAZ.mjs";
26
26
 
27
27
  // src/preview.tsx
@@ -895,6 +895,28 @@ var Inputs = () => {
895
895
  ] })
896
896
  ] })
897
897
  ] }),
898
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("section", { style: { marginBottom: "2rem" }, children: [
899
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h3", { style: { fontSize: "1.125rem", fontWeight: 700, marginBottom: "1rem", borderBottom: "1px solid var(--color-border)", paddingBottom: "0.5rem" }, children: "Range Sliders" }),
900
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "1rem", maxWidth: "24rem" }, children: [
901
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { children: [
902
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("label", { className: "qt-label", htmlFor: "range1", children: "Temperature" }),
903
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("input", { type: "range", id: "range1", className: "qt-range", style: { width: "100%" }, min: 0, max: 100, defaultValue: 65 })
904
+ ] }),
905
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { children: [
906
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("label", { className: "qt-label", htmlFor: "range2", style: { color: "var(--color-muted-foreground)" }, children: "Disabled slider" }),
907
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("input", { type: "range", id: "range2", className: "qt-range", style: { width: "100%" }, min: 0, max: 100, defaultValue: 35, disabled: true })
908
+ ] })
909
+ ] }),
910
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { style: { fontSize: "0.75rem", color: "var(--color-muted-foreground)", marginTop: "0.75rem", maxWidth: "32rem" }, children: [
911
+ "Sliders render natively; ",
912
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("code", { children: "--qt-range-accent" }),
913
+ " colours both the filled portion of the track and the thumb. Overriding ",
914
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("code", { children: ".qt-range" }),
915
+ " with",
916
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("code", { children: " appearance: none" }),
917
+ " gives a theme full control of the track, but drops the filled bar in Chrome and Safari."
918
+ ] })
919
+ ] }),
898
920
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("section", { style: { marginBottom: "2rem" }, children: [
899
921
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h3", { style: { fontSize: "1.125rem", fontWeight: 700, marginBottom: "1rem", borderBottom: "1px solid var(--color-border)", paddingBottom: "0.5rem" }, children: "Links" }),
900
922
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "0.75rem" }, children: [
@@ -1426,10 +1448,33 @@ var Dialogs = () => {
1426
1448
  ] }),
1427
1449
  /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("section", { children: [
1428
1450
  /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h3", { style: { fontSize: "1.125rem", fontWeight: 700, marginBottom: "1rem", borderBottom: "1px solid var(--color-border)", paddingBottom: "0.5rem" }, children: "Tooltip" }),
1429
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { display: "flex", alignItems: "center", gap: "2rem" }, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { position: "relative", display: "inline-block", marginTop: "2rem" }, children: [
1430
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { className: "qt-button qt-button-secondary", children: "Hover me" }),
1431
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "qt-tooltip", style: { position: "absolute", left: "50%", transform: "translateX(-50%)", bottom: "100%", marginBottom: "0.5rem", display: "block" }, children: "Helpful tooltip text" })
1432
- ] }) })
1451
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { display: "flex", alignItems: "flex-end", gap: "4rem", flexWrap: "wrap" }, children: [
1452
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { position: "relative", display: "inline-block", marginTop: "2rem" }, children: [
1453
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { className: "qt-button qt-button-secondary", children: "Hover me" }),
1454
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "qt-tooltip", style: { position: "absolute", left: "50%", transform: "translateX(-50%)", bottom: "100%", marginBottom: "0.5rem", display: "block" }, children: "Helpful tooltip text" })
1455
+ ] }),
1456
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { position: "relative", display: "inline-block", marginTop: "14rem" }, children: [
1457
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { className: "qt-button qt-button-secondary", children: "Pinned, with detail" }),
1458
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1459
+ "div",
1460
+ {
1461
+ className: "qt-tooltip",
1462
+ "data-interactive": "true",
1463
+ "data-pinned": "true",
1464
+ style: { position: "absolute", left: "50%", transform: "translateX(-50%)", bottom: "100%", marginBottom: "0.5rem", display: "block", width: "20rem" },
1465
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "qt-tooltip-body", children: [
1466
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "qt-tooltip-title", children: "Amended" }),
1467
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { children: "On reflection the author corrected this reply to match the record." }),
1468
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "qt-tooltip-section", children: [
1469
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "qt-tooltip-section-label", children: "What looked off" }),
1470
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "qt-tooltip-quote", children: "The ledger excerpt returned by the document read shows a metric column." })
1471
+ ] }),
1472
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "qt-tooltip-hint", children: "Click the badge to pin this note; Esc dismisses it." })
1473
+ ] })
1474
+ }
1475
+ )
1476
+ ] })
1477
+ ] })
1433
1478
  ] })
1434
1479
  ] });
1435
1480
  };
@@ -2065,6 +2110,28 @@ var Chat = () => {
2065
2110
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "qt-emoji-picker-message", children: "Couldn't load emoji" })
2066
2111
  ] }) })
2067
2112
  ] }),
2113
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("section", { style: { marginBottom: "2rem" }, children: [
2114
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h3", { style: { fontSize: "1.125rem", fontWeight: 700, marginBottom: "1rem", borderBottom: "1px solid var(--color-border)", paddingBottom: "0.5rem" }, children: "Answer-Confirmation Badges" }),
2115
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { style: { fontSize: "0.875rem", color: "var(--color-muted-foreground)", marginBottom: "1rem" }, children: "The fact-checker's verdict on a message, shown among the message action icons. Quiet by design; the discrepancy notes live in a tooltip. Hover one to see its hover state." }),
2116
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "0.75rem", flexWrap: "wrap" }, children: [
2117
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("button", { className: "qt-confirmation-badge", "data-confirmation-state": "vouched", children: [
2118
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "qt-confirmation-badge-glyph", children: "\u2713" }),
2119
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "qt-confirmation-badge-label", children: "Vouched" })
2120
+ ] }),
2121
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("button", { className: "qt-confirmation-badge", "data-confirmation-state": "amended", children: [
2122
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "qt-confirmation-badge-glyph", children: "\u270E" }),
2123
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "qt-confirmation-badge-label", children: "Amended" })
2124
+ ] }),
2125
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("button", { className: "qt-confirmation-badge", "data-confirmation-state": "stood-by", children: [
2126
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "qt-confirmation-badge-glyph", children: "!" }),
2127
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "qt-confirmation-badge-label", children: "Stood by" })
2128
+ ] }),
2129
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("button", { className: "qt-confirmation-badge", "data-confirmation-state": "unvetted", children: [
2130
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "qt-confirmation-badge-glyph", children: "\u2014" }),
2131
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "qt-confirmation-badge-label", children: "Unvetted" })
2132
+ ] })
2133
+ ] })
2134
+ ] }),
2068
2135
  /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("section", { children: [
2069
2136
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h3", { style: { fontSize: "1.125rem", fontWeight: 700, marginBottom: "1rem", borderBottom: "1px solid var(--color-border)", paddingBottom: "0.5rem" }, children: "Full Chat Layout" }),
2070
2137
  /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "qt-chat-layout", style: { height: "24rem", border: "1px solid var(--color-border)", borderRadius: "var(--radius-lg)", display: "flex", flexDirection: "column" }, children: [
@@ -21,7 +21,7 @@ import {
21
21
  ThemeComparison,
22
22
  Typography,
23
23
  Workspace
24
- } from "../chunk-TESCTXU3.mjs";
24
+ } from "../chunk-IAVNW2EO.mjs";
25
25
  import "../chunk-WUKYLWAZ.mjs";
26
26
  export {
27
27
  Avatars,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quilltap/theme-storybook",
3
- "version": "1.0.65",
3
+ "version": "1.0.67",
4
4
  "description": "Storybook preset and stories for developing Quilltap theme plugins",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -83,6 +83,12 @@
83
83
  --qt-radio-accent: var(--color-primary);
84
84
  --qt-radio-focus-ring: var(--color-ring);
85
85
 
86
+ /* Range slider variables. Sliders stay natively rendered: accent-color paints
87
+ the filled track and the thumb, which `appearance: none` would discard in
88
+ Chrome and Safari. */
89
+ --qt-range-accent: var(--color-primary);
90
+ --qt-range-focus-ring: var(--color-ring);
91
+
86
92
  /* Navbar variables */
87
93
  --qt-navbar-height: 3.5rem;
88
94
  --qt-navbar-bg: var(--color-background);
@@ -873,6 +879,31 @@
873
879
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--qt-radio-focus-ring) 35%, transparent);
874
880
  }
875
881
 
882
+ /* ==========================================================================
883
+ RANGE (SLIDER) COMPONENT
884
+ Natively rendered on purpose — accent-color paints the filled portion of the
885
+ track and the thumb. Do not reimplement with appearance:none plus custom
886
+ ::-webkit-slider-thumb / ::-moz-range-thumb rules: that discards the filled
887
+ bar in Chrome and Safari. Call sites own width/layout.
888
+ ========================================================================== */
889
+
890
+ .qt-range {
891
+ cursor: pointer;
892
+ accent-color: var(--qt-range-accent);
893
+ }
894
+
895
+ .qt-range:focus-visible {
896
+ outline: none;
897
+ box-shadow: 0 0 0 2px color-mix(in srgb, var(--qt-range-focus-ring) 35%, transparent);
898
+ }
899
+
900
+ /* No disabled opacity on purpose: browsers already drop the accent on a
901
+ disabled range, and app call sites nest these inside dimmed wrappers where a
902
+ second 50% would compound to 25%. */
903
+ .qt-range:disabled {
904
+ cursor: not-allowed;
905
+ }
906
+
876
907
  /* ==========================================================================
877
908
  BADGE COMPONENTS
878
909
  ========================================================================== */
@@ -1383,6 +1414,73 @@
1383
1414
  border-left-color: var(--qt-alert-info-border);
1384
1415
  }
1385
1416
 
1417
+ /* --------------------------------------------------------------------------
1418
+ ANSWER-CONFIRMATION BADGE
1419
+ A quiet per-message verdict marker (Vouched / Amended / Stood by /
1420
+ Unvetted). The glyph carries the state; a tooltip holds the discrepancy
1421
+ notes. Metadata, not an alarm.
1422
+ -------------------------------------------------------------------------- */
1423
+
1424
+ .qt-confirmation-badge {
1425
+ display: inline-flex;
1426
+ align-items: center;
1427
+ gap: 0.2rem;
1428
+ padding: 0.05rem 0.4rem;
1429
+ border-radius: 0.375rem;
1430
+ border: 1px solid color-mix(in srgb, currentColor 25%, transparent);
1431
+ background: transparent;
1432
+ font: inherit;
1433
+ line-height: 1.4;
1434
+ cursor: help;
1435
+ color: var(--qt-text-secondary-fg, var(--qt-text-secondary));
1436
+ opacity: 0.8;
1437
+ user-select: none;
1438
+ white-space: nowrap;
1439
+ transition: color 150ms, background-color 150ms, border-color 150ms, opacity 150ms;
1440
+ }
1441
+
1442
+ /* The badge sits among the message action icons and answers the pointer the
1443
+ same way they do. */
1444
+ .qt-confirmation-badge:hover,
1445
+ .qt-confirmation-badge:focus-visible {
1446
+ opacity: 1;
1447
+ border-color: color-mix(in srgb, currentColor 45%, transparent);
1448
+ background: color-mix(in srgb, var(--color-muted) 50%, transparent);
1449
+ }
1450
+
1451
+ /* The tinted states (stood-by, amended) keep their own colour on hover; the
1452
+ quiet ones brighten to the foreground the way the action icons do. */
1453
+ .qt-confirmation-badge[data-confirmation-state="vouched"]:hover,
1454
+ .qt-confirmation-badge[data-confirmation-state="vouched"]:focus-visible,
1455
+ .qt-confirmation-badge[data-confirmation-state="unvetted"]:hover,
1456
+ .qt-confirmation-badge[data-confirmation-state="unvetted"]:focus-visible {
1457
+ color: var(--color-foreground);
1458
+ }
1459
+
1460
+ .qt-confirmation-badge:focus-visible {
1461
+ outline: 2px solid color-mix(in srgb, var(--color-foreground) 45%, transparent);
1462
+ outline-offset: 2px;
1463
+ }
1464
+
1465
+ .qt-chat-message-user .qt-confirmation-badge:hover,
1466
+ .qt-chat-message-user .qt-confirmation-badge:focus-visible {
1467
+ color: var(--qt-chat-user-fg);
1468
+ background: color-mix(in srgb, var(--qt-chat-user-fg) 15%, transparent);
1469
+ }
1470
+
1471
+ .qt-confirmation-badge-glyph {
1472
+ font-weight: 600;
1473
+ }
1474
+
1475
+ .qt-confirmation-badge[data-confirmation-state="stood-by"] {
1476
+ color: var(--qt-warning-box-fg, var(--qt-text-secondary-fg));
1477
+ opacity: 1;
1478
+ }
1479
+
1480
+ .qt-confirmation-badge[data-confirmation-state="amended"] {
1481
+ opacity: 1;
1482
+ }
1483
+
1386
1484
  /* ==========================================================================
1387
1485
  CHAT — STAFF ANNOUNCEMENTS
1388
1486
  Messages authored by a personified feature (the Librarian, the Host, Pascal
@@ -2101,6 +2199,81 @@
2101
2199
  outline: none;
2102
2200
  }
2103
2201
 
2202
+ /* ==========================================================================
2203
+ TOOLTIP
2204
+ ==========================================================================
2205
+ Quilltap draws its own tooltips rather than leaning on the native `title`
2206
+ attribute, which the Electron shell renders unreliably. The bubble is
2207
+ portalled to `document.body` and positioned from script, so it escapes every
2208
+ stacking context and sits above dialogs (z-index 60). */
2209
+
2210
+ .qt-tooltip {
2211
+ position: fixed;
2212
+ z-index: 70;
2213
+ padding: 0.5rem 0.75rem;
2214
+ font-size: 0.75rem;
2215
+ line-height: 1.45;
2216
+ max-width: min(24rem, calc(100vw - 1rem));
2217
+ border-radius: var(--qt-popover-radius);
2218
+ background: var(--color-foreground);
2219
+ color: var(--color-background);
2220
+ border: 1px solid color-mix(in srgb, var(--color-background) 20%, transparent);
2221
+ box-shadow: var(--qt-popover-shadow);
2222
+ text-align: left;
2223
+ white-space: pre-line;
2224
+ /* Transparent to the pointer, so hovering never chases the bubble away —
2225
+ until the bubble is interactive (scrollable or pinned). */
2226
+ pointer-events: none;
2227
+ }
2228
+
2229
+ .qt-tooltip[data-interactive="true"] {
2230
+ pointer-events: auto;
2231
+ }
2232
+
2233
+ .qt-tooltip[data-pinned="true"] {
2234
+ border-color: color-mix(in srgb, var(--color-background) 45%, transparent);
2235
+ }
2236
+
2237
+ /* Layout-neutral wrapper carrying the hover/focus listeners. */
2238
+ .qt-tooltip-anchor {
2239
+ display: inline-flex;
2240
+ align-items: center;
2241
+ }
2242
+
2243
+ /* Structured tooltip contents — a heading, labelled sections, a closing hint. */
2244
+ .qt-tooltip-body {
2245
+ max-height: 40vh;
2246
+ overflow-y: auto;
2247
+ overscroll-behavior: contain;
2248
+ }
2249
+
2250
+ .qt-tooltip-title {
2251
+ font-weight: 600;
2252
+ margin-bottom: 0.15rem;
2253
+ }
2254
+
2255
+ .qt-tooltip-section {
2256
+ margin-top: 0.5rem;
2257
+ }
2258
+
2259
+ .qt-tooltip-section-label {
2260
+ text-transform: uppercase;
2261
+ font-size: 0.625rem;
2262
+ letter-spacing: 0.05em;
2263
+ opacity: 0.7;
2264
+ }
2265
+
2266
+ .qt-tooltip-quote {
2267
+ white-space: pre-wrap;
2268
+ opacity: 0.92;
2269
+ }
2270
+
2271
+ .qt-tooltip-hint {
2272
+ margin-top: 0.5rem;
2273
+ font-size: 0.625rem;
2274
+ opacity: 0.65;
2275
+ }
2276
+
2104
2277
  /* ==========================================================================
2105
2278
  TYPEAHEAD MENU
2106
2279
  ==========================================================================
@@ -691,6 +691,35 @@ export const Chat: React.FC = () => {
691
691
  </div>
692
692
  </section>
693
693
 
694
+ {/* Answer-Confirmation Badges */}
695
+ <section style={{ marginBottom: '2rem' }}>
696
+ <h3 style={{ fontSize: '1.125rem', fontWeight: 700, marginBottom: '1rem', borderBottom: '1px solid var(--color-border)', paddingBottom: '0.5rem' }}>
697
+ Answer-Confirmation Badges
698
+ </h3>
699
+ <p style={{ fontSize: '0.875rem', color: 'var(--color-muted-foreground)', marginBottom: '1rem' }}>
700
+ The fact-checker&apos;s verdict on a message, shown among the message action icons. Quiet by
701
+ design; the discrepancy notes live in a tooltip. Hover one to see its hover state.
702
+ </p>
703
+ <div style={{ display: 'flex', alignItems: 'center', gap: '0.75rem', flexWrap: 'wrap' }}>
704
+ <button className="qt-confirmation-badge" data-confirmation-state="vouched">
705
+ <span className="qt-confirmation-badge-glyph">✓</span>
706
+ <span className="qt-confirmation-badge-label">Vouched</span>
707
+ </button>
708
+ <button className="qt-confirmation-badge" data-confirmation-state="amended">
709
+ <span className="qt-confirmation-badge-glyph">✎</span>
710
+ <span className="qt-confirmation-badge-label">Amended</span>
711
+ </button>
712
+ <button className="qt-confirmation-badge" data-confirmation-state="stood-by">
713
+ <span className="qt-confirmation-badge-glyph">!</span>
714
+ <span className="qt-confirmation-badge-label">Stood by</span>
715
+ </button>
716
+ <button className="qt-confirmation-badge" data-confirmation-state="unvetted">
717
+ <span className="qt-confirmation-badge-glyph">—</span>
718
+ <span className="qt-confirmation-badge-label">Unvetted</span>
719
+ </button>
720
+ </div>
721
+ </section>
722
+
694
723
  {/* Full Chat Layout Preview */}
695
724
  <section>
696
725
  <h3 style={{ fontSize: '1.125rem', fontWeight: 700, marginBottom: '1rem', borderBottom: '1px solid var(--color-border)', paddingBottom: '0.5rem' }}>
@@ -237,13 +237,34 @@ export const Dialogs: React.FC = () => {
237
237
  <h3 style={{ fontSize: '1.125rem', fontWeight: 700, marginBottom: '1rem', borderBottom: '1px solid var(--color-border)', paddingBottom: '0.5rem' }}>
238
238
  Tooltip
239
239
  </h3>
240
- <div style={{ display: 'flex', alignItems: 'center', gap: '2rem' }}>
240
+ <div style={{ display: 'flex', alignItems: 'flex-end', gap: '4rem', flexWrap: 'wrap' }}>
241
241
  <div style={{ position: 'relative', display: 'inline-block', marginTop: '2rem' }}>
242
242
  <button className="qt-button qt-button-secondary">Hover me</button>
243
243
  <div className="qt-tooltip" style={{ position: 'absolute', left: '50%', transform: 'translateX(-50%)', bottom: '100%', marginBottom: '0.5rem', display: 'block' }}>
244
244
  Helpful tooltip text
245
245
  </div>
246
246
  </div>
247
+
248
+ {/* Structured (pinned) tooltip — a heading, labelled sections, a hint */}
249
+ <div style={{ position: 'relative', display: 'inline-block', marginTop: '14rem' }}>
250
+ <button className="qt-button qt-button-secondary">Pinned, with detail</button>
251
+ <div
252
+ className="qt-tooltip"
253
+ data-interactive="true"
254
+ data-pinned="true"
255
+ style={{ position: 'absolute', left: '50%', transform: 'translateX(-50%)', bottom: '100%', marginBottom: '0.5rem', display: 'block', width: '20rem' }}
256
+ >
257
+ <div className="qt-tooltip-body">
258
+ <p className="qt-tooltip-title">Amended</p>
259
+ <p>On reflection the author corrected this reply to match the record.</p>
260
+ <div className="qt-tooltip-section">
261
+ <p className="qt-tooltip-section-label">What looked off</p>
262
+ <p className="qt-tooltip-quote">The ledger excerpt returned by the document read shows a metric column.</p>
263
+ </div>
264
+ <p className="qt-tooltip-hint">Click the badge to pin this note; Esc dismisses it.</p>
265
+ </div>
266
+ </div>
267
+ </div>
247
268
  </div>
248
269
  </section>
249
270
  </div>
@@ -102,6 +102,29 @@ export const Inputs: React.FC = () => {
102
102
  </div>
103
103
  </section>
104
104
 
105
+ {/* Range sliders */}
106
+ <section style={{ marginBottom: '2rem' }}>
107
+ <h3 style={{ fontSize: '1.125rem', fontWeight: 700, marginBottom: '1rem', borderBottom: '1px solid var(--color-border)', paddingBottom: '0.5rem' }}>
108
+ Range Sliders
109
+ </h3>
110
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '1rem', maxWidth: '24rem' }}>
111
+ <div>
112
+ <label className="qt-label" htmlFor="range1">Temperature</label>
113
+ <input type="range" id="range1" className="qt-range" style={{ width: '100%' }} min={0} max={100} defaultValue={65} />
114
+ </div>
115
+ <div>
116
+ <label className="qt-label" htmlFor="range2" style={{ color: 'var(--color-muted-foreground)' }}>Disabled slider</label>
117
+ <input type="range" id="range2" className="qt-range" style={{ width: '100%' }} min={0} max={100} defaultValue={35} disabled />
118
+ </div>
119
+ </div>
120
+ <p style={{ fontSize: '0.75rem', color: 'var(--color-muted-foreground)', marginTop: '0.75rem', maxWidth: '32rem' }}>
121
+ Sliders render natively; <code>--qt-range-accent</code> colours both the filled
122
+ portion of the track and the thumb. Overriding <code>.qt-range</code> with
123
+ <code> appearance: none</code> gives a theme full control of the track, but drops
124
+ the filled bar in Chrome and Safari.
125
+ </p>
126
+ </section>
127
+
105
128
  {/* Links */}
106
129
  <section style={{ marginBottom: '2rem' }}>
107
130
  <h3 style={{ fontSize: '1.125rem', fontWeight: 700, marginBottom: '1rem', borderBottom: '1px solid var(--color-border)', paddingBottom: '0.5rem' }}>