@ksp-gonogo/ui-kit 1.0.0-rc.21 → 1.0.0-rc.25

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/dist/index.js CHANGED
@@ -128,7 +128,6 @@ import {
128
128
  WidgetSections,
129
129
  asQuantityish,
130
130
  badgeFace,
131
- bandClaim,
132
131
  clearAugments,
133
132
  commandFailedSentence,
134
133
  commandFoundSentence,
@@ -151,6 +150,9 @@ import {
151
150
  getSizeBucket,
152
151
  getWidgetShape,
153
152
  gridFloor,
153
+ heldFigureOf,
154
+ heldGradeOf,
155
+ heldMarking,
154
156
  heldNameMarker,
155
157
  heldWord,
156
158
  kspCalendar,
@@ -209,13 +211,13 @@ import {
209
211
  writeQuantity,
210
212
  writtenAs,
211
213
  writtenQuantity
212
- } from "./chunk-GGJES6XH.js";
214
+ } from "./chunk-JNKL3HA3.js";
213
215
  import {
214
216
  COL_WIDTH,
215
217
  GRID_MARGIN,
216
218
  ROW_HEIGHT,
217
219
  gridToPixels
218
- } from "./chunk-IZZF25H2.js";
220
+ } from "./chunk-SPBHQUHI.js";
219
221
  import "./chunk-G3PMV62Z.js";
220
222
 
221
223
  // ../theme/dist/DefaultThemeProvider.js
@@ -361,7 +363,7 @@ function ComboboxListbox({
361
363
  onSelectKey,
362
364
  renderItem,
363
365
  emptyLabel = "No matches",
364
- ariaLabel,
366
+ "aria-label": ariaLabel,
365
367
  placement = "below"
366
368
  }) {
367
369
  return /* @__PURE__ */ jsx2(
@@ -456,7 +458,7 @@ function ActionMenu({
456
458
  items,
457
459
  onSelect,
458
460
  onDismiss,
459
- ariaLabel,
461
+ "aria-label": ariaLabel,
460
462
  style,
461
463
  header,
462
464
  footer,
@@ -556,7 +558,7 @@ function ActionMenu({
556
558
  {
557
559
  type: "button",
558
560
  role: "menuitem",
559
- "aria-label": item.ariaLabel,
561
+ "aria-label": item["aria-label"],
560
562
  "aria-disabled": item.disabled,
561
563
  $disabled: item.disabled,
562
564
  tabIndex: index === activeIndex ? 0 : -1,
@@ -1083,7 +1085,7 @@ function AugmentSettingsPanel({
1083
1085
  Switch,
1084
1086
  {
1085
1087
  checked: Boolean(current),
1086
- onChange: (value4) => onChange(block.namespace, field.key, value4),
1088
+ onChange: (value5) => onChange(block.namespace, field.key, value5),
1087
1089
  label
1088
1090
  }
1089
1091
  ) }, `${block.namespace}.${field.key}`);
@@ -1142,6 +1144,133 @@ var AutoEmptyState__Fallback = styled6.div`
1142
1144
  }
1143
1145
  `;
1144
1146
 
1147
+ // src/AvatarStack.tsx
1148
+ import styled7 from "styled-components";
1149
+ import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
1150
+ function initialsOf(name) {
1151
+ const parts = name.trim().split(/\s+/).filter(Boolean);
1152
+ if (parts.length === 0) return "?";
1153
+ const letters = parts.length === 1 ? Array.from(parts[0] ?? "").slice(0, 2) : parts.slice(0, 2).map((word) => Array.from(word)[0] ?? "");
1154
+ return letters.join("").toUpperCase();
1155
+ }
1156
+ var DEFAULT_MAX = 3;
1157
+ function AvatarStack({
1158
+ items,
1159
+ max = DEFAULT_MAX,
1160
+ label
1161
+ }) {
1162
+ const places = Math.max(1, Math.floor(max));
1163
+ const overflowing = items.length > places;
1164
+ const shown = overflowing ? items.slice(0, places - 1) : items;
1165
+ const hidden = overflowing ? items.slice(places - 1) : [];
1166
+ return /* @__PURE__ */ jsxs8(
1167
+ AvatarStack__Row,
1168
+ {
1169
+ $places: places,
1170
+ role: "group",
1171
+ ...label === void 0 ? {} : { "aria-label": label },
1172
+ children: [
1173
+ shown.map((item) => /* @__PURE__ */ jsx9(
1174
+ Tooltip,
1175
+ {
1176
+ text: item.name,
1177
+ announce: false,
1178
+ focusable: item.onSelect === void 0,
1179
+ children: item.onSelect === void 0 ? /* @__PURE__ */ jsx9(
1180
+ AvatarStack__Face,
1181
+ {
1182
+ $tone: item.tone,
1183
+ role: "img",
1184
+ "aria-label": item.name,
1185
+ children: initialsOf(item.name)
1186
+ }
1187
+ ) : /* @__PURE__ */ jsx9(
1188
+ AvatarStack__Face,
1189
+ {
1190
+ as: "button",
1191
+ type: "button",
1192
+ $tone: item.tone,
1193
+ "aria-label": item.name,
1194
+ onClick: item.onSelect,
1195
+ children: initialsOf(item.name)
1196
+ }
1197
+ )
1198
+ },
1199
+ item.id
1200
+ )),
1201
+ hidden.length > 0 && /* @__PURE__ */ jsx9(
1202
+ Tooltip,
1203
+ {
1204
+ text: hidden.map((item) => item.name).join(", "),
1205
+ announce: false,
1206
+ focusable: true,
1207
+ children: /* @__PURE__ */ jsxs8(
1208
+ AvatarStack__Face,
1209
+ {
1210
+ $tone: void 0,
1211
+ role: "img",
1212
+ "aria-label": `${hidden.length} more: ${hidden.map((item) => item.name).join(", ")}`,
1213
+ children: [
1214
+ "+",
1215
+ hidden.length
1216
+ ]
1217
+ }
1218
+ )
1219
+ }
1220
+ )
1221
+ ]
1222
+ }
1223
+ );
1224
+ }
1225
+ var AvatarStack__Row = styled7.div`
1226
+ /* Two insets short of a control, so a stack in a bordered control of that height always fits inside it. */
1227
+ --avatar-size: calc(var(--control-height) - 2 * var(--inset-avatar));
1228
+ /*
1229
+ * Initials are centred, so the later badge must leave the earlier one's
1230
+ * letters clear: the step is nearly the whole badge and only a sliver of
1231
+ * edge is covered.
1232
+ */
1233
+ --avatar-step: calc(var(--avatar-size) * 0.92);
1234
+ display: flex;
1235
+ align-items: center;
1236
+ flex: none;
1237
+ block-size: var(--avatar-size);
1238
+ /* One place is a whole avatar and every further one only its uncovered part. */
1239
+ inline-size: calc(
1240
+ var(--avatar-size) + (${({ $places }) => $places} - 1) * var(--avatar-step)
1241
+ );
1242
+ `;
1243
+ var AvatarStack__Face = styled7.span`
1244
+ flex: none;
1245
+ display: inline-flex;
1246
+ align-items: center;
1247
+ justify-content: center;
1248
+ inline-size: var(--avatar-size);
1249
+ block-size: var(--avatar-size);
1250
+ margin: 0;
1251
+ padding: 0;
1252
+ border: 1px solid ${({ $tone }) => TONE_MARK[$tone ?? "neutral"]};
1253
+ border-radius: var(--radius-circle);
1254
+ background: var(--color-surface-raised);
1255
+ color: ${({ $tone }) => TONE_TEXT[$tone ?? "neutral"]};
1256
+ font: inherit;
1257
+ font-size: var(--font-size-caption);
1258
+ font-weight: 600;
1259
+ line-height: var(--line-height-flush);
1260
+ white-space: nowrap;
1261
+ /* Each avatar overlaps the one before it, which stays on top. */
1262
+ &:not(:first-child) {
1263
+ margin-inline-start: calc(var(--avatar-step) - var(--avatar-size));
1264
+ }
1265
+ &:is(button) {
1266
+ cursor: pointer;
1267
+ }
1268
+ ${focusRing}
1269
+ &:focus-visible {
1270
+ position: relative;
1271
+ }
1272
+ `;
1273
+
1145
1274
  // src/anchoredPosition.ts
1146
1275
  var GAP = 12;
1147
1276
  var EDGE = 8;
@@ -1160,8 +1289,8 @@ function place(anchor, extent, bound) {
1160
1289
  }
1161
1290
 
1162
1291
  // src/Band.tsx
1163
- import styled7 from "styled-components";
1164
- import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
1292
+ import styled8 from "styled-components";
1293
+ import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
1165
1294
  var INTERVAL_DASH = "\u2013";
1166
1295
  function Band({
1167
1296
  min,
@@ -1173,12 +1302,12 @@ function Band({
1173
1302
  const low = magnitudeOf(min);
1174
1303
  const high = magnitudeOf(max);
1175
1304
  if (min == null || max == null || low === null || high === null) {
1176
- return /* @__PURE__ */ jsx9(Band__Body, { className, children: NULL_DISPLAY });
1305
+ return /* @__PURE__ */ jsx10(Band__Body, { className, children: NULL_DISPLAY });
1177
1306
  }
1178
1307
  if (wrapsAt !== void 0 && Math.abs(high - low) >= wrapsAt / 2) {
1179
- return /* @__PURE__ */ jsx9(Band__Body, { className, children: "(precesses)" });
1308
+ return /* @__PURE__ */ jsx10(Band__Body, { className, children: "(precesses)" });
1180
1309
  }
1181
- return /* @__PURE__ */ jsx9(UnitSharedFormat, { of: min.unit, separate: true, ...pins, children: /* @__PURE__ */ jsx9(BandEnds, { min, max, className }) });
1310
+ return /* @__PURE__ */ jsx10(UnitSharedFormat, { of: min.unit, separate: true, ...pins, children: /* @__PURE__ */ jsx10(BandEnds, { min, max, className }) });
1182
1311
  }
1183
1312
  function BandEnds({
1184
1313
  min,
@@ -1189,55 +1318,55 @@ function BandEnds({
1189
1318
  useSharedFormat(max);
1190
1319
  const oneFigure = useReadsAsOneFigure(min);
1191
1320
  if (oneFigure) {
1192
- return /* @__PURE__ */ jsx9(Band__Body, { className, children: /* @__PURE__ */ jsxs8(Band__Approximate, { children: [
1193
- /* @__PURE__ */ jsx9("span", { "aria-hidden": "true", children: "~" }),
1194
- /* @__PURE__ */ jsx9(VisuallyHidden, { children: "approximately " }),
1195
- /* @__PURE__ */ jsx9(Unit, { value: min })
1321
+ return /* @__PURE__ */ jsx10(Band__Body, { className, children: /* @__PURE__ */ jsxs9(Band__Approximate, { children: [
1322
+ /* @__PURE__ */ jsx10("span", { "aria-hidden": "true", children: "~" }),
1323
+ /* @__PURE__ */ jsx10(VisuallyHidden, { children: "approximately " }),
1324
+ /* @__PURE__ */ jsx10(Unit, { value: min })
1196
1325
  ] }) });
1197
1326
  }
1198
- return /* @__PURE__ */ jsxs8(Band__Body, { className, children: [
1199
- /* @__PURE__ */ jsx9(Unit, { value: min }),
1200
- /* @__PURE__ */ jsx9(Band__Dash, { "aria-hidden": "true", children: INTERVAL_DASH }),
1201
- /* @__PURE__ */ jsx9(VisuallyHidden, { children: " to " }),
1202
- /* @__PURE__ */ jsx9(Unit, { value: max })
1327
+ return /* @__PURE__ */ jsxs9(Band__Body, { className, children: [
1328
+ /* @__PURE__ */ jsx10(Unit, { value: min }),
1329
+ /* @__PURE__ */ jsx10(Band__Dash, { "aria-hidden": "true", children: INTERVAL_DASH }),
1330
+ /* @__PURE__ */ jsx10(VisuallyHidden, { children: " to " }),
1331
+ /* @__PURE__ */ jsx10(Unit, { value: max })
1203
1332
  ] });
1204
1333
  }
1205
- var Band__Body = styled7.span`
1334
+ var Band__Body = styled8.span`
1206
1335
  display: inline-flex;
1207
1336
  align-items: baseline;
1208
1337
  gap: var(--gap-figure-parts);
1209
1338
  font-variant-numeric: tabular-nums;
1210
1339
  white-space: nowrap;
1211
1340
  `;
1212
- var Band__Dash = styled7.span`
1341
+ var Band__Dash = styled8.span`
1213
1342
  color: var(--color-text-faint);
1214
1343
  `;
1215
- var Band__Approximate = styled7.span`
1344
+ var Band__Approximate = styled8.span`
1216
1345
  display: inline-flex;
1217
1346
  align-items: baseline;
1218
1347
  white-space: nowrap;
1219
1348
  `;
1220
1349
 
1221
1350
  // src/Block.tsx
1222
- import styled8 from "styled-components";
1351
+ import styled9 from "styled-components";
1223
1352
 
1224
1353
  // src/SubjectHeading.tsx
1225
- import { jsxs as jsxs9 } from "react/jsx-runtime";
1354
+ import { jsxs as jsxs10 } from "react/jsx-runtime";
1226
1355
  function SubjectHeading({
1227
1356
  children,
1228
1357
  status,
1229
1358
  gap = "related-packed",
1230
1359
  align = "center"
1231
1360
  }) {
1232
- return /* @__PURE__ */ jsxs9(Cluster, { align, gap, justify: "between", wrap: true, children: [
1361
+ return /* @__PURE__ */ jsxs10(Cluster, { align, gap, justify: "between", wrap: true, children: [
1233
1362
  children,
1234
1363
  status
1235
1364
  ] });
1236
1365
  }
1237
1366
 
1238
1367
  // src/Block.tsx
1239
- import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
1240
- var Block__Title = styled8.div`
1368
+ import { Fragment as Fragment3, jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
1369
+ var Block__Title = styled9.div`
1241
1370
  color: var(--color-text-primary);
1242
1371
  font-weight: 600;
1243
1372
  /* One rung above the body the arrangement sets; both halves are declared here, so a site cannot break the step. */
@@ -1247,7 +1376,7 @@ var Block__Title = styled8.div`
1247
1376
  flex: 1 1 auto;
1248
1377
  min-width: 0;
1249
1378
  `;
1250
- var Block__TitleLead = styled8.div`
1379
+ var Block__TitleLead = styled9.div`
1251
1380
  display: flex;
1252
1381
  align-items: baseline;
1253
1382
  gap: var(--gap-record-lead);
@@ -1255,37 +1384,37 @@ var Block__TitleLead = styled8.div`
1255
1384
  min-width: 0;
1256
1385
  `;
1257
1386
  function Block__TitleRow({ left, right, children }) {
1258
- return /* @__PURE__ */ jsx10(SubjectHeading, { align: "baseline", status: right, children: left == null ? children : /* @__PURE__ */ jsxs10(Block__TitleLead, { children: [
1387
+ return /* @__PURE__ */ jsx11(SubjectHeading, { align: "baseline", status: right, children: left == null ? children : /* @__PURE__ */ jsxs11(Block__TitleLead, { children: [
1259
1388
  left,
1260
1389
  children
1261
1390
  ] }) });
1262
1391
  }
1263
- var Block__Middle = styled8.div`
1392
+ var Block__Middle = styled9.div`
1264
1393
  display: flex;
1265
1394
  flex-wrap: wrap;
1266
1395
  align-items: flex-start;
1267
1396
  gap: var(--gap-related);
1268
1397
  `;
1269
- var Block__Body = styled8.div`
1398
+ var Block__Body = styled9.div`
1270
1399
  display: flex;
1271
1400
  flex-direction: column;
1272
1401
  gap: var(--gap-related);
1273
1402
  flex: 1 1 var(--block-body-floor, 9rem);
1274
1403
  min-width: 0;
1275
1404
  `;
1276
- var Block__Aside = styled8.div`
1405
+ var Block__Aside = styled9.div`
1277
1406
  min-width: 0;
1278
1407
  ${({ $side }) => $side ? `flex: 0 0 auto;
1279
1408
  --radius-display-frame: var(--radius-display-frame-aside);` : ""}
1280
1409
  `;
1281
- var Block__Footer = styled8.div`
1410
+ var Block__Footer = styled9.div`
1282
1411
  display: flex;
1283
1412
  align-items: center;
1284
1413
  justify-content: space-between;
1285
1414
  gap: var(--gap-related);
1286
1415
  flex-wrap: wrap;
1287
1416
  `;
1288
- var Block__Root = styled8.div`
1417
+ var Block__Root = styled9.div`
1289
1418
  display: flex;
1290
1419
  flex-direction: column;
1291
1420
  gap: var(--gap-related);
@@ -1308,22 +1437,22 @@ function renderBlockAnatomy(Root, {
1308
1437
  }) {
1309
1438
  const hasTitleRow = title != null || titleLeft != null || titleRight != null;
1310
1439
  const hasSideAside = left != null || right != null;
1311
- const heading = hasTitleRow && /* @__PURE__ */ jsx10(Block__TitleRow, { left: titleLeft, right: titleRight, children: title != null && /* @__PURE__ */ jsx10(Block__Title, { as: titleAs, children: title }) });
1312
- return /* @__PURE__ */ jsxs10(Root, { ...rest, children: [
1313
- top != null && /* @__PURE__ */ jsx10(Block__Aside, { $side: false, children: top }),
1314
- hasSideAside ? /* @__PURE__ */ jsxs10(Block__Middle, { children: [
1315
- left != null && /* @__PURE__ */ jsx10(Block__Aside, { $side: true, children: left }),
1316
- /* @__PURE__ */ jsxs10(Block__Body, { children: [
1440
+ const heading = hasTitleRow && /* @__PURE__ */ jsx11(Block__TitleRow, { left: titleLeft, right: titleRight, children: title != null && /* @__PURE__ */ jsx11(Block__Title, { as: titleAs, children: title }) });
1441
+ return /* @__PURE__ */ jsxs11(Root, { ...rest, children: [
1442
+ top != null && /* @__PURE__ */ jsx11(Block__Aside, { $side: false, children: top }),
1443
+ hasSideAside ? /* @__PURE__ */ jsxs11(Block__Middle, { children: [
1444
+ left != null && /* @__PURE__ */ jsx11(Block__Aside, { $side: true, children: left }),
1445
+ /* @__PURE__ */ jsxs11(Block__Body, { children: [
1317
1446
  heading,
1318
1447
  children
1319
1448
  ] }),
1320
- right != null && /* @__PURE__ */ jsx10(Block__Aside, { $side: true, children: right })
1321
- ] }) : /* @__PURE__ */ jsxs10(Fragment3, { children: [
1449
+ right != null && /* @__PURE__ */ jsx11(Block__Aside, { $side: true, children: right })
1450
+ ] }) : /* @__PURE__ */ jsxs11(Fragment3, { children: [
1322
1451
  heading,
1323
1452
  children
1324
1453
  ] }),
1325
- footer != null && /* @__PURE__ */ jsx10(Block__Footer, { children: footer }),
1326
- bottom != null && /* @__PURE__ */ jsx10(Block__Aside, { $side: false, children: bottom })
1454
+ footer != null && /* @__PURE__ */ jsx11(Block__Footer, { children: footer }),
1455
+ bottom != null && /* @__PURE__ */ jsx11(Block__Aside, { $side: false, children: bottom })
1327
1456
  ] });
1328
1457
  }
1329
1458
  var BLOCK_PARTS = {
@@ -1339,8 +1468,8 @@ function BlockRoot({ ...props }) {
1339
1468
  var Block = Object.assign(BlockRoot, BLOCK_PARTS);
1340
1469
 
1341
1470
  // src/Box.tsx
1342
- import styled9 from "styled-components";
1343
- import { jsx as jsx11 } from "react/jsx-runtime";
1471
+ import styled10 from "styled-components";
1472
+ import { jsx as jsx12 } from "react/jsx-runtime";
1344
1473
  var SURFACE_VAR = {
1345
1474
  app: "var(--color-surface-app)",
1346
1475
  panel: "var(--color-surface-panel)",
@@ -1355,7 +1484,7 @@ function Box({
1355
1484
  children,
1356
1485
  ...rest
1357
1486
  }) {
1358
- return /* @__PURE__ */ jsx11(
1487
+ return /* @__PURE__ */ jsx12(
1359
1488
  Box__Root,
1360
1489
  {
1361
1490
  $surface: surface,
@@ -1367,7 +1496,7 @@ function Box({
1367
1496
  }
1368
1497
  );
1369
1498
  }
1370
- var Box__Root = styled9.div`
1499
+ var Box__Root = styled10.div`
1371
1500
  ${({ $surface }) => $surface && `background: ${SURFACE_VAR[$surface]};`}
1372
1501
  ${({ $bordered }) => $bordered && `border: 1px solid var(--color-border-subtle);`}
1373
1502
  ${({ $radius }) => $radius && `border-radius: ${RADIUS_VAR[$radius]};`}
@@ -1376,11 +1505,11 @@ var Box__Root = styled9.div`
1376
1505
 
1377
1506
  // src/ButtonGroup.tsx
1378
1507
  import { forwardRef } from "react";
1379
- import styled10 from "styled-components";
1380
- import { jsx as jsx12 } from "react/jsx-runtime";
1508
+ import styled11 from "styled-components";
1509
+ import { jsx as jsx13 } from "react/jsx-runtime";
1381
1510
  var ButtonGroup = forwardRef(
1382
1511
  function ButtonGroup2({ equalWidth = true, gap, children, ...rest }, ref) {
1383
- return /* @__PURE__ */ jsx12(
1512
+ return /* @__PURE__ */ jsx13(
1384
1513
  ButtonGroup__Root,
1385
1514
  {
1386
1515
  ref,
@@ -1392,7 +1521,7 @@ var ButtonGroup = forwardRef(
1392
1521
  );
1393
1522
  }
1394
1523
  );
1395
- var ButtonGroup__Root = styled10.div`
1524
+ var ButtonGroup__Root = styled11.div`
1396
1525
  display: grid;
1397
1526
  grid-auto-flow: column;
1398
1527
  grid-auto-columns: ${({ $equalWidth }) => $equalWidth ? "1fr" : "auto"};
@@ -1403,9 +1532,9 @@ var ButtonGroup__Root = styled10.div`
1403
1532
  `;
1404
1533
 
1405
1534
  // src/Card.tsx
1406
- import styled11 from "styled-components";
1535
+ import styled12 from "styled-components";
1407
1536
  var STRIP_WIDTH = "3px";
1408
- var Card__Root = styled11(Block__Root)`
1537
+ var Card__Root = styled12(Block__Root)`
1409
1538
  --gap-related: var(--gap-related-compact);
1410
1539
  --gap-section: var(--gap-section-compact);
1411
1540
  --bleed-inline: 0px;
@@ -1458,7 +1587,7 @@ var Card = Object.assign(CardRoot, BLOCK_PARTS);
1458
1587
  // src/CommandButton/CommandButton.tsx
1459
1588
  import { classifyCommandRejection } from "@ksp-gonogo/sitrep-sdk";
1460
1589
  import { useCallback as useCallback3, useEffect as useEffect3, useRef as useRef4, useState as useState4 } from "react";
1461
- import styled15, { css as css3, keyframes as keyframes3 } from "styled-components";
1590
+ import styled16, { css as css3, keyframes as keyframes3 } from "styled-components";
1462
1591
 
1463
1592
  // src/CommandDelay/commandOutcomes.ts
1464
1593
  function commandOutcomes(handle) {
@@ -1481,10 +1610,10 @@ import {
1481
1610
  useRef as useRef3,
1482
1611
  useState as useState3
1483
1612
  } from "react";
1484
- import styled12 from "styled-components";
1485
- import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
1613
+ import styled13 from "styled-components";
1614
+ import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
1486
1615
  var FitLabelButton = forwardRef2(function FitLabelButton2({ label, icon, type, ...rest }, ref) {
1487
- return /* @__PURE__ */ jsx13("button", { ref, type: type ?? "button", "aria-label": label, ...rest, children: /* @__PURE__ */ jsx13(FitLabel, { label, icon }) });
1616
+ return /* @__PURE__ */ jsx14("button", { ref, type: type ?? "button", "aria-label": label, ...rest, children: /* @__PURE__ */ jsx14(FitLabel, { label, icon }) });
1488
1617
  });
1489
1618
  function FitLabel({ label, icon }) {
1490
1619
  const contentRef = useRef3(null);
@@ -1504,12 +1633,12 @@ function FitLabel({ label, icon }) {
1504
1633
  observer.observe(ghost);
1505
1634
  return () => observer.disconnect();
1506
1635
  }, []);
1507
- return /* @__PURE__ */ jsxs11(FitLabelButton__Content, { ref: contentRef, children: [
1508
- /* @__PURE__ */ jsx13(FitLabelButton__Ghost, { ref: ghostRef, "aria-hidden": "true", children: label }),
1509
- fits ? /* @__PURE__ */ jsx13(FitLabelButton__Label, { "aria-hidden": "true", children: label }) : /* @__PURE__ */ jsx13(FitLabelButton__Icon, { "aria-hidden": "true", "data-fit-label-icon": "", children: icon })
1636
+ return /* @__PURE__ */ jsxs12(FitLabelButton__Content, { ref: contentRef, children: [
1637
+ /* @__PURE__ */ jsx14(FitLabelButton__Ghost, { ref: ghostRef, "aria-hidden": "true", children: label }),
1638
+ fits ? /* @__PURE__ */ jsx14(FitLabelButton__Label, { "aria-hidden": "true", children: label }) : /* @__PURE__ */ jsx14(FitLabelButton__Icon, { "aria-hidden": "true", "data-fit-label-icon": "", children: icon })
1510
1639
  ] });
1511
1640
  }
1512
- var FitLabelButton__Content = styled12.span`
1641
+ var FitLabelButton__Content = styled13.span`
1513
1642
  position: relative;
1514
1643
  display: flex;
1515
1644
  align-items: center;
@@ -1518,7 +1647,7 @@ var FitLabelButton__Content = styled12.span`
1518
1647
  min-width: 0;
1519
1648
  width: 100%;
1520
1649
  `;
1521
- var FitLabelButton__Ghost = styled12.span`
1650
+ var FitLabelButton__Ghost = styled13.span`
1522
1651
  position: absolute;
1523
1652
  left: 0;
1524
1653
  top: 0;
@@ -1526,30 +1655,30 @@ var FitLabelButton__Ghost = styled12.span`
1526
1655
  pointer-events: none;
1527
1656
  white-space: nowrap;
1528
1657
  `;
1529
- var FitLabelButton__Label = styled12.span`
1658
+ var FitLabelButton__Label = styled13.span`
1530
1659
  /* nowrap, so a label that does not fit overflows and the measurement stays honest. */
1531
1660
  white-space: nowrap;
1532
1661
  `;
1533
- var FitLabelButton__Icon = styled12.span`
1662
+ var FitLabelButton__Icon = styled13.span`
1534
1663
  display: inline-flex;
1535
1664
  align-items: center;
1536
1665
  justify-content: center;
1537
1666
  `;
1538
1667
 
1539
1668
  // src/CommandButton/InFlightFace.tsx
1540
- import styled14 from "styled-components";
1669
+ import styled15 from "styled-components";
1541
1670
 
1542
1671
  // src/Spinner.tsx
1543
- import styled13, { keyframes as keyframes2 } from "styled-components";
1544
- import { jsx as jsx14 } from "react/jsx-runtime";
1672
+ import styled14, { keyframes as keyframes2 } from "styled-components";
1673
+ import { jsx as jsx15 } from "react/jsx-runtime";
1545
1674
  function Spinner({
1546
1675
  size = 12,
1547
1676
  thickness = 2,
1548
1677
  color = "var(--color-accent-fg)",
1549
- ariaLabel = "Loading",
1678
+ "aria-label": ariaLabel = "Loading",
1550
1679
  ...rest
1551
1680
  }) {
1552
- return /* @__PURE__ */ jsx14(
1681
+ return /* @__PURE__ */ jsx15(
1553
1682
  SpinnerEl,
1554
1683
  {
1555
1684
  ...rest,
@@ -1564,7 +1693,7 @@ function Spinner({
1564
1693
  var spin = keyframes2`
1565
1694
  to { transform: rotate(360deg); }
1566
1695
  `;
1567
- var SpinnerEl = styled13.span`
1696
+ var SpinnerEl = styled14.span`
1568
1697
  display: inline-block;
1569
1698
  width: ${({ $size }) => `${$size}px`};
1570
1699
  height: ${({ $size }) => `${$size}px`};
@@ -1580,34 +1709,34 @@ var SpinnerEl = styled13.span`
1580
1709
  `;
1581
1710
 
1582
1711
  // src/CommandButton/InFlightFace.tsx
1583
- import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
1712
+ import { jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
1584
1713
  function InFlightFace({
1585
1714
  holds,
1586
1715
  label,
1587
1716
  spinnerSize = 12
1588
1717
  }) {
1589
- return /* @__PURE__ */ jsxs12(InFlightFace__Root, { children: [
1590
- /* @__PURE__ */ jsx15(InFlightFace__Hold, { "aria-hidden": "true", children: holds }),
1591
- /* @__PURE__ */ jsx15(InFlightFace__Spinner, { children: /* @__PURE__ */ jsx15(Spinner, { size: spinnerSize, ariaLabel: label }) })
1718
+ return /* @__PURE__ */ jsxs13(InFlightFace__Root, { children: [
1719
+ /* @__PURE__ */ jsx16(InFlightFace__Hold, { "aria-hidden": "true", children: holds }),
1720
+ /* @__PURE__ */ jsx16(InFlightFace__Spinner, { children: /* @__PURE__ */ jsx16(Spinner, { size: spinnerSize, "aria-label": label }) })
1592
1721
  ] });
1593
1722
  }
1594
- var InFlightFace__Root = styled14.span`
1723
+ var InFlightFace__Root = styled15.span`
1595
1724
  display: inline-grid;
1596
1725
  & > * {
1597
1726
  grid-area: 1 / 1;
1598
1727
  }
1599
1728
  `;
1600
- var InFlightFace__Hold = styled14.span`
1729
+ var InFlightFace__Hold = styled15.span`
1601
1730
  visibility: hidden;
1602
1731
  `;
1603
- var InFlightFace__Spinner = styled14.span`
1732
+ var InFlightFace__Spinner = styled15.span`
1604
1733
  display: flex;
1605
1734
  align-items: center;
1606
1735
  justify-content: center;
1607
1736
  `;
1608
1737
 
1609
1738
  // src/CommandButton/CommandButton.tsx
1610
- import { Fragment as Fragment4, jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
1739
+ import { Fragment as Fragment4, jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
1611
1740
  var ARM_TIMEOUT_MS = 4e3;
1612
1741
  var REFUSAL_TIMEOUT_MS = 8e3;
1613
1742
  var PENDING_BACKSTOP_MS = 3e4;
@@ -1811,7 +1940,7 @@ function CommandButton({
1811
1940
  }, [onPressReady, isPending, press]);
1812
1941
  const resolveBody = () => {
1813
1942
  if (isPending)
1814
- return /* @__PURE__ */ jsx16(
1943
+ return /* @__PURE__ */ jsx17(
1815
1944
  InFlightFace,
1816
1945
  {
1817
1946
  holds: label,
@@ -1828,7 +1957,7 @@ function CommandButton({
1828
1957
  };
1829
1958
  const resolved = resolveBody();
1830
1959
  const fitWord = icon !== void 0 && typeof resolved === "string";
1831
- const body = fitWord ? /* @__PURE__ */ jsx16(FitLabel, { label: resolved, icon: isArmed ? confirmIcon ?? icon : icon }) : resolved;
1960
+ const body = fitWord ? /* @__PURE__ */ jsx17(FitLabel, { label: resolved, icon: isArmed ? confirmIcon ?? icon : icon }) : resolved;
1832
1961
  const reserve = icon === void 0 && typeof label === "string" && typeof confirmLabel === "string" && !isRefused && !isLost && !isFound && !isShowingReason;
1833
1962
  const outcome = isRefused ? refusalText : isLost ? lossText : isFound ? foundText : null;
1834
1963
  const filled = active === true || isArmed || isRefused;
@@ -1841,12 +1970,12 @@ function CommandButton({
1841
1970
  confirmTone,
1842
1971
  tone
1843
1972
  });
1844
- return /* @__PURE__ */ jsxs13(Fragment4, { children: [
1845
- /* @__PURE__ */ jsx16(
1973
+ return /* @__PURE__ */ jsxs14(Fragment4, { children: [
1974
+ /* @__PURE__ */ jsx17(
1846
1975
  Tooltip,
1847
1976
  {
1848
1977
  text: foundText ?? refusalText ?? (isPending ? pendingLabel : title),
1849
- children: /* @__PURE__ */ jsx16(
1978
+ children: /* @__PURE__ */ jsx17(
1850
1979
  CommandButton__Body,
1851
1980
  {
1852
1981
  type: "button",
@@ -1870,12 +1999,12 @@ function CommandButton({
1870
1999
  "data-rest-label": reserve ? label : void 0,
1871
2000
  "data-armed-label": reserve ? confirmLabel : void 0,
1872
2001
  ...rest,
1873
- children: reserve ? /* @__PURE__ */ jsx16(CommandButton__Face, { children: body }) : body
2002
+ children: reserve ? /* @__PURE__ */ jsx17(CommandButton__Face, { children: body }) : body
1874
2003
  }
1875
2004
  )
1876
2005
  }
1877
2006
  ),
1878
- /* @__PURE__ */ jsx16(LiveRegion, { visuallyHidden: true, children: outcome })
2007
+ /* @__PURE__ */ jsx17(LiveRegion, { visuallyHidden: true, children: outcome })
1879
2008
  ] });
1880
2009
  }
1881
2010
  function commandTone(p) {
@@ -1889,7 +2018,7 @@ var armedPulse = keyframes3`
1889
2018
  0%, 100% { opacity: 1; }
1890
2019
  50% { opacity: 0.65; }
1891
2020
  `;
1892
- var CommandButton__Face = styled15.span`
2021
+ var CommandButton__Face = styled16.span`
1893
2022
  grid-area: 1 / 1;
1894
2023
  /* First in the cell's order, so the button's baseline is the face's and not an invisible sizer's. */
1895
2024
  order: -1;
@@ -1898,7 +2027,7 @@ var CommandButton__Face = styled15.span`
1898
2027
  justify-content: center;
1899
2028
  gap: var(--gap-glyph);
1900
2029
  `;
1901
- var CommandButton__Body = styled15(Button__Body)`
2030
+ var CommandButton__Body = styled16(Button__Body)`
1902
2031
  letter-spacing: 0.04em;
1903
2032
 
1904
2033
  /* Shrinks below its word so the word can be measured and give way to the icon. */
@@ -1957,10 +2086,10 @@ var CommandButton__Body = styled15(Button__Body)`
1957
2086
 
1958
2087
  // src/CommandDelay/CommandGroup.tsx
1959
2088
  import { useEffect as useEffect4, useId as useId3 } from "react";
1960
- import styled16, { css as css4 } from "styled-components";
1961
- import { jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
2089
+ import styled17, { css as css4 } from "styled-components";
2090
+ import { jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
1962
2091
  function CommandGroup({
1963
- value: value4,
2092
+ value: value5,
1964
2093
  onCommit,
1965
2094
  gated = false,
1966
2095
  children,
@@ -1979,10 +2108,10 @@ function CommandGroup({
1979
2108
  );
1980
2109
  }, [named, commitAriaLabel]);
1981
2110
  const reasonId = useId3();
1982
- return /* @__PURE__ */ jsxs14(CommandGroup__Root, { "data-gated": gated, $orientation: orientation, children: [
1983
- /* @__PURE__ */ jsx17(CommandGroup__Inputs, { $wrap: wrap, children }),
1984
- gated && /* @__PURE__ */ jsx17(VisuallyHidden, { id: reasonId, children: gatedReason }),
1985
- /* @__PURE__ */ jsx17(Tooltip, { text: gated ? gatedReason : void 0, announce: false, children: /* @__PURE__ */ jsx17(
2111
+ return /* @__PURE__ */ jsxs15(CommandGroup__Root, { "data-gated": gated, $orientation: orientation, children: [
2112
+ /* @__PURE__ */ jsx18(CommandGroup__Inputs, { $wrap: wrap, children }),
2113
+ gated && /* @__PURE__ */ jsx18(VisuallyHidden, { id: reasonId, children: gatedReason }),
2114
+ /* @__PURE__ */ jsx18(Tooltip, { text: gated ? gatedReason : void 0, announce: false, children: /* @__PURE__ */ jsx18(
1986
2115
  CommandGroup__CommitButton,
1987
2116
  {
1988
2117
  type: "button",
@@ -1994,26 +2123,26 @@ function CommandGroup({
1994
2123
  "aria-label": commitAriaLabel,
1995
2124
  onClick: () => {
1996
2125
  if (gated) return;
1997
- onCommit(value4);
2126
+ onCommit(value5);
1998
2127
  },
1999
2128
  children: commitLabel
2000
2129
  }
2001
2130
  ) })
2002
2131
  ] });
2003
2132
  }
2004
- var CommandGroup__Root = styled16.div`
2133
+ var CommandGroup__Root = styled17.div`
2005
2134
  display: flex;
2006
2135
  flex-direction: ${({ $orientation }) => $orientation};
2007
2136
  ${({ $orientation }) => $orientation === "row" && "align-items: center;"}
2008
2137
  gap: var(--gap-control-row);
2009
2138
  `;
2010
- var CommandGroup__Inputs = styled16.div`
2139
+ var CommandGroup__Inputs = styled17.div`
2011
2140
  display: flex;
2012
2141
  flex-wrap: ${({ $wrap }) => $wrap ? "wrap" : "nowrap"};
2013
2142
  gap: var(--gap-control-row);
2014
2143
  align-items: center;
2015
2144
  `;
2016
- var CommandGroup__CommitButton = styled16.button`
2145
+ var CommandGroup__CommitButton = styled17.button`
2017
2146
  align-self: ${({ $orientation }) => $orientation === "row" ? "center" : "flex-start"};
2018
2147
  /* A commit control must not be squeezed to nothing by the inputs beside it. */
2019
2148
  ${({ $orientation }) => $orientation === "row" && "flex-shrink: 0;"}
@@ -2051,8 +2180,8 @@ var CommandGroup__CommitButton = styled16.button`
2051
2180
 
2052
2181
  // src/CommandDelay/SignalDelayBadge.tsx
2053
2182
  import { value } from "@ksp-gonogo/sitrep-sdk";
2054
- import styled17 from "styled-components";
2055
- import { jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
2183
+ import styled18 from "styled-components";
2184
+ import { jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
2056
2185
  function SignalDelayBadge({
2057
2186
  oneWaySeconds,
2058
2187
  delayReading,
@@ -2061,7 +2190,7 @@ function SignalDelayBadge({
2061
2190
  const oneWay = value("s", oneWaySeconds);
2062
2191
  return (
2063
2192
  // Not a live region: the delay changes with every sample.
2064
- /* @__PURE__ */ jsxs15(
2193
+ /* @__PURE__ */ jsxs16(
2065
2194
  SignalDelayBadge__Chip,
2066
2195
  {
2067
2196
  className,
@@ -2069,7 +2198,7 @@ function SignalDelayBadge({
2069
2198
  "aria-label": "Signal delay",
2070
2199
  children: [
2071
2200
  "one-way ~",
2072
- /* @__PURE__ */ jsx18(
2201
+ /* @__PURE__ */ jsx19(
2073
2202
  Unit,
2074
2203
  {
2075
2204
  value: withDelayCurrency(oneWay, delayReading),
@@ -2081,7 +2210,7 @@ function SignalDelayBadge({
2081
2210
  )
2082
2211
  );
2083
2212
  }
2084
- var SignalDelayBadge__Chip = styled17.div`
2213
+ var SignalDelayBadge__Chip = styled18.div`
2085
2214
  /* Non-growing: it shares the console's corner row, and its text is short by construction. */
2086
2215
  flex: 0 0 auto;
2087
2216
  padding: var(--inset-chip-readout);
@@ -2112,8 +2241,8 @@ function useRailEntry(entry) {
2112
2241
 
2113
2242
  // src/ComposerBar.tsx
2114
2243
  import { useId as useId5 } from "react";
2115
- import styled18, { css as css5 } from "styled-components";
2116
- import { jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
2244
+ import styled19, { css as css5 } from "styled-components";
2245
+ import { jsx as jsx20, jsxs as jsxs17 } from "react/jsx-runtime";
2117
2246
  function ComposerBar({
2118
2247
  blocked = false,
2119
2248
  flag,
@@ -2128,12 +2257,12 @@ function ComposerBar({
2128
2257
  }) {
2129
2258
  const { anchor, tip } = useTooltip(sendTooltip);
2130
2259
  const described = useId5();
2131
- return /* @__PURE__ */ jsxs16(ComposerBar__Row, { $blocked: blocked, ...rest, children: [
2132
- prompt !== void 0 && /* @__PURE__ */ jsx19(ComposerBar__Prompt, { "aria-hidden": "true", children: prompt }),
2260
+ return /* @__PURE__ */ jsxs17(ComposerBar__Row, { $blocked: blocked, ...rest, children: [
2261
+ prompt !== void 0 && /* @__PURE__ */ jsx20(ComposerBar__Prompt, { "aria-hidden": "true", children: prompt }),
2133
2262
  children,
2134
2263
  onSend !== void 0 && /* The anchor is the wrapper, not the button: a disabled button raises no pointer events. */
2135
- /* @__PURE__ */ jsxs16(ComposerBar__SendAnchor, { ...anchor, children: [
2136
- /* @__PURE__ */ jsx19(
2264
+ /* @__PURE__ */ jsxs17(ComposerBar__SendAnchor, { ...anchor, children: [
2265
+ /* @__PURE__ */ jsx20(
2137
2266
  ComposerBar__Send,
2138
2267
  {
2139
2268
  type: "button",
@@ -2142,17 +2271,17 @@ function ComposerBar({
2142
2271
  $icon: sendVariant === "icon",
2143
2272
  ...sendTooltip ? { "aria-describedby": described } : {},
2144
2273
  ...sendVariant === "icon" ? { "aria-label": sendLabel } : {},
2145
- children: sendVariant === "icon" ? /* @__PURE__ */ jsx19(SendIcon, { size: 16 }) : sendLabel
2274
+ children: sendVariant === "icon" ? /* @__PURE__ */ jsx20(SendIcon, { size: 16 }) : sendLabel
2146
2275
  }
2147
2276
  ),
2148
- sendTooltip && /* @__PURE__ */ jsx19(VisuallyHidden, { id: described, children: sendTooltip.replace("\n", ". ") }),
2277
+ sendTooltip && /* @__PURE__ */ jsx20(VisuallyHidden, { id: described, children: sendTooltip.replace("\n", ". ") }),
2149
2278
  tip
2150
2279
  ] }),
2151
2280
  flag !== void 0 && // `role="status"`, never `alert`: a lost path is ambient, not an interruption.
2152
- /* @__PURE__ */ jsx19(ComposerBar__Flag, { $blocked: blocked, role: "status", children: flag })
2281
+ /* @__PURE__ */ jsx20(ComposerBar__Flag, { $blocked: blocked, role: "status", children: flag })
2153
2282
  ] });
2154
2283
  }
2155
- var ComposerBar__Row = styled18.div`
2284
+ var ComposerBar__Row = styled19.div`
2156
2285
  position: relative;
2157
2286
  flex: 0 0 auto;
2158
2287
  display: flex;
@@ -2164,13 +2293,13 @@ var ComposerBar__Row = styled18.div`
2164
2293
  ${({ $blocked }) => $blocked ? "var(--color-nogo-text)" : "var(--console-tone-fg, var(--color-accent-fg))"};
2165
2294
  border-radius: var(--radius-regular);
2166
2295
  `;
2167
- var ComposerBar__Prompt = styled18.span`
2296
+ var ComposerBar__Prompt = styled19.span`
2168
2297
  flex: 0 0 auto;
2169
2298
  color: var(--console-tone-fg, var(--color-accent-fg));
2170
2299
  font-weight: bold;
2171
2300
  margin-right: var(--gap-prompt-glyph);
2172
2301
  `;
2173
- var ComposerBar__SendAnchor = styled18.span`
2302
+ var ComposerBar__SendAnchor = styled19.span`
2174
2303
  display: inline-flex;
2175
2304
 
2176
2305
  /* A disabled button swallows pointer events, so they go to the anchor instead. */
@@ -2178,7 +2307,7 @@ var ComposerBar__SendAnchor = styled18.span`
2178
2307
  pointer-events: none;
2179
2308
  }
2180
2309
  `;
2181
- var ComposerBar__Send = styled18(Button)`
2310
+ var ComposerBar__Send = styled19(Button)`
2182
2311
  flex: 0 0 auto;
2183
2312
  margin-left: auto;
2184
2313
  font-size: var(--font-size-compact);
@@ -2197,7 +2326,7 @@ var ComposerBar__Send = styled18(Button)`
2197
2326
  }
2198
2327
  `}
2199
2328
  `;
2200
- var ComposerBar__Flag = styled18.div`
2329
+ var ComposerBar__Flag = styled19.div`
2201
2330
  position: absolute;
2202
2331
  /* Straddles the top border by half its own height, which tracks the font size. */
2203
2332
  top: 0;
@@ -2227,8 +2356,8 @@ var ComposerBar__Flag = styled18.div`
2227
2356
  `;
2228
2357
 
2229
2358
  // src/ConsoleFrame.tsx
2230
- import styled19, { css as css6 } from "styled-components";
2231
- import { jsx as jsx20, jsxs as jsxs17 } from "react/jsx-runtime";
2359
+ import styled20, { css as css6 } from "styled-components";
2360
+ import { jsx as jsx21, jsxs as jsxs18 } from "react/jsx-runtime";
2232
2361
  function ConsoleFrame({
2233
2362
  tone = "accent",
2234
2363
  queue,
@@ -2241,16 +2370,16 @@ function ConsoleFrame({
2241
2370
  const straddles = standing !== void 0 && Boolean(composer);
2242
2371
  return (
2243
2372
  // A stable structural hook, since containment is invisible to a role query.
2244
- /* @__PURE__ */ jsxs17(ConsoleFrame__Box, { "data-console-frame": "", $tone: tone, ...rest, children: [
2245
- /* @__PURE__ */ jsx20(ConsoleFrame__Surface, { children }),
2246
- hasFoot && /* @__PURE__ */ jsxs17(ConsoleFrame__Foot, { $straddled: straddles, children: [
2373
+ /* @__PURE__ */ jsxs18(ConsoleFrame__Box, { "data-console-frame": "", $tone: tone, ...rest, children: [
2374
+ /* @__PURE__ */ jsx21(ConsoleFrame__Surface, { children }),
2375
+ hasFoot && /* @__PURE__ */ jsxs18(ConsoleFrame__Foot, { $straddled: straddles, children: [
2247
2376
  queue,
2248
2377
  standing !== void 0 && /*
2249
2378
  A structural hook for the same reason. BEFORE the composer, so
2250
2379
  in the in-flow case the reading is announced before the control
2251
2380
  it sits above.
2252
2381
  */
2253
- /* @__PURE__ */ jsx20(
2382
+ /* @__PURE__ */ jsx21(
2254
2383
  ConsoleFrame__Standing,
2255
2384
  {
2256
2385
  "data-console-standing": "",
@@ -2263,7 +2392,7 @@ function ConsoleFrame({
2263
2392
  ] })
2264
2393
  );
2265
2394
  }
2266
- var ConsoleFrame__Box = styled19.div`
2395
+ var ConsoleFrame__Box = styled20.div`
2267
2396
  flex: 1 1 auto;
2268
2397
  min-height: 0;
2269
2398
  min-width: 0;
@@ -2281,14 +2410,14 @@ var ConsoleFrame__Box = styled19.div`
2281
2410
  --console-tone-fg: var(--color-accent-fg);
2282
2411
  `}
2283
2412
  `;
2284
- var ConsoleFrame__Surface = styled19.div`
2413
+ var ConsoleFrame__Surface = styled20.div`
2285
2414
  position: relative;
2286
2415
  flex: 1 1 auto;
2287
2416
  min-height: 0;
2288
2417
  min-width: 0;
2289
2418
  display: flex;
2290
2419
  `;
2291
- var ConsoleFrame__Standing = styled19.div`
2420
+ var ConsoleFrame__Standing = styled20.div`
2292
2421
  flex: 0 0 auto;
2293
2422
  display: flex;
2294
2423
  align-items: center;
@@ -2309,7 +2438,7 @@ var ConsoleFrame__Standing = styled19.div`
2309
2438
  `
2310
2439
  )}
2311
2440
  `;
2312
- var ConsoleFrame__Foot = styled19.div`
2441
+ var ConsoleFrame__Foot = styled20.div`
2313
2442
  position: relative;
2314
2443
  flex: 0 0 auto;
2315
2444
  min-width: 0;
@@ -2324,7 +2453,7 @@ var ConsoleFrame__Foot = styled19.div`
2324
2453
  `;
2325
2454
 
2326
2455
  // src/Console.tsx
2327
- import { jsx as jsx21 } from "react/jsx-runtime";
2456
+ import { jsx as jsx22 } from "react/jsx-runtime";
2328
2457
  var QUEUE_LABEL = "Uplink queue";
2329
2458
  function Console({
2330
2459
  tone,
@@ -2347,12 +2476,12 @@ function Console({
2347
2476
  const showStrip = inFlight !== void 0 && (presentation === "strip" || inFlightFrozenAtDispatch && presentation !== "badge");
2348
2477
  return (
2349
2478
  // Two slots rather than one `footer`, so the frame knows whether there is a composer to place the reading against.
2350
- /* @__PURE__ */ jsx21(
2479
+ /* @__PURE__ */ jsx22(
2351
2480
  ConsoleFrame,
2352
2481
  {
2353
2482
  ...tone !== void 0 ? { tone } : {},
2354
2483
  ...badgeSeconds !== null ? {
2355
- standing: /* @__PURE__ */ jsx21(
2484
+ standing: /* @__PURE__ */ jsx22(
2356
2485
  SignalDelayBadge,
2357
2486
  {
2358
2487
  oneWaySeconds: badgeSeconds,
@@ -2360,7 +2489,7 @@ function Console({
2360
2489
  }
2361
2490
  )
2362
2491
  } : {},
2363
- ...showStrip ? { queue: /* @__PURE__ */ jsx21(InFlightList, { items: inFlight, ariaLabel: QUEUE_LABEL }) } : {},
2492
+ ...showStrip ? { queue: /* @__PURE__ */ jsx22(InFlightList, { items: inFlight, "aria-label": QUEUE_LABEL }) } : {},
2364
2493
  ...composer !== void 0 ? { composer } : {},
2365
2494
  ...rest,
2366
2495
  children
@@ -2370,8 +2499,8 @@ function Console({
2370
2499
  }
2371
2500
 
2372
2501
  // src/ContainerBreak.tsx
2373
- import styled20 from "styled-components";
2374
- import { jsx as jsx22 } from "react/jsx-runtime";
2502
+ import styled21 from "styled-components";
2503
+ import { jsx as jsx23 } from "react/jsx-runtime";
2375
2504
  function ContainerBreak({
2376
2505
  at,
2377
2506
  narrow,
@@ -2379,9 +2508,9 @@ function ContainerBreak({
2379
2508
  children,
2380
2509
  ...rest
2381
2510
  }) {
2382
- return /* @__PURE__ */ jsx22(ContainerBreak__Root, { $at: at, $narrow: narrow, $wide: wide, ...rest, children });
2511
+ return /* @__PURE__ */ jsx23(ContainerBreak__Root, { $at: at, $narrow: narrow, $wide: wide, ...rest, children });
2383
2512
  }
2384
- var ContainerBreak__Root = styled20.div`
2513
+ var ContainerBreak__Root = styled21.div`
2385
2514
  ${({ $narrow }) => $narrow}
2386
2515
  @container (min-width: ${({ $at }) => $at}px) {
2387
2516
  ${({ $wide }) => $wide}
@@ -2442,12 +2571,12 @@ import {
2442
2571
  useRef as useRef5,
2443
2572
  useState as useState5
2444
2573
  } from "react";
2445
- import styled21 from "styled-components";
2446
- import { Fragment as Fragment5, jsx as jsx23, jsxs as jsxs18 } from "react/jsx-runtime";
2574
+ import styled22 from "styled-components";
2575
+ import { Fragment as Fragment5, jsx as jsx24, jsxs as jsxs19 } from "react/jsx-runtime";
2447
2576
  var RETIRED_MESSAGE = "is no longer available";
2448
2577
  function DataKeyPicker({
2449
2578
  keys,
2450
- value: value4,
2579
+ value: value5,
2451
2580
  onChange,
2452
2581
  clearable = false,
2453
2582
  placeholder = "Search...",
@@ -2464,8 +2593,8 @@ function DataKeyPicker({
2464
2593
  const optionIdPrefix = useId6();
2465
2594
  const retiredId = useId6();
2466
2595
  const optionId = (key) => `${optionIdPrefix}-${key}`;
2467
- const selectedOption = keys.find((k) => k.key === value4);
2468
- const retired = value4 !== null && value4 !== "" && selectedOption === void 0 && keys.length > 0;
2596
+ const selectedOption = keys.find((k) => k.key === value5);
2597
+ const retired = value5 !== null && value5 !== "" && selectedOption === void 0 && keys.length > 0;
2469
2598
  const filtered = useMemo(
2470
2599
  () => filterComboboxOptions(keys, query),
2471
2600
  [keys, query]
@@ -2531,18 +2660,18 @@ function DataKeyPicker({
2531
2660
  document.addEventListener("pointerdown", onOutside);
2532
2661
  return () => document.removeEventListener("pointerdown", onOutside);
2533
2662
  }, [open, closePicker]);
2534
- const displayValue = open ? query : selectedOption?.label ?? value4 ?? "";
2663
+ const displayValue = open ? query : selectedOption?.label ?? value5 ?? "";
2535
2664
  const activeOption = open && activeIndex >= 0 ? flatOptions[activeIndex] : void 0;
2536
- return /* @__PURE__ */ jsxs18(Container, { ref: containerRef, children: [
2537
- /* @__PURE__ */ jsx23(
2665
+ return /* @__PURE__ */ jsxs19(Container, { ref: containerRef, children: [
2666
+ /* @__PURE__ */ jsx24(
2538
2667
  PickerInput,
2539
2668
  {
2540
2669
  ref: inputRef,
2541
2670
  id,
2542
2671
  "aria-label": ariaLabel,
2543
2672
  value: displayValue,
2544
- placeholder: value4 ? void 0 : placeholder,
2545
- $hasValue: !!value4 && !open,
2673
+ placeholder: value5 ? void 0 : placeholder,
2674
+ $hasValue: !!value5 && !open,
2546
2675
  $retired: retired && !open,
2547
2676
  "aria-invalid": retired && !open ? true : void 0,
2548
2677
  "aria-describedby": retired && !open ? retiredId : void 0,
@@ -2560,8 +2689,8 @@ function DataKeyPicker({
2560
2689
  "aria-activedescendant": activeOption ? optionId(activeOption.key) : void 0
2561
2690
  }
2562
2691
  ),
2563
- retired && !open && /* @__PURE__ */ jsx23(RetiredNote, { id: retiredId, children: `This ${subjectNoun} ${RETIRED_MESSAGE}. Pick another.` }),
2564
- clearable && value4 && !open && /* @__PURE__ */ jsx23(
2692
+ retired && !open && /* @__PURE__ */ jsx24(RetiredNote, { id: retiredId, children: `This ${subjectNoun} ${RETIRED_MESSAGE}. Pick another.` }),
2693
+ clearable && value5 && !open && /* @__PURE__ */ jsx24(
2565
2694
  ClearButton,
2566
2695
  {
2567
2696
  type: "button",
@@ -2573,30 +2702,30 @@ function DataKeyPicker({
2573
2702
  children: "\xD7"
2574
2703
  }
2575
2704
  ),
2576
- open && /* @__PURE__ */ jsx23(
2705
+ open && /* @__PURE__ */ jsx24(
2577
2706
  ComboboxListbox,
2578
2707
  {
2579
2708
  id: listboxId,
2580
2709
  groups: sortedGroups,
2581
2710
  flatOptions,
2582
2711
  activeIndex,
2583
- selectedKey: value4,
2712
+ selectedKey: value5,
2584
2713
  getOptionId: optionId,
2585
2714
  onHoverIndex: setActiveIndex,
2586
2715
  onSelectKey: selectOption,
2587
- ariaLabel: ariaLabel ?? "Data keys",
2588
- renderItem: (opt) => /* @__PURE__ */ jsxs18(Fragment5, { children: [
2589
- /* @__PURE__ */ jsx23(ItemLabel, { children: opt.label ?? opt.key }),
2590
- opt.unit && /* @__PURE__ */ jsx23(ItemUnit, { children: opt.unit })
2716
+ "aria-label": ariaLabel ?? "Data keys",
2717
+ renderItem: (opt) => /* @__PURE__ */ jsxs19(Fragment5, { children: [
2718
+ /* @__PURE__ */ jsx24(ItemLabel, { children: opt.label ?? opt.key }),
2719
+ opt.unit && /* @__PURE__ */ jsx24(ItemUnit, { children: opt.unit })
2591
2720
  ] })
2592
2721
  }
2593
2722
  )
2594
2723
  ] });
2595
2724
  }
2596
- var Container = styled21.div`
2725
+ var Container = styled22.div`
2597
2726
  position: relative;
2598
2727
  `;
2599
- var PickerInput = styled21.input`
2728
+ var PickerInput = styled22.input`
2600
2729
  background: var(--color-surface-raised);
2601
2730
  border: 1px solid ${({ $retired }) => $retired ? "var(--color-nogo-text)" : "var(--color-border-strong)"};
2602
2731
  border-radius: var(--radius-regular);
@@ -2619,7 +2748,7 @@ var PickerInput = styled21.input`
2619
2748
  color: var(--color-text-faint);
2620
2749
  }
2621
2750
  `;
2622
- var ClearButton = styled21.button`
2751
+ var ClearButton = styled22.button`
2623
2752
  position: absolute;
2624
2753
  right: 6px;
2625
2754
  top: 50%;
@@ -2638,24 +2767,24 @@ var ClearButton = styled21.button`
2638
2767
 
2639
2768
  ${focusRing}
2640
2769
  `;
2641
- var RetiredNote = styled21.div`
2770
+ var RetiredNote = styled22.div`
2642
2771
  color: var(--color-nogo-text);
2643
2772
  font-size: var(--font-size-compact);
2644
2773
  margin-top: var(--gap-caption);
2645
2774
  `;
2646
- var ItemLabel = styled21.span`
2775
+ var ItemLabel = styled22.span`
2647
2776
  font-size: var(--font-size-compact);
2648
2777
  color: var(--color-text-primary);
2649
2778
  `;
2650
- var ItemUnit = styled21.span`
2779
+ var ItemUnit = styled22.span`
2651
2780
  font-size: var(--font-size-compact);
2652
2781
  color: var(--color-text-muted);
2653
2782
  margin-left: var(--gap-trailing-mark);
2654
2783
  `;
2655
2784
 
2656
2785
  // src/DataLine.tsx
2657
- import styled22, { css as css7 } from "styled-components";
2658
- import { jsx as jsx24, jsxs as jsxs19 } from "react/jsx-runtime";
2786
+ import styled23, { css as css7 } from "styled-components";
2787
+ import { jsx as jsx25, jsxs as jsxs20 } from "react/jsx-runtime";
2659
2788
  function DataLine({
2660
2789
  label,
2661
2790
  lead,
@@ -2664,16 +2793,16 @@ function DataLine({
2664
2793
  aligned = false,
2665
2794
  ...rest
2666
2795
  }) {
2667
- return /* @__PURE__ */ jsxs19(DataLine__Root, { $aligned: aligned, ...rest, children: [
2668
- /* @__PURE__ */ jsx24(DataLine__Label, { children: label }),
2669
- /* @__PURE__ */ jsxs19(DataLine__Value, { $tone: tone, children: [
2796
+ return /* @__PURE__ */ jsxs20(DataLine__Root, { $aligned: aligned, ...rest, children: [
2797
+ /* @__PURE__ */ jsx25(DataLine__Label, { children: label }),
2798
+ /* @__PURE__ */ jsxs20(DataLine__Value, { $tone: tone, children: [
2670
2799
  lead,
2671
2800
  children
2672
2801
  ] })
2673
2802
  ] });
2674
2803
  }
2675
2804
  var LABEL_COLUMN = "7ch";
2676
- var DataLine__Root = styled22.div`
2805
+ var DataLine__Root = styled23.div`
2677
2806
  display: ${({ $aligned }) => $aligned ? "grid" : "flex"};
2678
2807
  align-items: baseline;
2679
2808
  gap: var(--gap-data-line);
@@ -2684,13 +2813,13 @@ var DataLine__Root = styled22.div`
2684
2813
  flex-wrap: wrap;
2685
2814
  `}
2686
2815
  `;
2687
- var DataLine__Label = styled22.span`
2816
+ var DataLine__Label = styled23.span`
2688
2817
  font-size: var(--font-size-caption);
2689
2818
  letter-spacing: 0.08em;
2690
2819
  text-transform: uppercase;
2691
2820
  color: var(--color-text-muted);
2692
2821
  `;
2693
- var DataLine__Value = styled22.span`
2822
+ var DataLine__Value = styled23.span`
2694
2823
  display: flex;
2695
2824
  flex-wrap: wrap;
2696
2825
  align-items: baseline;
@@ -2703,11 +2832,11 @@ var DataLine__Value = styled22.span`
2703
2832
 
2704
2833
  // src/DataTable.tsx
2705
2834
  import { Fragment as Fragment6, useState as useState7 } from "react";
2706
- import styled24 from "styled-components";
2835
+ import styled25 from "styled-components";
2707
2836
 
2708
2837
  // src/inlineOverflow.tsx
2709
2838
  import { useEffect as useEffect7, useRef as useRef6, useState as useState6 } from "react";
2710
- import styled23 from "styled-components";
2839
+ import styled24 from "styled-components";
2711
2840
  var NONE = { left: false, right: false };
2712
2841
  function useInlineOverflow(el) {
2713
2842
  const [overflow, setOverflow] = useState6(NONE);
@@ -2739,7 +2868,7 @@ function useInlineOverflow(el) {
2739
2868
  }, [el]);
2740
2869
  return overflow;
2741
2870
  }
2742
- var InlineOverflowGlow = styled23.div`
2871
+ var InlineOverflowGlow = styled24.div`
2743
2872
  position: absolute;
2744
2873
  top: 0;
2745
2874
  bottom: 0;
@@ -2760,9 +2889,9 @@ var InlineOverflowGlow = styled23.div`
2760
2889
  `;
2761
2890
 
2762
2891
  // src/DataTable.tsx
2763
- import { jsx as jsx25, jsxs as jsxs20 } from "react/jsx-runtime";
2892
+ import { jsx as jsx26, jsxs as jsxs21 } from "react/jsx-runtime";
2764
2893
  function cellContent(col, row) {
2765
- if (col.value !== void 0) return /* @__PURE__ */ jsx25(Unit, { value: col.value(row) ?? null });
2894
+ if (col.value !== void 0) return /* @__PURE__ */ jsx26(Unit, { value: col.value(row) ?? null });
2766
2895
  return col.render(row);
2767
2896
  }
2768
2897
  function DataTable({
@@ -2780,10 +2909,10 @@ function DataTable({
2780
2909
  const [scroller, setScroller] = useState7(null);
2781
2910
  const overflow = useInlineOverflow(scroller);
2782
2911
  const tabIndex = useKeyboardScrollable(scroller);
2783
- return /* @__PURE__ */ jsxs20(DataTable__Shell, { className, children: [
2784
- /* @__PURE__ */ jsx25(DataTable__Scroller, { ref: setScroller, tabIndex, children: /* @__PURE__ */ jsxs20(DataTable__Table, { children: [
2785
- /* @__PURE__ */ jsx25(DataTable__Caption, { children: caption }),
2786
- /* @__PURE__ */ jsx25("thead", { children: /* @__PURE__ */ jsx25("tr", { children: columns.map((col) => /* @__PURE__ */ jsx25(
2912
+ return /* @__PURE__ */ jsxs21(DataTable__Shell, { className, children: [
2913
+ /* @__PURE__ */ jsx26(DataTable__Scroller, { ref: setScroller, tabIndex, children: /* @__PURE__ */ jsxs21(DataTable__Table, { children: [
2914
+ /* @__PURE__ */ jsx26(DataTable__Caption, { children: caption }),
2915
+ /* @__PURE__ */ jsx26("thead", { children: /* @__PURE__ */ jsx26("tr", { children: columns.map((col) => /* @__PURE__ */ jsx26(
2787
2916
  DataTable__HeaderCell,
2788
2917
  {
2789
2918
  scope: "col",
@@ -2796,9 +2925,9 @@ function DataTable({
2796
2925
  },
2797
2926
  col.key
2798
2927
  )) }) }),
2799
- total === 0 && empty !== void 0 && /* @__PURE__ */ jsx25("tbody", { children: /* @__PURE__ */ jsx25("tr", { children: /* @__PURE__ */ jsx25(DataTable__EmptyCell, { colSpan: columns.length, children: empty }) }) }),
2800
- groups.map((group) => /* @__PURE__ */ jsxs20("tbody", { children: [
2801
- group.title !== null && group.title !== void 0 && /* @__PURE__ */ jsx25("tr", { children: /* @__PURE__ */ jsx25(
2928
+ total === 0 && empty !== void 0 && /* @__PURE__ */ jsx26("tbody", { children: /* @__PURE__ */ jsx26("tr", { children: /* @__PURE__ */ jsx26(DataTable__EmptyCell, { colSpan: columns.length, children: empty }) }) }),
2929
+ groups.map((group) => /* @__PURE__ */ jsxs21("tbody", { children: [
2930
+ group.title !== null && group.title !== void 0 && /* @__PURE__ */ jsx26("tr", { children: /* @__PURE__ */ jsx26(
2802
2931
  DataTable__SectionCell,
2803
2932
  {
2804
2933
  scope: "rowgroup",
@@ -2810,8 +2939,8 @@ function DataTable({
2810
2939
  const key = rowKey(row);
2811
2940
  const detail = rowDetail?.(row);
2812
2941
  const hasDetail = detail !== null && detail !== void 0 && detail !== false && detail !== "";
2813
- return /* @__PURE__ */ jsxs20(Fragment6, { children: [
2814
- /* @__PURE__ */ jsx25(DataTable__Row, { $hasDetail: hasDetail, children: columns.map((col) => /* @__PURE__ */ jsx25(
2942
+ return /* @__PURE__ */ jsxs21(Fragment6, { children: [
2943
+ /* @__PURE__ */ jsx26(DataTable__Row, { $hasDetail: hasDetail, children: columns.map((col) => /* @__PURE__ */ jsx26(
2815
2944
  DataTable__Cell,
2816
2945
  {
2817
2946
  as: col.rowHeader ? "th" : void 0,
@@ -2821,21 +2950,21 @@ function DataTable({
2821
2950
  },
2822
2951
  col.key
2823
2952
  )) }),
2824
- hasDetail ? /* @__PURE__ */ jsx25("tr", { children: /* @__PURE__ */ jsx25(DataTable__DetailCell, { colSpan: columns.length, children: detail }) }) : null
2953
+ hasDetail ? /* @__PURE__ */ jsx26("tr", { children: /* @__PURE__ */ jsx26(DataTable__DetailCell, { colSpan: columns.length, children: detail }) }) : null
2825
2954
  ] }, key);
2826
2955
  })
2827
2956
  ] }, group.id))
2828
2957
  ] }) }),
2829
- /* @__PURE__ */ jsx25(InlineOverflowGlow, { $position: "left", $visible: overflow.left }),
2830
- /* @__PURE__ */ jsx25(InlineOverflowGlow, { $position: "right", $visible: overflow.right })
2958
+ /* @__PURE__ */ jsx26(InlineOverflowGlow, { $position: "left", $visible: overflow.left }),
2959
+ /* @__PURE__ */ jsx26(InlineOverflowGlow, { $position: "right", $visible: overflow.right })
2831
2960
  ] });
2832
2961
  }
2833
- var DataTable__Shell = styled24.div`
2962
+ var DataTable__Shell = styled25.div`
2834
2963
  position: relative;
2835
2964
  min-width: 0;
2836
2965
  margin-inline: calc(-1 * var(--bleed-inline));
2837
2966
  `;
2838
- var DataTable__Scroller = styled24.div`
2967
+ var DataTable__Scroller = styled25.div`
2839
2968
  display: flex;
2840
2969
  padding-inline: var(--bleed-inline);
2841
2970
  overflow-x: auto;
@@ -2846,12 +2975,12 @@ var DataTable__Scroller = styled24.div`
2846
2975
  display: none;
2847
2976
  }
2848
2977
  `;
2849
- var DataTable__Table = styled24.table`
2978
+ var DataTable__Table = styled25.table`
2850
2979
  width: 100%;
2851
2980
  border-collapse: collapse;
2852
2981
  font-size: var(--font-size-compact);
2853
2982
  `;
2854
- var DataTable__Caption = styled24.caption`
2983
+ var DataTable__Caption = styled25.caption`
2855
2984
  position: absolute;
2856
2985
  width: 1px;
2857
2986
  height: 1px;
@@ -2859,7 +2988,7 @@ var DataTable__Caption = styled24.caption`
2859
2988
  clip-path: inset(50%);
2860
2989
  white-space: nowrap;
2861
2990
  `;
2862
- var DataTable__HeaderCell = styled24.th`
2991
+ var DataTable__HeaderCell = styled25.th`
2863
2992
  text-align: ${({ $align }) => $align};
2864
2993
  position: sticky;
2865
2994
  top: 0;
@@ -2875,7 +3004,7 @@ var DataTable__HeaderCell = styled24.th`
2875
3004
  padding: var(--inset-table-cell);
2876
3005
  border-bottom: 1px solid var(--color-border-subtle);
2877
3006
  `;
2878
- var DataTable__SectionCell = styled24.th`
3007
+ var DataTable__SectionCell = styled25.th`
2879
3008
  text-align: start;
2880
3009
  background: var(--color-surface-raised);
2881
3010
  color: var(--color-text-muted);
@@ -2886,13 +3015,13 @@ var DataTable__SectionCell = styled24.th`
2886
3015
  padding: var(--inset-table-section);
2887
3016
  border-bottom: 1px solid var(--color-border-subtle);
2888
3017
  `;
2889
- var DataTable__Row = styled24.tr`
3018
+ var DataTable__Row = styled25.tr`
2890
3019
  &:not(:last-child) > td,
2891
3020
  &:not(:last-child) > th {
2892
3021
  border-bottom: ${({ $hasDetail }) => $hasDetail ? "none" : "1px solid var(--color-border-subtle)"};
2893
3022
  }
2894
3023
  `;
2895
- var DataTable__Cell = styled24.td`
3024
+ var DataTable__Cell = styled25.td`
2896
3025
  text-align: ${({ $align }) => $align};
2897
3026
  font-weight: inherit;
2898
3027
  color: var(--color-text-primary);
@@ -2900,11 +3029,11 @@ var DataTable__Cell = styled24.td`
2900
3029
  font-variant-numeric: tabular-nums;
2901
3030
  vertical-align: baseline;
2902
3031
  `;
2903
- var DataTable__DetailCell = styled24.td`
3032
+ var DataTable__DetailCell = styled25.td`
2904
3033
  padding: var(--inset-table-detail);
2905
3034
  border-bottom: 1px solid var(--color-border-subtle);
2906
3035
  `;
2907
- var DataTable__EmptyCell = styled24.td`
3036
+ var DataTable__EmptyCell = styled25.td`
2908
3037
  color: var(--color-text-faint);
2909
3038
  font-style: italic;
2910
3039
  padding: var(--inset-table-empty);
@@ -2912,8 +3041,8 @@ var DataTable__EmptyCell = styled24.td`
2912
3041
 
2913
3042
  // src/Dial.tsx
2914
3043
  import { bandIn } from "@ksp-gonogo/sitrep-sdk";
2915
- import styled25 from "styled-components";
2916
- import { Fragment as Fragment7, jsx as jsx26, jsxs as jsxs21 } from "react/jsx-runtime";
3044
+ import styled26 from "styled-components";
3045
+ import { Fragment as Fragment7, jsx as jsx27, jsxs as jsxs22 } from "react/jsx-runtime";
2917
3046
  var TRACK_THICKNESS = 6;
2918
3047
  var HUB_RADIUS = 3;
2919
3048
  var RAISED = { track: 8, hub: 4, needle: 0.92 };
@@ -2934,7 +3063,7 @@ function arcPath(cx, cy, r, a0, a1) {
2934
3063
  return `M ${p0.x.toFixed(2)} ${p0.y.toFixed(2)} A ${r} ${r} 0 ${largeArc} ${sweepFlag} ${p1.x.toFixed(2)} ${p1.y.toFixed(2)}`;
2935
3064
  }
2936
3065
  function Dial({
2937
- value: value4,
3066
+ value: value5,
2938
3067
  min,
2939
3068
  max,
2940
3069
  width = 120,
@@ -2949,9 +3078,9 @@ function Dial({
2949
3078
  format,
2950
3079
  needleColor = "var(--color-text-primary)",
2951
3080
  trackColor = "var(--color-border-subtle)",
2952
- ariaLabel
3081
+ "aria-label": ariaLabel
2953
3082
  }) {
2954
- const resolved = resolveCurrency(value4);
3083
+ const resolved = resolveCurrency(value5);
2955
3084
  const { shown, held, caption, band } = resolved;
2956
3085
  const { anchor, tip } = useTooltip(caption);
2957
3086
  const current = shown?.magnitude ?? Number.NaN;
@@ -2997,14 +3126,14 @@ function Dial({
2997
3126
  r * (raised ? RAISED.needle : 0.88),
2998
3127
  angleOf(display)
2999
3128
  );
3000
- return /* @__PURE__ */ jsxs21(
3129
+ return /* @__PURE__ */ jsxs22(
3001
3130
  Dial__Meter,
3002
3131
  {
3003
3132
  ...figureAttributes(resolved),
3004
3133
  ...anchor,
3005
3134
  ...hasFigure ? {
3006
3135
  role: "meter",
3007
- "aria-label": sayHeld(ariaLabel ?? "Dial", caption),
3136
+ "aria-label": sayHeld(ariaLabel, caption),
3008
3137
  ...heldNameMarker(caption),
3009
3138
  "aria-valuenow": display,
3010
3139
  "aria-valuemin": axisMin,
@@ -3013,11 +3142,11 @@ function Dial({
3013
3142
  } : {
3014
3143
  /* With no value to state, the face is an image rather than a meter at its minimum. */
3015
3144
  role: "img",
3016
- "aria-label": sayHeld(`${ariaLabel ?? "Dial"}: ${spoken}`, caption),
3145
+ "aria-label": sayHeld(`${ariaLabel}: ${spoken}`, caption),
3017
3146
  ...heldNameMarker(caption)
3018
3147
  },
3019
3148
  children: [
3020
- /* @__PURE__ */ jsxs21(
3149
+ /* @__PURE__ */ jsxs22(
3021
3150
  "svg",
3022
3151
  {
3023
3152
  width,
@@ -3031,7 +3160,7 @@ function Dial({
3031
3160
  height: "auto"
3032
3161
  },
3033
3162
  children: [
3034
- r > 0 && (isFullCircle ? /* @__PURE__ */ jsx26(
3163
+ r > 0 && (isFullCircle ? /* @__PURE__ */ jsx27(
3035
3164
  "circle",
3036
3165
  {
3037
3166
  cx,
@@ -3041,7 +3170,7 @@ function Dial({
3041
3170
  stroke: trackColor,
3042
3171
  strokeWidth: trackThickness
3043
3172
  }
3044
- ) : /* @__PURE__ */ jsx26(
3173
+ ) : /* @__PURE__ */ jsx27(
3045
3174
  "path",
3046
3175
  {
3047
3176
  d: arcPath(cx, cy, r, startAngle, startAngle + sweep),
@@ -3063,7 +3192,7 @@ function Dial({
3063
3192
  if (angle === null) return [];
3064
3193
  const end = pointAt(cx, cy, r, angle);
3065
3194
  return [
3066
- /* @__PURE__ */ jsx26(
3195
+ /* @__PURE__ */ jsx27(
3067
3196
  "circle",
3068
3197
  {
3069
3198
  "data-dial-cap": "",
@@ -3081,7 +3210,7 @@ function Dial({
3081
3210
  const lo = onAxis(z.from.min(z.to));
3082
3211
  const hi = onAxis(z.from.max(z.to));
3083
3212
  if (!hi.greaterThan(lo)) return null;
3084
- return /* @__PURE__ */ jsx26(
3213
+ return /* @__PURE__ */ jsx27(
3085
3214
  "path",
3086
3215
  {
3087
3216
  d: arcPath(cx, cy, r, onFace(lo), onFace(hi)),
@@ -3099,8 +3228,8 @@ function Dial({
3099
3228
  const outer = pointAt(cx, cy, r, a);
3100
3229
  const inner = pointAt(cx, cy, r - trackThickness, a);
3101
3230
  const labelPt = pointAt(cx, cy, r - trackThickness - 8, a);
3102
- return /* @__PURE__ */ jsxs21("g", { children: [
3103
- /* @__PURE__ */ jsx26(
3231
+ return /* @__PURE__ */ jsxs22("g", { children: [
3232
+ /* @__PURE__ */ jsx27(
3104
3233
  "line",
3105
3234
  {
3106
3235
  x1: inner.x,
@@ -3111,7 +3240,7 @@ function Dial({
3111
3240
  strokeWidth: 1
3112
3241
  }
3113
3242
  ),
3114
- tk.label && /* @__PURE__ */ jsx26(
3243
+ tk.label && /* @__PURE__ */ jsx27(
3115
3244
  "text",
3116
3245
  {
3117
3246
  x: labelPt.x,
@@ -3129,7 +3258,7 @@ function Dial({
3129
3258
  const a = onFace(onAxis(drawnInterval[end]));
3130
3259
  const inner = pointAt(cx, cy, r - trackThickness / 2, a);
3131
3260
  const outer = pointAt(cx, cy, r + trackThickness / 2, a);
3132
- return /* @__PURE__ */ jsx26(
3261
+ return /* @__PURE__ */ jsx27(
3133
3262
  InstrumentBound,
3134
3263
  {
3135
3264
  end,
@@ -3141,8 +3270,8 @@ function Dial({
3141
3270
  end
3142
3271
  );
3143
3272
  }),
3144
- r > 0 && hasFigure && /* @__PURE__ */ jsxs21(Fragment7, { children: [
3145
- /* @__PURE__ */ jsx26(
3273
+ r > 0 && hasFigure && /* @__PURE__ */ jsxs22(Fragment7, { children: [
3274
+ /* @__PURE__ */ jsx27(
3146
3275
  "line",
3147
3276
  {
3148
3277
  x1: cx,
@@ -3154,9 +3283,9 @@ function Dial({
3154
3283
  strokeLinecap: "round"
3155
3284
  }
3156
3285
  ),
3157
- /* @__PURE__ */ jsx26("circle", { cx, cy, r: hubRadius, fill: needleColor })
3286
+ /* @__PURE__ */ jsx27("circle", { cx, cy, r: hubRadius, fill: needleColor })
3158
3287
  ] }),
3159
- /* @__PURE__ */ jsxs21(
3288
+ /* @__PURE__ */ jsxs22(
3160
3289
  "text",
3161
3290
  {
3162
3291
  x: cx,
@@ -3167,7 +3296,7 @@ function Dial({
3167
3296
  fill: centreLabel === null ? "var(--color-text-muted)" : "var(--color-text-primary)",
3168
3297
  children: [
3169
3298
  centreLabel ?? NULL_DISPLAY,
3170
- held && centreLabel !== null && /* @__PURE__ */ jsx26(
3299
+ held && centreLabel !== null && /* @__PURE__ */ jsx27(
3171
3300
  InstrumentHeldMark,
3172
3301
  {
3173
3302
  size: raised ? 7 : 6,
@@ -3185,19 +3314,19 @@ function Dial({
3185
3314
  }
3186
3315
  );
3187
3316
  }
3188
- var Dial__Meter = styled25.div`
3317
+ var Dial__Meter = styled26.div`
3189
3318
  display: block;
3190
3319
  max-width: 100%;
3191
3320
  `;
3192
3321
 
3193
3322
  // src/Disclosure.tsx
3194
3323
  import { useId as useId7, useRef as useRef7, useState as useState8 } from "react";
3195
- import styled26, { css as css8 } from "styled-components";
3196
- import { Fragment as Fragment8, jsx as jsx27, jsxs as jsxs22 } from "react/jsx-runtime";
3324
+ import styled27, { css as css8 } from "styled-components";
3325
+ import { Fragment as Fragment8, jsx as jsx28, jsxs as jsxs23 } from "react/jsx-runtime";
3197
3326
  function Disclosure({
3198
3327
  label,
3199
3328
  children,
3200
- ariaLabel,
3329
+ "aria-label": ariaLabel,
3201
3330
  className,
3202
3331
  variant = "popover",
3203
3332
  panelHeight = "cap",
@@ -3221,11 +3350,11 @@ function Disclosure({
3221
3350
  "aria-label": ariaLabel,
3222
3351
  onClick: () => setOpen((v) => !v)
3223
3352
  };
3224
- const triggerBody = /* @__PURE__ */ jsxs22(Fragment8, { children: [
3353
+ const triggerBody = /* @__PURE__ */ jsxs23(Fragment8, { children: [
3225
3354
  resolvedLabel,
3226
- showChevron && /* @__PURE__ */ jsx27(Disclosure__Chevron, { $open: open, children: /* @__PURE__ */ jsx27(ChevronRightIcon, { size: "var(--icon-size-control)" }) })
3355
+ showChevron && /* @__PURE__ */ jsx28(Disclosure__Chevron, { $open: open, children: /* @__PURE__ */ jsx28(ChevronRightIcon, { size: "var(--icon-size-control)" }) })
3227
3356
  ] });
3228
- return /* @__PURE__ */ jsxs22(
3357
+ return /* @__PURE__ */ jsxs23(
3229
3358
  Disclosure__Root,
3230
3359
  {
3231
3360
  className,
@@ -3237,7 +3366,7 @@ function Disclosure({
3237
3366
  }
3238
3367
  },
3239
3368
  children: [
3240
- asButton ? /* @__PURE__ */ jsx27(
3369
+ asButton ? /* @__PURE__ */ jsx28(
3241
3370
  Disclosure__ButtonTrigger,
3242
3371
  {
3243
3372
  ...triggerProps,
@@ -3246,7 +3375,7 @@ function Disclosure({
3246
3375
  $inline: variant === "inline",
3247
3376
  children: triggerBody
3248
3377
  }
3249
- ) : /* @__PURE__ */ jsx27(
3378
+ ) : /* @__PURE__ */ jsx28(
3250
3379
  Disclosure__Trigger,
3251
3380
  {
3252
3381
  ...triggerProps,
@@ -3255,7 +3384,7 @@ function Disclosure({
3255
3384
  children: triggerBody
3256
3385
  }
3257
3386
  ),
3258
- open && /* @__PURE__ */ jsx27(
3387
+ open && /* @__PURE__ */ jsx28(
3259
3388
  Disclosure__Panel,
3260
3389
  {
3261
3390
  ref: setPanel,
@@ -3271,13 +3400,13 @@ function Disclosure({
3271
3400
  }
3272
3401
  );
3273
3402
  }
3274
- var Disclosure__Root = styled26.div`
3403
+ var Disclosure__Root = styled27.div`
3275
3404
  position: relative;
3276
3405
  display: ${({ $variant }) => $variant === "inline" ? "flex" : "inline-flex"};
3277
3406
  flex-direction: column;
3278
3407
  width: ${({ $variant }) => $variant === "inline" ? "100%" : "auto"};
3279
3408
  `;
3280
- var Disclosure__Trigger = styled26.button`
3409
+ var Disclosure__Trigger = styled27.button`
3281
3410
  display: inline-flex;
3282
3411
  align-items: center;
3283
3412
  gap: var(--gap-glyph);
@@ -3296,12 +3425,12 @@ var Disclosure__Trigger = styled26.button`
3296
3425
  `}
3297
3426
  ${focusRing}
3298
3427
  `;
3299
- var Disclosure__ButtonTrigger = styled26(Button)`
3428
+ var Disclosure__ButtonTrigger = styled27(Button)`
3300
3429
  ${({ $inline }) => $inline && css8`
3301
3430
  align-self: flex-end;
3302
3431
  `}
3303
3432
  `;
3304
- var Disclosure__Chevron = styled26.span`
3433
+ var Disclosure__Chevron = styled27.span`
3305
3434
  display: inline-flex;
3306
3435
  flex-shrink: 0;
3307
3436
  @media (prefers-reduced-motion: no-preference) {
@@ -3309,7 +3438,7 @@ var Disclosure__Chevron = styled26.span`
3309
3438
  }
3310
3439
  transform: rotate(${({ $open }) => $open ? 90 : 0}deg);
3311
3440
  `;
3312
- var Disclosure__Panel = styled26.div`
3441
+ var Disclosure__Panel = styled27.div`
3313
3442
  ${({ $variant }) => $variant === "popover" ? css8`
3314
3443
  position: absolute;
3315
3444
  top: 100%;
@@ -3335,17 +3464,17 @@ var Disclosure__Panel = styled26.div`
3335
3464
  `;
3336
3465
 
3337
3466
  // src/DivergingBar.tsx
3338
- import styled27, { css as css9 } from "styled-components";
3339
- import { jsx as jsx28, jsxs as jsxs23 } from "react/jsx-runtime";
3467
+ import styled28, { css as css9 } from "styled-components";
3468
+ import { jsx as jsx29, jsxs as jsxs24 } from "react/jsx-runtime";
3340
3469
  function DivergingBar({
3341
- value: value4,
3470
+ value: value5,
3342
3471
  maxAbs,
3343
3472
  className
3344
3473
  }) {
3345
- const resolved = resolveCurrency(value4);
3474
+ const resolved = resolveCurrency(value5);
3346
3475
  const { shown, held } = resolved;
3347
3476
  const pct = shown != null && maxAbs.isPositive() ? Math.min(50, shown.abs().dividedBy(maxAbs).magnitude * 50) : 0;
3348
- return /* @__PURE__ */ jsxs23(
3477
+ return /* @__PURE__ */ jsxs24(
3349
3478
  DivergingBar__Track,
3350
3479
  {
3351
3480
  "aria-hidden": "true",
@@ -3353,8 +3482,8 @@ function DivergingBar({
3353
3482
  ...figureAttributes(resolved),
3354
3483
  className,
3355
3484
  children: [
3356
- /* @__PURE__ */ jsx28(DivergingBar__Zero, {}),
3357
- shown != null && /* @__PURE__ */ jsx28(
3485
+ /* @__PURE__ */ jsx29(DivergingBar__Zero, {}),
3486
+ shown != null && /* @__PURE__ */ jsx29(
3358
3487
  DivergingBar__Fill,
3359
3488
  {
3360
3489
  $positive: !shown.isNegative(),
@@ -3367,7 +3496,7 @@ function DivergingBar({
3367
3496
  );
3368
3497
  }
3369
3498
  var DIVERGING_BAR_MIN_CONTAINER = "300px";
3370
- var DivergingBar__Track = styled27.div`
3499
+ var DivergingBar__Track = styled28.div`
3371
3500
  position: relative;
3372
3501
  width: 3.5rem;
3373
3502
  height: 4px;
@@ -3381,7 +3510,7 @@ var DivergingBar__Track = styled27.div`
3381
3510
  display: block;
3382
3511
  }
3383
3512
  `;
3384
- var DivergingBar__Zero = styled27.div`
3513
+ var DivergingBar__Zero = styled28.div`
3385
3514
  position: absolute;
3386
3515
  left: 50%;
3387
3516
  top: 0;
@@ -3389,7 +3518,7 @@ var DivergingBar__Zero = styled27.div`
3389
3518
  width: 1px;
3390
3519
  background: var(--color-border-strong);
3391
3520
  `;
3392
- var DivergingBar__Fill = styled27.div`
3521
+ var DivergingBar__Fill = styled28.div`
3393
3522
  position: absolute;
3394
3523
  top: 0;
3395
3524
  bottom: 0;
@@ -3406,12 +3535,12 @@ var DivergingBar__Fill = styled27.div`
3406
3535
  `;
3407
3536
 
3408
3537
  // src/Divider.tsx
3409
- import styled28 from "styled-components";
3410
- import { jsx as jsx29 } from "react/jsx-runtime";
3538
+ import styled29 from "styled-components";
3539
+ import { jsx as jsx30 } from "react/jsx-runtime";
3411
3540
  function Divider({ space, ...rest }) {
3412
- return /* @__PURE__ */ jsx29(Divider__Root, { $space: space, ...rest });
3541
+ return /* @__PURE__ */ jsx30(Divider__Root, { $space: space, ...rest });
3413
3542
  }
3414
- var Divider__Root = styled28.hr`
3543
+ var Divider__Root = styled29.hr`
3415
3544
  border: 0;
3416
3545
  border-top: 1px solid var(--color-border-subtle);
3417
3546
  width: 100%;
@@ -3420,8 +3549,8 @@ var Divider__Root = styled28.hr`
3420
3549
 
3421
3550
  // src/ExpandableText.tsx
3422
3551
  import { useId as useId8, useState as useState9 } from "react";
3423
- import styled29 from "styled-components";
3424
- import { Fragment as Fragment9, jsx as jsx30, jsxs as jsxs24 } from "react/jsx-runtime";
3552
+ import styled30 from "styled-components";
3553
+ import { Fragment as Fragment9, jsx as jsx31, jsxs as jsxs25 } from "react/jsx-runtime";
3425
3554
  var DEFAULT_LIMIT = 160;
3426
3555
  var WORTH_CUTTING = 24;
3427
3556
  var CUT_MARK = "...";
@@ -3434,12 +3563,12 @@ function ExpandableText({
3434
3563
  const [expanded, setExpanded] = useState9(false);
3435
3564
  const proseId = useId8();
3436
3565
  const head = cut(children, limit);
3437
- if (head === void 0) return /* @__PURE__ */ jsx30(Fragment9, { children });
3566
+ if (head === void 0) return /* @__PURE__ */ jsx31(Fragment9, { children });
3438
3567
  const verb = expanded ? "Show less" : "Show more";
3439
- return /* @__PURE__ */ jsxs24(ExpandableText__Root, { className, children: [
3440
- /* @__PURE__ */ jsx30("span", { id: proseId, children: expanded ? children : `${head}${CUT_MARK}` }),
3568
+ return /* @__PURE__ */ jsxs25(ExpandableText__Root, { className, children: [
3569
+ /* @__PURE__ */ jsx31("span", { id: proseId, children: expanded ? children : `${head}${CUT_MARK}` }),
3441
3570
  " ",
3442
- /* @__PURE__ */ jsx30(
3571
+ /* @__PURE__ */ jsx31(
3443
3572
  ExpandableText__Toggle,
3444
3573
  {
3445
3574
  type: "button",
@@ -3458,41 +3587,50 @@ function cut(text, limit) {
3458
3587
  const boundary = text.lastIndexOf(" ", limit);
3459
3588
  return boundary <= 0 ? text.slice(0, limit) : text.slice(0, boundary);
3460
3589
  }
3461
- var ExpandableText__Root = styled29.span`
3590
+ var ExpandableText__Root = styled30.span`
3462
3591
  /* Long prose may carry a word wider than its column, and a broken word beats a sideways scroll. */
3463
3592
  overflow-wrap: break-word;
3464
3593
  `;
3465
- var ExpandableText__Toggle = styled29(TextButton)`
3594
+ var ExpandableText__Toggle = styled30(TextButton)`
3466
3595
  /* Sits on the text's baseline as the paragraph's last word, so the cut and its undo read as one. */
3467
3596
  white-space: nowrap;
3468
3597
  `;
3469
3598
 
3470
3599
  // src/ephemerisFigure.ts
3471
3600
  import {
3472
- asDeterministic
3601
+ asDeterministic,
3602
+ poseAtIndex,
3603
+ value as value2
3473
3604
  } from "@ksp-gonogo/sitrep-sdk";
3474
- function ephemerisFigureOf(catalogue, bodies) {
3475
- const exact = bodies.length > 0 && bodies.every((body) => body?.deterministic === true);
3605
+ function ephemerisFigureOf(poses, bodies) {
3606
+ const resting = bodies.map(
3607
+ (body) => body == null ? null : poseAtIndex(poses, body.index)
3608
+ );
3609
+ const exact = resting.length > 0 && resting.every((pose) => pose?.currency === "exact");
3610
+ const heldAt = resting.reduce((oldest, pose) => {
3611
+ if (pose?.currency !== "held" || pose.asOfUt === null) return oldest;
3612
+ return oldest === null ? pose.asOfUt : Math.min(oldest, pose.asOfUt);
3613
+ }, null);
3476
3614
  return (figure) => {
3477
3615
  const drawn = exact ? asDeterministic(figure) : figure;
3478
- if (catalogue?.state !== "held") return drawn;
3616
+ if (heldAt === null) return drawn;
3479
3617
  return {
3480
3618
  state: "held",
3481
3619
  value: drawn,
3482
- asOfUt: catalogue.asOfUt,
3483
- grade: catalogue.grade,
3620
+ asOfUt: value2("ut", heldAt),
3621
+ grade: "held",
3484
3622
  reckoning: { status: "none" }
3485
3623
  };
3486
3624
  };
3487
3625
  }
3488
3626
 
3489
3627
  // src/Fill.tsx
3490
- import styled30 from "styled-components";
3491
- import { jsx as jsx31 } from "react/jsx-runtime";
3628
+ import styled31 from "styled-components";
3629
+ import { jsx as jsx32 } from "react/jsx-runtime";
3492
3630
  function Fill({ grow = false, children, ...rest }) {
3493
- return /* @__PURE__ */ jsx31(Fill__Root, { $grow: grow, ...rest, children });
3631
+ return /* @__PURE__ */ jsx32(Fill__Root, { $grow: grow, ...rest, children });
3494
3632
  }
3495
- var Fill__Root = styled30.div`
3633
+ var Fill__Root = styled31.div`
3496
3634
  position: relative;
3497
3635
  display: flex;
3498
3636
  flex-direction: column;
@@ -3505,7 +3643,7 @@ var Fill__Root = styled30.div`
3505
3643
  `;
3506
3644
 
3507
3645
  // src/FilterList.tsx
3508
- import { jsx as jsx32 } from "react/jsx-runtime";
3646
+ import { jsx as jsx33 } from "react/jsx-runtime";
3509
3647
  function FilterList({
3510
3648
  rows,
3511
3649
  segment = "filters",
@@ -3513,7 +3651,7 @@ function FilterList({
3513
3651
  }) {
3514
3652
  const filter = useRowFilter({ segment });
3515
3653
  const shown = rows.filter((row) => filter.matches(row.searchText));
3516
- return /* @__PURE__ */ jsx32(FilterRegion, { filter, children: shown.length > 0 ? /* @__PURE__ */ jsx32(Stack, { gap: "related", children: shown.map((row) => /* @__PURE__ */ jsx32("div", { children: row.node }, row.id)) }) : /* @__PURE__ */ jsx32(EmptyState, { children: emptyLabel }) });
3654
+ return /* @__PURE__ */ jsx33(FilterRegion, { filter, children: shown.length > 0 ? /* @__PURE__ */ jsx33(Stack, { gap: "related", children: shown.map((row) => /* @__PURE__ */ jsx33("div", { children: row.node }, row.id)) }) : /* @__PURE__ */ jsx33(EmptyState, { children: emptyLabel }) });
3517
3655
  }
3518
3656
 
3519
3657
  // src/Floating.tsx
@@ -3524,8 +3662,8 @@ import {
3524
3662
  useState as useState10
3525
3663
  } from "react";
3526
3664
  import { createPortal } from "react-dom";
3527
- import styled31 from "styled-components";
3528
- import { jsx as jsx33 } from "react/jsx-runtime";
3665
+ import styled32 from "styled-components";
3666
+ import { jsx as jsx34 } from "react/jsx-runtime";
3529
3667
  function Floating({ anchor, style, children, ...rest }) {
3530
3668
  const [host, setHost] = useState10(null);
3531
3669
  const [pos, setPos] = useState10(null);
@@ -3563,7 +3701,7 @@ function Floating({ anchor, style, children, ...rest }) {
3563
3701
  }, [host, place2]);
3564
3702
  if (typeof document === "undefined") return null;
3565
3703
  return createPortal(
3566
- /* @__PURE__ */ jsx33(
3704
+ /* @__PURE__ */ jsx34(
3567
3705
  Floating__Root,
3568
3706
  {
3569
3707
  ref: setHost,
@@ -3580,14 +3718,14 @@ function Floating({ anchor, style, children, ...rest }) {
3580
3718
  document.body
3581
3719
  );
3582
3720
  }
3583
- var Floating__Root = styled31.div`
3721
+ var Floating__Root = styled32.div`
3584
3722
  position: fixed;
3585
3723
  z-index: var(--z-dropdown);
3586
3724
  `;
3587
3725
 
3588
3726
  // src/Grid.tsx
3589
- import styled32 from "styled-components";
3590
- import { jsx as jsx34 } from "react/jsx-runtime";
3727
+ import styled33 from "styled-components";
3728
+ import { jsx as jsx35 } from "react/jsx-runtime";
3591
3729
  var ALIGN_ITEMS = {
3592
3730
  center: "center",
3593
3731
  start: "start",
@@ -3604,7 +3742,7 @@ function Grid({
3604
3742
  children,
3605
3743
  ...rest
3606
3744
  }) {
3607
- return /* @__PURE__ */ jsx34(
3745
+ return /* @__PURE__ */ jsx35(
3608
3746
  Grid__Root,
3609
3747
  {
3610
3748
  $cols: cols,
@@ -3618,7 +3756,7 @@ function Grid({
3618
3756
  }
3619
3757
  );
3620
3758
  }
3621
- var Grid__Root = styled32.div`
3759
+ var Grid__Root = styled33.div`
3622
3760
  display: grid;
3623
3761
  align-items: ${({ $align }) => ALIGN_ITEMS[$align]};
3624
3762
  gap: ${({ $gap, $rowGap }) => $rowGap ? `${GAP_VAR[$rowGap]} ${GAP_VAR[$gap]}` : GAP_VAR[$gap]};
@@ -3631,15 +3769,15 @@ var Grid__Root = styled32.div`
3631
3769
  `;
3632
3770
 
3633
3771
  // src/HeldBadge.tsx
3634
- import { jsx as jsx35 } from "react/jsx-runtime";
3772
+ import { jsx as jsx36 } from "react/jsx-runtime";
3635
3773
  function HeldBadge({ grade, subject, size }) {
3636
3774
  const word = heldWord(grade);
3637
- return /* @__PURE__ */ jsx35(
3775
+ return /* @__PURE__ */ jsx36(
3638
3776
  Tooltip,
3639
3777
  {
3640
3778
  text: subject === void 0 ? void 0 : `${subject}: ${word}`,
3641
3779
  focusable: true,
3642
- children: /* @__PURE__ */ jsx35(Badge, { tone: severityFromStreamStatus(grade), size, children: word })
3780
+ children: /* @__PURE__ */ jsx36(Badge, { tone: severityFromStreamStatus(grade), size, children: word })
3643
3781
  }
3644
3782
  );
3645
3783
  }
@@ -3652,10 +3790,14 @@ import {
3652
3790
  useRef as useRef9,
3653
3791
  useState as useState11
3654
3792
  } from "react";
3655
- import styled33 from "styled-components";
3656
- import { Fragment as Fragment10, jsx as jsx36, jsxs as jsxs25 } from "react/jsx-runtime";
3793
+ import styled34 from "styled-components";
3794
+ import { Fragment as Fragment10, jsx as jsx37, jsxs as jsxs26 } from "react/jsx-runtime";
3657
3795
  var CLOSE_DELAY_MS = 120;
3658
- function HoverCard({ trigger, ariaLabel, children }) {
3796
+ function HoverCard({
3797
+ trigger,
3798
+ "aria-label": ariaLabel,
3799
+ children
3800
+ }) {
3659
3801
  const [open, setOpen] = useState11(false);
3660
3802
  const triggerRef = useRef9(null);
3661
3803
  const closeTimer = useRef9(null);
@@ -3690,8 +3832,8 @@ function HoverCard({ trigger, ariaLabel, children }) {
3690
3832
  const rect = triggerRef.current?.getBoundingClientRect();
3691
3833
  return rect ? { x: rect.left, y: rect.bottom } : null;
3692
3834
  };
3693
- return /* @__PURE__ */ jsxs25(Fragment10, { children: [
3694
- /* @__PURE__ */ jsx36(
3835
+ return /* @__PURE__ */ jsxs26(Fragment10, { children: [
3836
+ /* @__PURE__ */ jsx37(
3695
3837
  HoverCard__Trigger,
3696
3838
  {
3697
3839
  ref: triggerRef,
@@ -3705,18 +3847,18 @@ function HoverCard({ trigger, ariaLabel, children }) {
3705
3847
  children: trigger
3706
3848
  }
3707
3849
  ),
3708
- open && /* @__PURE__ */ jsx36(
3850
+ open && /* @__PURE__ */ jsx37(
3709
3851
  Floating,
3710
3852
  {
3711
3853
  anchor,
3712
3854
  onPointerEnter: cancelClose,
3713
3855
  onPointerLeave: hideSoon,
3714
- children: /* @__PURE__ */ jsx36(HoverCard__Card, { id: cardId, role: "tooltip", children })
3856
+ children: /* @__PURE__ */ jsx37(HoverCard__Card, { id: cardId, role: "tooltip", children })
3715
3857
  }
3716
3858
  )
3717
3859
  ] });
3718
3860
  }
3719
- var HoverCard__Trigger = styled33.button`
3861
+ var HoverCard__Trigger = styled34.button`
3720
3862
  display: inline-flex;
3721
3863
  align-items: center;
3722
3864
  padding: 0;
@@ -3724,11 +3866,11 @@ var HoverCard__Trigger = styled33.button`
3724
3866
  background: none;
3725
3867
  color: inherit;
3726
3868
  font: inherit;
3727
- cursor: help;
3869
+ cursor: default;
3728
3870
 
3729
3871
  ${focusRing}
3730
3872
  `;
3731
- var HoverCard__Card = styled33.div`
3873
+ var HoverCard__Card = styled34.div`
3732
3874
  padding: var(--inset-popover);
3733
3875
  border: 1px solid var(--color-border-strong);
3734
3876
  border-radius: var(--radius-regular);
@@ -3737,8 +3879,8 @@ var HoverCard__Card = styled33.div`
3737
3879
  `;
3738
3880
 
3739
3881
  // src/Inline.tsx
3740
- import styled34 from "styled-components";
3741
- import { jsx as jsx37 } from "react/jsx-runtime";
3882
+ import styled35 from "styled-components";
3883
+ import { jsx as jsx38 } from "react/jsx-runtime";
3742
3884
  function Inline({
3743
3885
  gap,
3744
3886
  inset = false,
@@ -3746,9 +3888,9 @@ function Inline({
3746
3888
  children,
3747
3889
  ...rest
3748
3890
  }) {
3749
- return /* @__PURE__ */ jsx37(Inline__Root, { $gap: gap, $inset: inset, $wrap: wrap, ...rest, children });
3891
+ return /* @__PURE__ */ jsx38(Inline__Root, { $gap: gap, $inset: inset, $wrap: wrap, ...rest, children });
3750
3892
  }
3751
- var Inline__Root = styled34.span`
3893
+ var Inline__Root = styled35.span`
3752
3894
  display: inline-flex;
3753
3895
  gap: ${({ $gap }) => $gap ? GAP_VAR[$gap] : "var(--gap-related)"};
3754
3896
  flex-shrink: ${({ $wrap }) => $wrap ? 1 : 0};
@@ -3758,8 +3900,8 @@ var Inline__Root = styled34.span`
3758
3900
 
3759
3901
  // src/JogWheel.tsx
3760
3902
  import { useEffect as useEffect9, useRef as useRef10, useState as useState12 } from "react";
3761
- import styled35 from "styled-components";
3762
- import { jsx as jsx38, jsxs as jsxs26 } from "react/jsx-runtime";
3903
+ import styled36 from "styled-components";
3904
+ import { jsx as jsx39, jsxs as jsxs27 } from "react/jsx-runtime";
3763
3905
  var SENSITIVITY_PX_PER_STEP = 4;
3764
3906
  var RATE_TRAVEL_PX = 80;
3765
3907
  var RATE_TICK_MS = 60;
@@ -3768,9 +3910,9 @@ var JOG_WHEEL_MIN_TARGET_PX = 24;
3768
3910
  var COMPACT_CROSS_AXIS_PX = 32;
3769
3911
  var DEFAULT_LONG_PX = 56;
3770
3912
  var DEFAULT_SHORT_PX = JOG_WHEEL_MIN_TARGET_PX;
3771
- function applyDelta(value4, bounds, deltaSteps) {
3913
+ function applyDelta(value5, bounds, deltaSteps) {
3772
3914
  const { min, max, step } = bounds;
3773
- const raw = value4 + deltaSteps * step;
3915
+ const raw = value5 + deltaSteps * step;
3774
3916
  const clamped = Math.min(max, Math.max(min, raw));
3775
3917
  if (!Number.isFinite(min)) return clamped;
3776
3918
  const snapped = min + Math.round((clamped - min) / step) * step;
@@ -3778,14 +3920,14 @@ function applyDelta(value4, bounds, deltaSteps) {
3778
3920
  }
3779
3921
  function JogWheel(props) {
3780
3922
  const {
3781
- value: value4,
3923
+ value: value5,
3782
3924
  min,
3783
3925
  max,
3784
3926
  step,
3785
3927
  orientation = "horizontal",
3786
3928
  onChange,
3787
3929
  format,
3788
- ariaLabel,
3930
+ "aria-label": ariaLabel,
3789
3931
  label: caption = ariaLabel,
3790
3932
  disabled = false,
3791
3933
  width,
@@ -3805,14 +3947,14 @@ function JogWheel(props) {
3805
3947
  const hi = max ?? Number.POSITIVE_INFINITY;
3806
3948
  const bounds = { min: lo, max: hi, step };
3807
3949
  const drag = useRef10(null);
3808
- const latest = useRef10(value4);
3809
- latest.current = value4;
3950
+ const latest = useRef10(value5);
3951
+ latest.current = value5;
3810
3952
  const [displacement, setDisplacement] = useState12(0);
3811
- const label = format ? format(value4) : String(Math.round(value4));
3812
- const fraction = hi > lo && Number.isFinite(hi - lo) ? (value4 - lo) / (hi - lo) : 0.5;
3953
+ const label = format ? format(value5) : String(Math.round(value5));
3954
+ const fraction = hi > lo && Number.isFinite(hi - lo) ? (value5 - lo) / (hi - lo) : 0.5;
3813
3955
  const emit = (next) => {
3814
3956
  if (disabled) return;
3815
- if (next !== value4) onChange(next);
3957
+ if (next !== value5) onChange(next);
3816
3958
  };
3817
3959
  useEffect9(() => {
3818
3960
  if (!rate || displacement === 0 || disabled) return;
@@ -3829,11 +3971,11 @@ function JogWheel(props) {
3829
3971
  switch (e.key) {
3830
3972
  case "ArrowRight":
3831
3973
  case "ArrowUp":
3832
- next = applyDelta(value4, bounds, 1);
3974
+ next = applyDelta(value5, bounds, 1);
3833
3975
  break;
3834
3976
  case "ArrowLeft":
3835
3977
  case "ArrowDown":
3836
- next = applyDelta(value4, bounds, -1);
3978
+ next = applyDelta(value5, bounds, -1);
3837
3979
  break;
3838
3980
  case "Home":
3839
3981
  if (!Number.isFinite(lo)) return;
@@ -3852,7 +3994,7 @@ function JogWheel(props) {
3852
3994
  const axisPos = (e) => orientation === "vertical" ? e.clientY : e.clientX;
3853
3995
  const handlePointerDown = (e) => {
3854
3996
  if (disabled) return;
3855
- drag.current = { start: axisPos(e), startValue: value4 };
3997
+ drag.current = { start: axisPos(e), startValue: value5 };
3856
3998
  e.currentTarget.setPointerCapture(e.pointerId);
3857
3999
  };
3858
4000
  const handlePointerMove = (e) => {
@@ -3874,15 +4016,15 @@ function JogWheel(props) {
3874
4016
  e.currentTarget.releasePointerCapture(e.pointerId);
3875
4017
  }
3876
4018
  };
3877
- return /* @__PURE__ */ jsxs26(JogWheel__Frame, { children: [
3878
- caption !== false && /* @__PURE__ */ jsx38(JogWheel__Caption, { "aria-hidden": "true", children: caption }),
3879
- /* @__PURE__ */ jsxs26(
4019
+ return /* @__PURE__ */ jsxs27(JogWheel__Frame, { children: [
4020
+ caption !== false && /* @__PURE__ */ jsx39(JogWheel__Caption, { "aria-hidden": "true", children: caption }),
4021
+ /* @__PURE__ */ jsxs27(
3880
4022
  JogWheel__Root,
3881
4023
  {
3882
4024
  role: "slider",
3883
4025
  "aria-label": ariaLabel,
3884
4026
  "aria-orientation": orientation,
3885
- "aria-valuenow": Number.isFinite(value4) ? value4 : void 0,
4027
+ "aria-valuenow": Number.isFinite(value5) ? value5 : void 0,
3886
4028
  "aria-valuemin": min,
3887
4029
  "aria-valuemax": max,
3888
4030
  "aria-valuetext": label,
@@ -3899,7 +4041,7 @@ function JogWheel(props) {
3899
4041
  onPointerUp: endDrag,
3900
4042
  onPointerCancel: endDrag,
3901
4043
  children: [
3902
- /* @__PURE__ */ jsx38(
4044
+ /* @__PURE__ */ jsx39(
3903
4045
  JogWheel__Tape,
3904
4046
  {
3905
4047
  $orientation: orientation,
@@ -3907,25 +4049,25 @@ function JogWheel(props) {
3907
4049
  "aria-hidden": "true"
3908
4050
  }
3909
4051
  ),
3910
- /* @__PURE__ */ jsx38(JogWheel__Caret, { $orientation: orientation, "aria-hidden": "true" }),
3911
- /* @__PURE__ */ jsx38(JogWheel__Label, { "aria-hidden": "true", children: label })
4052
+ /* @__PURE__ */ jsx39(JogWheel__Caret, { $orientation: orientation, "aria-hidden": "true" }),
4053
+ /* @__PURE__ */ jsx39(JogWheel__Label, { "aria-hidden": "true", children: label })
3912
4054
  ]
3913
4055
  }
3914
4056
  )
3915
4057
  ] });
3916
4058
  }
3917
- var JogWheel__Frame = styled35.div`
4059
+ var JogWheel__Frame = styled36.div`
3918
4060
  display: inline-flex;
3919
4061
  flex-direction: column;
3920
4062
  align-items: flex-start;
3921
4063
  gap: var(--gap-related-packed);
3922
4064
  `;
3923
- var JogWheel__Caption = styled35.span`
4065
+ var JogWheel__Caption = styled36.span`
3924
4066
  font-size: var(--font-size-caption);
3925
4067
  color: var(--color-text-muted);
3926
4068
  white-space: nowrap;
3927
4069
  `;
3928
- var JogWheel__Root = styled35.div`
4070
+ var JogWheel__Root = styled36.div`
3929
4071
  position: relative;
3930
4072
  overflow: hidden;
3931
4073
  display: flex;
@@ -3945,7 +4087,7 @@ var JogWheel__Root = styled35.div`
3945
4087
 
3946
4088
  ${focusRing}
3947
4089
  `;
3948
- var JogWheel__Tape = styled35.div`
4090
+ var JogWheel__Tape = styled36.div`
3949
4091
  position: absolute;
3950
4092
  inset: 0;
3951
4093
  background-image: repeating-linear-gradient(
@@ -3956,13 +4098,13 @@ var JogWheel__Tape = styled35.div`
3956
4098
  opacity: 0.6;
3957
4099
  pointer-events: none;
3958
4100
  `;
3959
- var JogWheel__Caret = styled35.div`
4101
+ var JogWheel__Caret = styled36.div`
3960
4102
  position: absolute;
3961
4103
  background: var(--color-accent-fg);
3962
4104
  pointer-events: none;
3963
4105
  ${(p) => p.$orientation === "vertical" ? "left: 0; right: 0; height: 2px; top: 50%;" : "top: 0; bottom: 0; width: 2px; left: 50%;"}
3964
4106
  `;
3965
- var JogWheel__Label = styled35.span`
4107
+ var JogWheel__Label = styled36.span`
3966
4108
  /* Last DOM sibling, so it paints over the absolute tape and caret without a z-index. */
3967
4109
  position: relative;
3968
4110
  font-family: var(--font-family-mono);
@@ -3974,7 +4116,7 @@ var JogWheel__Label = styled35.span`
3974
4116
  `;
3975
4117
 
3976
4118
  // src/LineGraph.tsx
3977
- import styled36 from "styled-components";
4119
+ import styled37 from "styled-components";
3978
4120
 
3979
4121
  // src/reckoningBasisPhrase.ts
3980
4122
  var PHRASE = {
@@ -3990,7 +4132,7 @@ function reckoningBasisPhrase(basis) {
3990
4132
  }
3991
4133
 
3992
4134
  // src/LineGraph.tsx
3993
- import { jsx as jsx39, jsxs as jsxs27 } from "react/jsx-runtime";
4135
+ import { jsx as jsx40, jsxs as jsxs28 } from "react/jsx-runtime";
3994
4136
  var VIEW_W = 100;
3995
4137
  var VIEW_H = 40;
3996
4138
  function computeDomain(series, thresholds) {
@@ -4079,6 +4221,14 @@ function splitAtBreaks(points, breaks) {
4079
4221
  runs.push(points.slice(start));
4080
4222
  return runs;
4081
4223
  }
4224
+ function stepped(run) {
4225
+ const out = [];
4226
+ for (const [i, point] of run.entries()) {
4227
+ if (i > 0) out.push({ ...point, y: run[i - 1].y });
4228
+ out.push(point);
4229
+ }
4230
+ return out;
4231
+ }
4082
4232
  function computeXDomain(series) {
4083
4233
  const xs = [];
4084
4234
  for (const s of series)
@@ -4097,7 +4247,7 @@ function LineGraph({
4097
4247
  thresholds = [],
4098
4248
  yDomain,
4099
4249
  height = 120,
4100
- ariaLabel,
4250
+ "aria-label": ariaLabel,
4101
4251
  className,
4102
4252
  variant = "chart",
4103
4253
  thresholdStyle = "full"
@@ -4115,23 +4265,16 @@ function LineGraph({
4115
4265
  ...series.flatMap((s) => {
4116
4266
  const name = s.label ?? s.id;
4117
4267
  const runs = s.reckoned ?? [];
4118
- const kinds = new Set(
4119
- runs.map(
4120
- (run) => run.bandLo && run.bandHi ? run.bandKind : void 0
4121
- ).filter((kind) => kind !== void 0)
4122
- );
4123
4268
  return [
4124
4269
  ...[...new Set(runs.map((run) => run.basis))].map(
4125
4270
  (basis) => `${name}: part of this trace is reckoned, ${reckoningBasisPhrase(basis)}, not measured`
4126
4271
  ),
4127
- ...[...kinds].map(
4128
- (kind) => `${name}: ${bandClaim(kind, "the value is inside the shaded region")}`
4129
- )
4272
+ ...runs.some((run) => run.bandLo && run.bandHi) ? [`${name}: the value is inside the shaded region`] : []
4130
4273
  ];
4131
4274
  })
4132
4275
  ].join("; ") : void 0;
4133
- return /* @__PURE__ */ jsxs27(LineGraph__Root, { className, style: { height }, children: [
4134
- /* @__PURE__ */ jsxs27(
4276
+ return /* @__PURE__ */ jsxs28(LineGraph__Root, { className, style: { height }, children: [
4277
+ /* @__PURE__ */ jsxs28(
4135
4278
  "svg",
4136
4279
  {
4137
4280
  viewBox: `0 0 ${VIEW_W} ${VIEW_H}`,
@@ -4142,7 +4285,7 @@ function LineGraph({
4142
4285
  "aria-label": chartLabel,
4143
4286
  "aria-hidden": ariaLabel ? void 0 : "true",
4144
4287
  children: [
4145
- !isSparkline && [0.25, 0.5, 0.75].map((f) => /* @__PURE__ */ jsx39(
4288
+ !isSparkline && [0.25, 0.5, 0.75].map((f) => /* @__PURE__ */ jsx40(
4146
4289
  "line",
4147
4290
  {
4148
4291
  x1: 0,
@@ -4156,8 +4299,9 @@ function LineGraph({
4156
4299
  f
4157
4300
  )),
4158
4301
  isSparkline && series.map((s, si) => {
4159
- if (s.points.length < 2) return null;
4160
- return splitAtBreaks(tagged[si], s.breaks).map((run) => {
4302
+ if (s.points.length < 2 || s.interpolation === "none") return null;
4303
+ return splitAtBreaks(tagged[si], s.breaks).map((unstepped) => {
4304
+ const run = s.interpolation === "step" ? stepped(unstepped) : unstepped;
4161
4305
  if (run.length < 2) return null;
4162
4306
  const first = run[0];
4163
4307
  const last = run[run.length - 1];
@@ -4166,7 +4310,7 @@ function LineGraph({
4166
4310
  `${toX(last.x)},${VIEW_H}`,
4167
4311
  `${toX(first.x)},${VIEW_H}`
4168
4312
  ].join(" ");
4169
- return /* @__PURE__ */ jsx39(
4313
+ return /* @__PURE__ */ jsx40(
4170
4314
  "polygon",
4171
4315
  {
4172
4316
  points: areaPoints,
@@ -4182,7 +4326,7 @@ function LineGraph({
4182
4326
  (s) => (s.reckoned ?? []).map((run, ri) => {
4183
4327
  const corners = bandCorners(s, run, toX, toY);
4184
4328
  if (corners === null) return null;
4185
- return /* @__PURE__ */ jsx39(
4329
+ return /* @__PURE__ */ jsx40(
4186
4330
  "polygon",
4187
4331
  {
4188
4332
  points: corners,
@@ -4195,7 +4339,7 @@ function LineGraph({
4195
4339
  );
4196
4340
  })
4197
4341
  ),
4198
- thresholdStyle === "full" && thresholds.map((t) => /* @__PURE__ */ jsx39(
4342
+ thresholdStyle === "full" && thresholds.map((t) => /* @__PURE__ */ jsx40(
4199
4343
  "line",
4200
4344
  {
4201
4345
  x1: 0,
@@ -4209,13 +4353,31 @@ function LineGraph({
4209
4353
  },
4210
4354
  t.id
4211
4355
  )),
4356
+ series.map((s) => {
4357
+ if (s.interpolation !== "none") return null;
4358
+ return s.points.map((p) => /* @__PURE__ */ jsx40(
4359
+ "line",
4360
+ {
4361
+ x1: toX(p.x),
4362
+ x2: toX(p.x),
4363
+ y1: toY(p.y),
4364
+ y2: toY(p.y),
4365
+ stroke: s.color,
4366
+ strokeWidth: isSparkline ? 3 : 4,
4367
+ strokeLinecap: "round",
4368
+ vectorEffect: "non-scaling-stroke"
4369
+ },
4370
+ `${s.id}-mark-${p.x}`
4371
+ ));
4372
+ }),
4212
4373
  series.map((s, si) => {
4213
- if (s.points.length < 2) return null;
4374
+ if (s.points.length < 2 || s.interpolation === "none") return null;
4214
4375
  return splitAtBreaks(tagged[si], s.breaks).flatMap(
4215
4376
  (run) => splitAtBasis(run).map((piece) => {
4216
4377
  if (piece.points.length < 2) return null;
4217
- const points = piece.points.map((p) => `${toX(p.x)},${toY(p.y)}`).join(" ");
4218
- return /* @__PURE__ */ jsx39(
4378
+ const drawn = s.interpolation === "step" ? stepped(piece.points) : piece.points;
4379
+ const points = drawn.map((p) => `${toX(p.x)},${toY(p.y)}`).join(" ");
4380
+ return /* @__PURE__ */ jsx40(
4219
4381
  "polyline",
4220
4382
  {
4221
4383
  points,
@@ -4240,7 +4402,7 @@ function LineGraph({
4240
4402
  thresholdStyle === "marker" && thresholds.map((t) => {
4241
4403
  const topPct = (yMax - t.value) / ySpan * 100;
4242
4404
  if (topPct < 0 || topPct > 100) return null;
4243
- return /* @__PURE__ */ jsxs27(
4405
+ return /* @__PURE__ */ jsxs28(
4244
4406
  LineGraph__ThresholdMarker,
4245
4407
  {
4246
4408
  "aria-hidden": "true",
@@ -4250,8 +4412,8 @@ function LineGraph({
4250
4412
  color: t.color ?? "var(--color-warn-text)"
4251
4413
  },
4252
4414
  children: [
4253
- /* @__PURE__ */ jsx39(LineGraph__ThresholdTick, {}),
4254
- t.valueText !== void 0 && /* @__PURE__ */ jsx39("span", { children: t.valueText })
4415
+ /* @__PURE__ */ jsx40(LineGraph__ThresholdTick, {}),
4416
+ t.valueText !== void 0 && /* @__PURE__ */ jsx40("span", { children: t.valueText })
4255
4417
  ]
4256
4418
  },
4257
4419
  t.id
@@ -4259,7 +4421,7 @@ function LineGraph({
4259
4421
  })
4260
4422
  ] });
4261
4423
  }
4262
- var LineGraph__ThresholdMarker = styled36.div`
4424
+ var LineGraph__ThresholdMarker = styled37.div`
4263
4425
  position: absolute;
4264
4426
  left: 0;
4265
4427
  transform: translateY(-50%);
@@ -4272,14 +4434,14 @@ var LineGraph__ThresholdMarker = styled36.div`
4272
4434
  /* Single-glyph chrome text centring against a 2px tick: the flush rung. */
4273
4435
  line-height: var(--line-height-flush);
4274
4436
  `;
4275
- var LineGraph__ThresholdTick = styled36.span`
4437
+ var LineGraph__ThresholdTick = styled37.span`
4276
4438
  display: inline-block;
4277
4439
  width: var(--size-mark);
4278
4440
  height: 2px;
4279
4441
  border-radius: var(--radius-pill);
4280
4442
  background: currentColor;
4281
4443
  `;
4282
- var LineGraph__Root = styled36.div`
4444
+ var LineGraph__Root = styled37.div`
4283
4445
  position: relative;
4284
4446
  width: 100%;
4285
4447
  min-height: 0;
@@ -4292,19 +4454,19 @@ var LineGraph__Root = styled36.div`
4292
4454
  // src/LockMark.tsx
4293
4455
  import { isLocked } from "@ksp-gonogo/sitrep-sdk";
4294
4456
  import { lockSentence } from "@ksp-gonogo/sitrep-sdk/spine";
4295
- import styled37 from "styled-components";
4296
- import { jsx as jsx40, jsxs as jsxs28 } from "react/jsx-runtime";
4457
+ import styled38 from "styled-components";
4458
+ import { jsx as jsx41, jsxs as jsxs29 } from "react/jsx-runtime";
4297
4459
  function LockMark({ lock: given }) {
4298
4460
  const lock = isLocked(given) ? summaryOf(given) : given;
4299
4461
  const sentence = lock.hint === void 0 ? lock.reason : `${lock.reason}. ${lock.hint}`;
4300
- return /* @__PURE__ */ jsx40(Tooltip, { text: sentence, focusable: true, children: /* @__PURE__ */ jsxs28(LockMark__Body, { role: "status", "aria-label": sentence, children: [
4301
- /* @__PURE__ */ jsx40(LockIcon, {}),
4302
- /* @__PURE__ */ jsx40(LockMark__Name, { children: missingNames(lock) })
4462
+ return /* @__PURE__ */ jsx41(Tooltip, { text: sentence, focusable: true, children: /* @__PURE__ */ jsxs29(LockMark__Body, { role: "status", "aria-label": sentence, children: [
4463
+ /* @__PURE__ */ jsx41(LockIcon, {}),
4464
+ /* @__PURE__ */ jsx41(LockMark__Name, { children: missingNames(lock) })
4303
4465
  ] }) });
4304
4466
  }
4305
- function summaryOf(value4) {
4467
+ function summaryOf(value5) {
4306
4468
  const locks = [
4307
- { capability: { kind: "topic", id: "" }, missing: value4.locked }
4469
+ { capability: { kind: "topic", id: "" }, missing: value5.locked }
4308
4470
  ];
4309
4471
  return { ...lockSentence(locks, writeLockQuantity), locks };
4310
4472
  }
@@ -4314,7 +4476,7 @@ function missingNames(lock) {
4314
4476
  ];
4315
4477
  return names.length > 0 ? names.join(", ") : lock.reason;
4316
4478
  }
4317
- var LockMark__Body = styled37.span`
4479
+ var LockMark__Body = styled38.span`
4318
4480
  display: inline-flex;
4319
4481
  align-items: center;
4320
4482
  gap: var(--gap-figure-parts);
@@ -4326,7 +4488,7 @@ var LockMark__Body = styled37.span`
4326
4488
  letter-spacing: 0.06em;
4327
4489
  text-transform: uppercase;
4328
4490
  `;
4329
- var LockMark__Name = styled37.span`
4491
+ var LockMark__Name = styled38.span`
4330
4492
  min-width: 0;
4331
4493
  overflow: hidden;
4332
4494
  text-overflow: ellipsis;
@@ -4335,7 +4497,7 @@ var LockMark__Name = styled37.span`
4335
4497
 
4336
4498
  // src/MarkerIcons.tsx
4337
4499
  import { forwardRef as forwardRef3 } from "react";
4338
- import { Fragment as Fragment11, jsx as jsx41, jsxs as jsxs29 } from "react/jsx-runtime";
4500
+ import { Fragment as Fragment11, jsx as jsx42, jsxs as jsxs30 } from "react/jsx-runtime";
4339
4501
  var KEYLINE_EXTRA = 1.4;
4340
4502
  var DOT_RADIUS = 1.7;
4341
4503
  var DEFAULT_SIZE = "var(--icon-size-standalone)";
@@ -4431,7 +4593,7 @@ function Layer({
4431
4593
  strokeWidth,
4432
4594
  dotRadius
4433
4595
  }) {
4434
- return /* @__PURE__ */ jsxs29(
4596
+ return /* @__PURE__ */ jsxs30(
4435
4597
  "g",
4436
4598
  {
4437
4599
  fill: "none",
@@ -4440,8 +4602,8 @@ function Layer({
4440
4602
  strokeLinecap: "round",
4441
4603
  strokeLinejoin: "round",
4442
4604
  children: [
4443
- shape.paths.map((d) => /* @__PURE__ */ jsx41("path", { d }, d)),
4444
- shape.dot && /* @__PURE__ */ jsx41(
4605
+ shape.paths.map((d) => /* @__PURE__ */ jsx42("path", { d }, d)),
4606
+ shape.dot && /* @__PURE__ */ jsx42(
4445
4607
  "circle",
4446
4608
  {
4447
4609
  cx: shape.dot[0],
@@ -4473,8 +4635,8 @@ function makeMarker(id, displayName) {
4473
4635
  viewBox: "0 0 24 24",
4474
4636
  "data-marker": id
4475
4637
  };
4476
- const layers = /* @__PURE__ */ jsxs29(Fragment11, { children: [
4477
- /* @__PURE__ */ jsx41(
4638
+ const layers = /* @__PURE__ */ jsxs30(Fragment11, { children: [
4639
+ /* @__PURE__ */ jsx42(
4478
4640
  Layer,
4479
4641
  {
4480
4642
  shape,
@@ -4483,7 +4645,7 @@ function makeMarker(id, displayName) {
4483
4645
  dotRadius: DOT_RADIUS + KEYLINE_EXTRA / 2
4484
4646
  }
4485
4647
  ),
4486
- /* @__PURE__ */ jsx41(
4648
+ /* @__PURE__ */ jsx42(
4487
4649
  Layer,
4488
4650
  {
4489
4651
  shape,
@@ -4493,7 +4655,7 @@ function makeMarker(id, displayName) {
4493
4655
  }
4494
4656
  )
4495
4657
  ] });
4496
- return label ? /* @__PURE__ */ jsx41("svg", { ...frame, role: "img", "aria-label": label, ...rest, children: layers }) : /* @__PURE__ */ jsx41("svg", { ...frame, "aria-hidden": "true", ...rest, children: layers });
4658
+ return label ? /* @__PURE__ */ jsx42("svg", { ...frame, role: "img", "aria-label": label, ...rest, children: layers }) : /* @__PURE__ */ jsx42("svg", { ...frame, "aria-hidden": "true", ...rest, children: layers });
4497
4659
  }
4498
4660
  );
4499
4661
  Marker.displayName = displayName;
@@ -4546,11 +4708,11 @@ import {
4546
4708
  useLayoutEffect as useLayoutEffect3,
4547
4709
  useRef as useRef11
4548
4710
  } from "react";
4549
- import styled39, { css as css10 } from "styled-components";
4711
+ import styled40, { css as css10 } from "styled-components";
4550
4712
 
4551
4713
  // src/BarTrack.tsx
4552
- import styled38 from "styled-components";
4553
- import { jsx as jsx42, jsxs as jsxs30 } from "react/jsx-runtime";
4714
+ import styled39 from "styled-components";
4715
+ import { jsx as jsx43, jsxs as jsxs31 } from "react/jsx-runtime";
4554
4716
  var TRACK_HEIGHT = "8px";
4555
4717
  function BarTrack({
4556
4718
  percent,
@@ -4561,8 +4723,8 @@ function BarTrack({
4561
4723
  children,
4562
4724
  ...rest
4563
4725
  }) {
4564
- return /* @__PURE__ */ jsxs30(BarTrack__Track, { "data-track-held": trackHeld ? "" : void 0, ...rest, children: [
4565
- percent !== null && /* @__PURE__ */ jsx42(
4726
+ return /* @__PURE__ */ jsxs31(BarTrack__Track, { "data-track-held": trackHeld ? "" : void 0, ...rest, children: [
4727
+ percent !== null && /* @__PURE__ */ jsx43(
4566
4728
  BarTrack__Fill,
4567
4729
  {
4568
4730
  $tone: tone,
@@ -4572,7 +4734,7 @@ function BarTrack({
4572
4734
  style: { width: `${percent}%` }
4573
4735
  }
4574
4736
  ),
4575
- trackHeld && /* @__PURE__ */ jsx42(
4737
+ trackHeld && /* @__PURE__ */ jsx43(
4576
4738
  BarTrack__Hatch,
4577
4739
  {
4578
4740
  "data-track-hatch": "",
@@ -4582,7 +4744,7 @@ function BarTrack({
4582
4744
  children
4583
4745
  ] });
4584
4746
  }
4585
- var BarTrack__Track = styled38.div`
4747
+ var BarTrack__Track = styled39.div`
4586
4748
  width: 100%;
4587
4749
  border-radius: var(--radius-pill);
4588
4750
  background: var(--color-surface-raised);
@@ -4592,7 +4754,7 @@ var BarTrack__Track = styled38.div`
4592
4754
  position: relative;
4593
4755
  height: ${TRACK_HEIGHT};
4594
4756
  `;
4595
- var BarTrack__Hatch = styled38.div`
4757
+ var BarTrack__Hatch = styled39.div`
4596
4758
  position: absolute;
4597
4759
  top: 0;
4598
4760
  right: 0;
@@ -4605,7 +4767,7 @@ var BarTrack__Hatch = styled38.div`
4605
4767
  opacity: 0.55;
4606
4768
  pointer-events: none;
4607
4769
  `;
4608
- var BarTrack__Fill = styled38.div`
4770
+ var BarTrack__Fill = styled39.div`
4609
4771
  height: 100%;
4610
4772
  border-radius: var(--radius-pill);
4611
4773
  transition: width var(--duration-slow) var(--ease-standard);
@@ -4619,10 +4781,10 @@ var BarTrack__Fill = styled38.div`
4619
4781
  `;
4620
4782
 
4621
4783
  // src/Meter.tsx
4622
- import { Fragment as Fragment12, jsx as jsx43, jsxs as jsxs31 } from "react/jsx-runtime";
4784
+ import { Fragment as Fragment12, jsx as jsx44, jsxs as jsxs32 } from "react/jsx-runtime";
4623
4785
  function Meter({
4624
4786
  label,
4625
- value: value4,
4787
+ value: value5,
4626
4788
  capacity,
4627
4789
  format,
4628
4790
  tone = "neutral",
@@ -4634,7 +4796,7 @@ function Meter({
4634
4796
  statement = false,
4635
4797
  ...rest
4636
4798
  }) {
4637
- const shown = unwrap(value4);
4799
+ const shown = unwrap(value5);
4638
4800
  const held = unwrap(capacity);
4639
4801
  const fraction = fillFraction(
4640
4802
  shown.figure,
@@ -4642,14 +4804,14 @@ function Meter({
4642
4804
  );
4643
4805
  if (fraction === null || !Number.isFinite(fraction)) {
4644
4806
  if (hideLabel) return null;
4645
- return /* @__PURE__ */ jsx43(
4807
+ return /* @__PURE__ */ jsx44(
4646
4808
  MeterFrame,
4647
4809
  {
4648
4810
  layout,
4649
4811
  label,
4650
- display: /* @__PURE__ */ jsx43(NullValue, {}),
4812
+ display: /* @__PURE__ */ jsx44(NullValue, {}),
4651
4813
  ...rest,
4652
- children: /* @__PURE__ */ jsx43(BarTrack, { percent: null, tone, "aria-hidden": "true" })
4814
+ children: /* @__PURE__ */ jsx44(BarTrack, { percent: null, tone, "aria-hidden": "true" })
4653
4815
  }
4654
4816
  );
4655
4817
  }
@@ -4672,11 +4834,11 @@ function Meter({
4672
4834
  boundsOn(held.reading, held.figure, held.figure)
4673
4835
  );
4674
4836
  if (capacity !== void 0) {
4675
- return /* @__PURE__ */ jsx43(UnitSharedFormat, { of: shown.figure?.unit, format, children: /* @__PURE__ */ jsx43(
4837
+ return /* @__PURE__ */ jsx44(UnitSharedFormat, { of: shown.figure?.unit, format, children: /* @__PURE__ */ jsx44(
4676
4838
  MeterPairBar,
4677
4839
  {
4678
4840
  ...bar,
4679
- value: value4,
4841
+ value: value5,
4680
4842
  capacity,
4681
4843
  shown,
4682
4844
  held,
@@ -4691,15 +4853,15 @@ function Meter({
4691
4853
  clamped,
4692
4854
  boundsOn(shown.reading, shown.figure, null)
4693
4855
  );
4694
- return /* @__PURE__ */ jsx43(
4856
+ return /* @__PURE__ */ jsx44(
4695
4857
  MeterBar,
4696
4858
  {
4697
4859
  ...bar,
4698
4860
  bounds,
4699
4861
  endBounds,
4700
- display: valueLabelNode ?? (valueLabel === void 0 ? /* @__PURE__ */ jsx43(Unit, { value: value4, format }) : /* @__PURE__ */ jsx43(HeldLabel, { caption: heldCaption(value4), children: valueLabel })),
4862
+ display: valueLabelNode ?? (valueLabel === void 0 ? /* @__PURE__ */ jsx44(Unit, { value: value5, format }) : /* @__PURE__ */ jsx44(HeldLabel, { caption: heldCaption(value5), children: valueLabel })),
4701
4863
  spoken: withBands(
4702
- valueLabel === void 0 ? speakQuantity(shown.figure, { format }) : sayCaption(valueLabel, heldCaption(value4)),
4864
+ valueLabel === void 0 ? speakQuantity(shown.figure, { format }) : sayCaption(valueLabel, heldCaption(value5)),
4703
4865
  bounds,
4704
4866
  endBounds
4705
4867
  )
@@ -4717,8 +4879,8 @@ function HeldLabel({
4717
4879
  caption,
4718
4880
  children
4719
4881
  }) {
4720
- if (caption === null) return /* @__PURE__ */ jsx43(Fragment12, { children });
4721
- return /* @__PURE__ */ jsx43(HeldFigure, { caption, children });
4882
+ if (caption === null) return /* @__PURE__ */ jsx44(Fragment12, { children });
4883
+ return /* @__PURE__ */ jsx44(HeldFigure, { caption, children });
4722
4884
  }
4723
4885
  function unwrap(input) {
4724
4886
  if (typeof input !== "object" || input === null || !("state" in input)) {
@@ -4760,7 +4922,7 @@ function withBands(spoken, bounds, endBounds, shared) {
4760
4922
  const said = (bound, lead) => {
4761
4923
  const lo = speakQuantity(bound.loSaid, shared);
4762
4924
  const hi = speakQuantity(bound.hiSaid, shared);
4763
- return bandClaim(bound.kind, `${lead}with bands at ${lo} and ${hi}`);
4925
+ return `${lead}with bands at ${lo} and ${hi}`;
4764
4926
  };
4765
4927
  const clauses = [
4766
4928
  bounds === null ? null : said(bounds, ""),
@@ -4794,7 +4956,7 @@ function MeterBar({
4794
4956
  endBounds,
4795
4957
  ...rest
4796
4958
  }) {
4797
- return /* @__PURE__ */ jsxs31(
4959
+ return /* @__PURE__ */ jsxs32(
4798
4960
  MeterFrame,
4799
4961
  {
4800
4962
  layout,
@@ -4804,7 +4966,7 @@ function MeterBar({
4804
4966
  statement,
4805
4967
  ...rest,
4806
4968
  children: [
4807
- /* @__PURE__ */ jsx43(
4969
+ /* @__PURE__ */ jsx44(
4808
4970
  BarTrack,
4809
4971
  {
4810
4972
  percent: pct,
@@ -4820,14 +4982,14 @@ function MeterBar({
4820
4982
  "aria-valuetext": spoken
4821
4983
  }
4822
4984
  ),
4823
- (bounds !== null || endBounds !== null) && /* @__PURE__ */ jsxs31(Meter__Marks, { "aria-hidden": "true", children: [
4824
- bounds !== null && /* @__PURE__ */ jsxs31(Fragment12, { children: [
4825
- /* @__PURE__ */ jsx43(Meter__Bound, { "data-bound": "lo", ...markAt(bounds.lo) }),
4826
- /* @__PURE__ */ jsx43(Meter__Bound, { "data-bound": "hi", ...markAt(bounds.hi) })
4985
+ (bounds !== null || endBounds !== null) && /* @__PURE__ */ jsxs32(Meter__Marks, { "aria-hidden": "true", children: [
4986
+ bounds !== null && /* @__PURE__ */ jsxs32(Fragment12, { children: [
4987
+ /* @__PURE__ */ jsx44(Meter__Bound, { "data-bound": "lo", ...markAt(bounds.lo) }),
4988
+ /* @__PURE__ */ jsx44(Meter__Bound, { "data-bound": "hi", ...markAt(bounds.hi) })
4827
4989
  ] }),
4828
- endBounds !== null && /* @__PURE__ */ jsxs31(Fragment12, { children: [
4829
- /* @__PURE__ */ jsx43(Meter__Bound, { "data-end-bound": "lo", ...markAt(endBounds.lo) }),
4830
- /* @__PURE__ */ jsx43(Meter__Bound, { "data-end-bound": "hi", ...markAt(endBounds.hi) })
4990
+ endBounds !== null && /* @__PURE__ */ jsxs32(Fragment12, { children: [
4991
+ /* @__PURE__ */ jsx44(Meter__Bound, { "data-end-bound": "lo", ...markAt(endBounds.lo) }),
4992
+ /* @__PURE__ */ jsx44(Meter__Bound, { "data-end-bound": "hi", ...markAt(endBounds.hi) })
4831
4993
  ] })
4832
4994
  ] })
4833
4995
  ]
@@ -4844,28 +5006,28 @@ function MeterFrame({
4844
5006
  ...rest
4845
5007
  }) {
4846
5008
  if (hideHead) {
4847
- return /* @__PURE__ */ jsxs31(Meter__Root, { $row: false, ...rest, children: [
4848
- /* @__PURE__ */ jsx43(Meter__Bar, { $row: false, children }),
4849
- statement && /* @__PURE__ */ jsx43(Meter__Statement, { "data-meter-part": "statement", children: display })
5009
+ return /* @__PURE__ */ jsxs32(Meter__Root, { $row: false, ...rest, children: [
5010
+ /* @__PURE__ */ jsx44(Meter__Bar, { $row: false, children }),
5011
+ statement && /* @__PURE__ */ jsx44(Meter__Statement, { "data-meter-part": "statement", children: display })
4850
5012
  ] });
4851
5013
  }
4852
5014
  if (layout === "row") {
4853
- return /* @__PURE__ */ jsxs31(Meter__Root, { $row: true, "data-meter-row": "", ...rest, children: [
4854
- /* @__PURE__ */ jsx43(Meter__Label, { "data-meter-part": "label", children: label }),
4855
- /* @__PURE__ */ jsx43(Meter__Bar, { $row: true, "data-meter-part": "bar", children }),
4856
- /* @__PURE__ */ jsx43(Meter__Value, { $row: true, "data-meter-part": "figure", children: display })
5015
+ return /* @__PURE__ */ jsxs32(Meter__Root, { $row: true, "data-meter-row": "", ...rest, children: [
5016
+ /* @__PURE__ */ jsx44(Meter__Label, { "data-meter-part": "label", children: label }),
5017
+ /* @__PURE__ */ jsx44(Meter__Bar, { $row: true, "data-meter-part": "bar", children }),
5018
+ /* @__PURE__ */ jsx44(Meter__Value, { $row: true, "data-meter-part": "figure", children: display })
4857
5019
  ] });
4858
5020
  }
4859
- return /* @__PURE__ */ jsxs31(Meter__Root, { $row: false, ...rest, children: [
4860
- /* @__PURE__ */ jsxs31(Meter__Head, { children: [
4861
- /* @__PURE__ */ jsx43(Meter__Label, { children: label }),
4862
- /* @__PURE__ */ jsx43(Meter__Value, { $row: false, children: display })
5021
+ return /* @__PURE__ */ jsxs32(Meter__Root, { $row: false, ...rest, children: [
5022
+ /* @__PURE__ */ jsxs32(Meter__Head, { children: [
5023
+ /* @__PURE__ */ jsx44(Meter__Label, { children: label }),
5024
+ /* @__PURE__ */ jsx44(Meter__Value, { $row: false, children: display })
4863
5025
  ] }),
4864
- /* @__PURE__ */ jsx43(Meter__Bar, { $row: false, children })
5026
+ /* @__PURE__ */ jsx44(Meter__Bar, { $row: false, children })
4865
5027
  ] });
4866
5028
  }
4867
5029
  function MeterPairBar({
4868
- value: value4,
5030
+ value: value5,
4869
5031
  capacity,
4870
5032
  shown,
4871
5033
  held,
@@ -4878,23 +5040,23 @@ function MeterPairBar({
4878
5040
  const fromValue = useSharedFormat(reporting ? shown.figure : void 0);
4879
5041
  const fromCapacity = useSharedFormat(reporting ? held.figure : void 0);
4880
5042
  const shared = fromValue ?? fromCapacity ?? {};
4881
- const caption = heldCaption(value4) ?? heldCaption(capacity);
4882
- const display = valueLabelNode ?? (valueLabel !== void 0 ? /* @__PURE__ */ jsx43(HeldLabel, { caption, children: valueLabel }) : bar.layout === "row" ? /* @__PURE__ */ jsxs31(Meter__Pair, { $marked: bar.fillHeld || bar.trackHeld, children: [
4883
- /* @__PURE__ */ jsx43(Unit, { value: value4, hideUnitInGroup: true }),
5043
+ const caption = heldCaption(value5) ?? heldCaption(capacity);
5044
+ const display = valueLabelNode ?? (valueLabel !== void 0 ? /* @__PURE__ */ jsx44(HeldLabel, { caption, children: valueLabel }) : bar.layout === "row" ? /* @__PURE__ */ jsxs32(Meter__Pair, { $marked: bar.fillHeld || bar.trackHeld, children: [
5045
+ /* @__PURE__ */ jsx44(Unit, { value: value5, hideUnitInGroup: true }),
4884
5046
  " / ",
4885
- /* @__PURE__ */ jsx43(Unit, { value: capacity }),
4886
- (bar.fillHeld || bar.trackHeld) && /* @__PURE__ */ jsx43(HeldMark, { "aria-hidden": "true", "data-held-mark": "" })
4887
- ] }) : /* @__PURE__ */ jsxs31(Fragment12, { children: [
4888
- /* @__PURE__ */ jsx43(Unit, { value: value4 }),
5047
+ /* @__PURE__ */ jsx44(Unit, { value: capacity }),
5048
+ (bar.fillHeld || bar.trackHeld) && /* @__PURE__ */ jsx44(HeldMark, { "aria-hidden": "true", "data-held-mark": "" })
5049
+ ] }) : /* @__PURE__ */ jsxs32(Fragment12, { children: [
5050
+ /* @__PURE__ */ jsx44(Unit, { value: value5 }),
4889
5051
  " / ",
4890
- /* @__PURE__ */ jsx43(Unit, { value: capacity })
5052
+ /* @__PURE__ */ jsx44(Unit, { value: capacity })
4891
5053
  ] }));
4892
5054
  const spoken = valueLabel === void 0 ? `${speakQuantity(shown.figure, shared)} of ${speakQuantity(held.figure, shared)}` : sayCaption(valueLabel, caption);
4893
5055
  const bounds = apartFrom(
4894
5056
  at,
4895
5057
  boundsOn(shown.reading, shown.figure, held.figure)
4896
5058
  );
4897
- return /* @__PURE__ */ jsx43(
5059
+ return /* @__PURE__ */ jsx44(
4898
5060
  MeterBar,
4899
5061
  {
4900
5062
  ...bar,
@@ -4917,7 +5079,12 @@ function MeterStack({
4917
5079
  if (stack.clientWidth === 0) return;
4918
5080
  stack.toggleAttribute("data-figures-below", !figuresFitBeside(stack));
4919
5081
  };
4920
- const resize = new ResizeObserver(place2);
5082
+ let frame = 0;
5083
+ const placeNextFrame = () => {
5084
+ cancelAnimationFrame(frame);
5085
+ frame = requestAnimationFrame(place2);
5086
+ };
5087
+ const resize = new ResizeObserver(placeNextFrame);
4921
5088
  const watch = () => {
4922
5089
  resize.disconnect();
4923
5090
  resize.observe(stack);
@@ -4928,13 +5095,14 @@ function MeterStack({
4928
5095
  watch();
4929
5096
  place2();
4930
5097
  return () => {
5098
+ cancelAnimationFrame(frame);
4931
5099
  resize.disconnect();
4932
5100
  rows.disconnect();
4933
5101
  };
4934
5102
  }, []);
4935
- return /* @__PURE__ */ jsx43(Meter__Stack, { ref, ...rest, children });
5103
+ return /* @__PURE__ */ jsx44(Meter__Stack, { ref, ...rest, children });
4936
5104
  }
4937
- var MeterRowGroup = styled39.div.attrs({
5105
+ var MeterRowGroup = styled40.div.attrs({
4938
5106
  "data-meter-row-group": ""
4939
5107
  })`
4940
5108
  grid-column: 1 / -1;
@@ -4980,7 +5148,7 @@ function unwrappedWidth(label) {
4980
5148
  label.style.whiteSpace = before;
4981
5149
  return width;
4982
5150
  }
4983
- var Meter__Stack = styled39.div`
5151
+ var Meter__Stack = styled40.div`
4984
5152
  display: grid;
4985
5153
  grid-template-columns:
4986
5154
  minmax(min-content, max-content)
@@ -5029,7 +5197,7 @@ var Meter__Stack = styled39.div`
5029
5197
  }
5030
5198
  `;
5031
5199
  var MARK_INSET = "1px";
5032
- var Meter__Root = styled39.div`
5200
+ var Meter__Root = styled40.div`
5033
5201
  display: flex;
5034
5202
  width: 100%;
5035
5203
  min-width: 0;
@@ -5044,7 +5212,7 @@ var Meter__Root = styled39.div`
5044
5212
  gap: var(--gap-caption);
5045
5213
  `}
5046
5214
  `;
5047
- var Meter__Head = styled39.div`
5215
+ var Meter__Head = styled40.div`
5048
5216
  display: flex;
5049
5217
  justify-content: space-between;
5050
5218
  align-items: baseline;
@@ -5053,7 +5221,7 @@ var Meter__Head = styled39.div`
5053
5221
  /* The value may drop to its own line at narrow widths rather than crushing the label. */
5054
5222
  flex-wrap: wrap;
5055
5223
  `;
5056
- var Meter__Label = styled39.span`
5224
+ var Meter__Label = styled40.span`
5057
5225
  font-size: var(--font-size-caption);
5058
5226
  color: var(--color-text-muted);
5059
5227
  text-transform: uppercase;
@@ -5065,7 +5233,7 @@ var Meter__Label = styled39.span`
5065
5233
  flex: 0 0 auto;
5066
5234
  max-width: 100%;
5067
5235
  `;
5068
- var Meter__Value = styled39.span`
5236
+ var Meter__Value = styled40.span`
5069
5237
  font-size: ${({ $row }) => $row ? "var(--font-size-compact)" : "var(--font-size-value)"};
5070
5238
  color: var(--color-text-primary);
5071
5239
  font-variant-numeric: tabular-nums;
@@ -5079,7 +5247,7 @@ var Meter__Value = styled39.span`
5079
5247
  /* Room for the held mark Unit draws outside this box, reserved unconditionally so a quiet channel causes no reflow. */
5080
5248
  padding-right: max(0.44em, var(--inset-meter-mark));
5081
5249
  `;
5082
- var Meter__Statement = styled39.span`
5250
+ var Meter__Statement = styled40.span`
5083
5251
  font-size: var(--font-size-compact);
5084
5252
  color: var(--color-text-primary);
5085
5253
  font-variant-numeric: tabular-nums;
@@ -5088,19 +5256,19 @@ var Meter__Statement = styled39.span`
5088
5256
  text-overflow: ellipsis;
5089
5257
  white-space: nowrap;
5090
5258
  `;
5091
- var Meter__Marks = styled39.div`
5259
+ var Meter__Marks = styled40.div`
5092
5260
  position: absolute;
5093
5261
  inset: 0;
5094
5262
  pointer-events: none;
5095
5263
  `;
5096
- var Meter__Bar = styled39.div`
5264
+ var Meter__Bar = styled40.div`
5097
5265
  position: relative;
5098
5266
  ${({ $row }) => $row ? css10`
5099
5267
  flex: 1 1 28px;
5100
5268
  min-width: 28px;
5101
5269
  ` : ""}
5102
5270
  `;
5103
- var Meter__Pair = styled39(HeldHost)`
5271
+ var Meter__Pair = styled40(HeldHost)`
5104
5272
  /* The pair's own mark reserves the room; the figures inside it carry none. */
5105
5273
  &::after {
5106
5274
  content: ${({ $marked }) => $marked ? '""' : "none"};
@@ -5112,7 +5280,7 @@ var Meter__Pair = styled39(HeldHost)`
5112
5280
  content: none;
5113
5281
  }
5114
5282
  `;
5115
- var Meter__Bound = styled39.div`
5283
+ var Meter__Bound = styled40.div`
5116
5284
  position: absolute;
5117
5285
  top: ${MARK_INSET};
5118
5286
  bottom: ${MARK_INSET};
@@ -5127,8 +5295,8 @@ var Meter__Bound = styled39.div`
5127
5295
  `;
5128
5296
 
5129
5297
  // src/MissionDate.tsx
5130
- import styled40 from "styled-components";
5131
- import { Fragment as Fragment13, jsx as jsx44, jsxs as jsxs32 } from "react/jsx-runtime";
5298
+ import styled41 from "styled-components";
5299
+ import { Fragment as Fragment13, jsx as jsx45, jsxs as jsxs33 } from "react/jsx-runtime";
5132
5300
  function describeContext(context) {
5133
5301
  if (context.frame === "scet") {
5134
5302
  return {
@@ -5148,39 +5316,39 @@ function describeContext(context) {
5148
5316
  title: `When the telemetry showing this arrives at ${vantage}`
5149
5317
  };
5150
5318
  }
5151
- var MissionDate__Context = styled40.span`
5319
+ var MissionDate__Context = styled41.span`
5152
5320
  font-size: max(0.72em, 10px);
5153
5321
  opacity: 0.72;
5154
5322
  white-space: nowrap;
5155
5323
  text-transform: none;
5156
5324
  `;
5157
- function MissionDate({ value: value4, context }) {
5158
- const carried = typeof value4 === "number" ? void 0 : value4;
5325
+ function MissionDate({ value: value5, context }) {
5326
+ const carried = typeof value5 === "number" ? void 0 : value5;
5159
5327
  const currency = resolveCurrency(carried);
5160
5328
  const { shown, held, caption } = currency;
5161
- const ut = typeof value4 === "number" ? value4 : shown?.magnitude;
5329
+ const ut = typeof value5 === "number" ? value5 : shown?.magnitude;
5162
5330
  const figure = figureAttributes({ ...currency, shown: ut });
5163
5331
  const qualifier = context && describeContext(context);
5164
5332
  const date = formatKspDate(ut ?? Number.NaN);
5165
- return /* @__PURE__ */ jsxs32(Fragment13, { children: [
5333
+ return /* @__PURE__ */ jsxs33(Fragment13, { children: [
5166
5334
  held ? (
5167
5335
  /* The component otherwise renders bare text, so the mark needs a box to hang off. */
5168
- /* @__PURE__ */ jsx44(HeldFigure, { ...figure, caption, children: date })
5169
- ) : /* @__PURE__ */ jsx44("span", { "data-figure": figure["data-figure"], children: date }),
5170
- qualifier && /* @__PURE__ */ jsxs32(Fragment13, { children: [
5336
+ /* @__PURE__ */ jsx45(HeldFigure, { ...figure, caption, children: date })
5337
+ ) : /* @__PURE__ */ jsx45("span", { "data-figure": figure["data-figure"], children: date }),
5338
+ qualifier && /* @__PURE__ */ jsxs33(Fragment13, { children: [
5171
5339
  " ",
5172
- /* @__PURE__ */ jsx44(Tooltip, { text: qualifier.title, focusable: true, children: /* @__PURE__ */ jsxs32(MissionDate__Context, { children: [
5173
- /* @__PURE__ */ jsx44("span", { "aria-hidden": "true", children: qualifier.token }),
5174
- /* @__PURE__ */ jsx44(VisuallyHidden, { children: qualifier.spoken })
5340
+ /* @__PURE__ */ jsx45(Tooltip, { text: qualifier.title, focusable: true, children: /* @__PURE__ */ jsxs33(MissionDate__Context, { children: [
5341
+ /* @__PURE__ */ jsx45("span", { "aria-hidden": "true", children: qualifier.token }),
5342
+ /* @__PURE__ */ jsx45(VisuallyHidden, { children: qualifier.spoken })
5175
5343
  ] }) })
5176
5344
  ] })
5177
5345
  ] });
5178
5346
  }
5179
5347
 
5180
5348
  // src/MissionDateField.tsx
5181
- import { value as value2 } from "@ksp-gonogo/sitrep-sdk";
5349
+ import { value as value3 } from "@ksp-gonogo/sitrep-sdk";
5182
5350
  import { useId as useId10, useState as useState13 } from "react";
5183
- import { jsx as jsx45, jsxs as jsxs33 } from "react/jsx-runtime";
5351
+ import { jsx as jsx46, jsxs as jsxs34 } from "react/jsx-runtime";
5184
5352
  function partsOfUt(ut) {
5185
5353
  const { year: YEAR, day: DAY, hour: HOUR, minute: MINUTE } = kspCalendar();
5186
5354
  const clamped = Number.isFinite(ut) ? Math.max(0, ut) : 0;
@@ -5208,10 +5376,10 @@ function utOfParts(parts) {
5208
5376
  return (parts.year - 1) * YEAR + (parts.day - 1) * DAY + parts.hour * HOUR + parts.minute * MINUTE + parts.second;
5209
5377
  }
5210
5378
  function stepLabel(seconds) {
5211
- return writeQuantity(value2("s", seconds));
5379
+ return writeQuantity(value3("s", seconds));
5212
5380
  }
5213
5381
  function MissionDateField({
5214
- value: value4,
5382
+ value: value5,
5215
5383
  onChange,
5216
5384
  label,
5217
5385
  disabled,
@@ -5219,7 +5387,7 @@ function MissionDateField({
5219
5387
  }) {
5220
5388
  const groupId = useId10();
5221
5389
  const absentId = `${groupId}-absent`;
5222
- const instant = value4 !== null && Number.isFinite(value4) ? value4 : null;
5390
+ const instant = value5 !== null && Number.isFinite(value5) ? value5 : null;
5223
5391
  const parts = instant === null ? null : partsOfUt(instant);
5224
5392
  const calendar = kspCalendar();
5225
5393
  const coarse = steps ?? [
@@ -5229,9 +5397,9 @@ function MissionDateField({
5229
5397
  calendar.day
5230
5398
  ];
5231
5399
  const [draft, setDraft] = useState13(null);
5232
- const field = (key, text, min, width) => /* @__PURE__ */ jsxs33(Stack, { gap: "caption", children: [
5233
- /* @__PURE__ */ jsx45(FieldLabel, { htmlFor: `${groupId}-${key}`, children: text }),
5234
- /* @__PURE__ */ jsx45(
5400
+ const field = (key, text, min, width) => /* @__PURE__ */ jsxs34(Stack, { gap: "caption", children: [
5401
+ /* @__PURE__ */ jsx46(FieldLabel, { htmlFor: `${groupId}-${key}`, children: text }),
5402
+ /* @__PURE__ */ jsx46(
5235
5403
  Input,
5236
5404
  {
5237
5405
  id: `${groupId}-${key}`,
@@ -5257,18 +5425,18 @@ function MissionDateField({
5257
5425
  }
5258
5426
  )
5259
5427
  ] }, key);
5260
- return /* @__PURE__ */ jsxs33(Stack, { gap: "related-dense", role: "group", "aria-label": label, children: [
5261
- /* @__PURE__ */ jsxs33(Cluster, { gap: "related-dense", wrap: true, justify: "start", children: [
5428
+ return /* @__PURE__ */ jsxs34(Stack, { gap: "related-dense", role: "group", "aria-label": label, children: [
5429
+ /* @__PURE__ */ jsxs34(Cluster, { gap: "related-dense", wrap: true, justify: "start", children: [
5262
5430
  field("year", "YEAR", 1, "5rem"),
5263
5431
  field("day", "DAY", 1, "5rem"),
5264
5432
  field("hour", "HR", 0, "4rem"),
5265
5433
  field("minute", "MIN", 0, "4rem"),
5266
5434
  field("second", "SEC", 0, "4rem")
5267
5435
  ] }),
5268
- parts === null && /* @__PURE__ */ jsx45(Text, { id: absentId, level: "muted", size: "sm", children: `${NULL_DISPLAY} no ${label.toLowerCase()} to show. Type one to state it.` }),
5269
- coarse.length === 0 ? null : /* @__PURE__ */ jsxs33(Cluster, { gap: "related-packed", wrap: true, justify: "start", children: [
5270
- /* @__PURE__ */ jsx45(Text, { level: "faint", size: "sm", children: "NUDGE" }),
5271
- coarse.map((step) => /* @__PURE__ */ jsx45(
5436
+ parts === null && /* @__PURE__ */ jsx46(Text, { id: absentId, level: "muted", size: "sm", children: `${NULL_DISPLAY} no ${label.toLowerCase()} to show. Type one to state it.` }),
5437
+ coarse.length === 0 ? null : /* @__PURE__ */ jsxs34(Cluster, { gap: "related-packed", wrap: true, justify: "start", children: [
5438
+ /* @__PURE__ */ jsx46(Text, { level: "faint", size: "sm", children: "NUDGE" }),
5439
+ coarse.map((step) => /* @__PURE__ */ jsx46(
5272
5440
  Button,
5273
5441
  {
5274
5442
  variant: "ghost",
@@ -5280,7 +5448,7 @@ function MissionDateField({
5280
5448
  },
5281
5449
  `minus-${step}`
5282
5450
  )),
5283
- coarse.map((step) => /* @__PURE__ */ jsx45(
5451
+ coarse.map((step) => /* @__PURE__ */ jsx46(
5284
5452
  Button,
5285
5453
  {
5286
5454
  variant: "ghost",
@@ -5308,11 +5476,11 @@ import {
5308
5476
  useState as useState14
5309
5477
  } from "react";
5310
5478
  import { createPortal as createPortal2 } from "react-dom";
5311
- import styled41 from "styled-components";
5479
+ import styled42 from "styled-components";
5312
5480
 
5313
5481
  // src/ModalSaveBar.tsx
5314
5482
  import { createContext, useContext, useEffect as useEffect10, useMemo as useMemo2, useRef as useRef12 } from "react";
5315
- import { Fragment as Fragment14, jsx as jsx46, jsxs as jsxs34 } from "react/jsx-runtime";
5483
+ import { Fragment as Fragment14, jsx as jsx47, jsxs as jsxs35 } from "react/jsx-runtime";
5316
5484
  var ModalChromeContext = createContext(null);
5317
5485
  function useModalChrome(footer, dirty) {
5318
5486
  const ctx = useContext(ModalChromeContext);
@@ -5328,14 +5496,14 @@ function useModalChrome(footer, dirty) {
5328
5496
  }, [setDirty, dirty]);
5329
5497
  }
5330
5498
  function useModalSaveBar(options) {
5331
- const { onSave, value: value4, saved, saveLabel = "Save", extra, disabled } = options;
5499
+ const { onSave, value: value5, saved, saveLabel = "Save", extra, disabled } = options;
5332
5500
  const baselineRef = useRef12(null);
5333
- if (baselineRef.current === null) baselineRef.current = { v: value4 };
5334
- const dirty = !configEqual(value4, baselineRef.current.v) && !configEqual(value4, saved);
5501
+ if (baselineRef.current === null) baselineRef.current = { v: value5 };
5502
+ const dirty = !configEqual(value5, baselineRef.current.v) && !configEqual(value5, saved);
5335
5503
  const footer = useMemo2(
5336
- () => /* @__PURE__ */ jsxs34(Fragment14, { children: [
5504
+ () => /* @__PURE__ */ jsxs35(Fragment14, { children: [
5337
5505
  extra,
5338
- /* @__PURE__ */ jsx46(
5506
+ /* @__PURE__ */ jsx47(
5339
5507
  Button,
5340
5508
  {
5341
5509
  variant: "primary",
@@ -5352,7 +5520,7 @@ function useModalSaveBar(options) {
5352
5520
  }
5353
5521
 
5354
5522
  // src/Modal.tsx
5355
- import { Fragment as Fragment15, jsx as jsx47, jsxs as jsxs35 } from "react/jsx-runtime";
5523
+ import { Fragment as Fragment15, jsx as jsx48, jsxs as jsxs36 } from "react/jsx-runtime";
5356
5524
  var ModalContext = createContext2(null);
5357
5525
  var modalSeq = 0;
5358
5526
  function ModalProvider({ children }) {
@@ -5365,7 +5533,7 @@ function ModalProvider({ children }) {
5365
5533
  {
5366
5534
  id,
5367
5535
  title: options?.title,
5368
- ariaLabel: options?.ariaLabel,
5536
+ "aria-label": options?.["aria-label"],
5369
5537
  width: options?.width,
5370
5538
  content
5371
5539
  }
@@ -5377,10 +5545,10 @@ function ModalProvider({ children }) {
5377
5545
  const close = useCallback7((id) => {
5378
5546
  setModals((prev) => prev.filter((m) => m.id !== id));
5379
5547
  }, []);
5380
- const value4 = useMemo3(() => ({ open, close }), [open, close]);
5381
- return /* @__PURE__ */ jsxs35(ModalContext.Provider, { value: value4, children: [
5548
+ const value5 = useMemo3(() => ({ open, close }), [open, close]);
5549
+ return /* @__PURE__ */ jsxs36(ModalContext.Provider, { value: value5, children: [
5382
5550
  children,
5383
- modals.map((m, i) => /* @__PURE__ */ jsx47(
5551
+ modals.map((m, i) => /* @__PURE__ */ jsx48(
5384
5552
  ModalDialog,
5385
5553
  {
5386
5554
  entry: m,
@@ -5471,9 +5639,9 @@ function ModalDialog({ entry, isTop, onClose }) {
5471
5639
  if (!confirming) el.querySelector(FOCUSABLE)?.focus();
5472
5640
  return () => document.removeEventListener("keydown", handleTab);
5473
5641
  }, [confirming, footer]);
5474
- return /* @__PURE__ */ jsx47(Fragment15, { children: createPortal2(
5642
+ return /* @__PURE__ */ jsx48(Fragment15, { children: createPortal2(
5475
5643
  // Interactive, so it cannot also be role="presentation"; keyboard users close with Escape.
5476
- /* @__PURE__ */ jsx47(
5644
+ /* @__PURE__ */ jsx48(
5477
5645
  Backdrop,
5478
5646
  {
5479
5647
  onMouseDown: (e) => {
@@ -5485,30 +5653,30 @@ function ModalDialog({ entry, isTop, onClose }) {
5485
5653
  }
5486
5654
  downOnBackdropRef.current = false;
5487
5655
  },
5488
- children: /* @__PURE__ */ jsxs35(
5656
+ children: /* @__PURE__ */ jsxs36(
5489
5657
  Dialog,
5490
5658
  {
5491
5659
  ref: dialogRef,
5492
5660
  role: "dialog",
5493
5661
  "aria-modal": "true",
5494
5662
  "aria-labelledby": entry.title ? titleId : void 0,
5495
- "aria-label": entry.title ? void 0 : entry.ariaLabel,
5663
+ "aria-label": entry.title ? void 0 : entry["aria-label"],
5496
5664
  $width: entry.width,
5497
5665
  children: [
5498
- /* @__PURE__ */ jsxs35(DialogHeader, { children: [
5499
- entry.title && /* @__PURE__ */ jsx47(DialogTitle, { id: titleId, children: entry.title }),
5500
- /* @__PURE__ */ jsx47(CloseButton, { onClick: requestClose, "aria-label": "Close", children: /* @__PURE__ */ jsx47(CloseIcon, { size: 16 }) })
5666
+ /* @__PURE__ */ jsxs36(DialogHeader, { children: [
5667
+ entry.title && /* @__PURE__ */ jsx48(DialogTitle, { id: titleId, children: entry.title }),
5668
+ /* @__PURE__ */ jsx48(CloseButton, { onClick: requestClose, "aria-label": "Close", children: /* @__PURE__ */ jsx48(CloseIcon, { size: 16 }) })
5501
5669
  ] }),
5502
- /* @__PURE__ */ jsx47(DialogBody, { ref: setBody, tabIndex: bodyTabIndex, children: /* @__PURE__ */ jsx47(ModalChromeContext.Provider, { value: chrome, children: entry.content }) }),
5503
- footer && !confirming && /* @__PURE__ */ jsx47(DialogFooter, { children: footer }),
5504
- confirming && /* @__PURE__ */ jsxs35(
5670
+ /* @__PURE__ */ jsx48(DialogBody, { ref: setBody, tabIndex: bodyTabIndex, children: /* @__PURE__ */ jsx48(ModalChromeContext.Provider, { value: chrome, children: entry.content }) }),
5671
+ footer && !confirming && /* @__PURE__ */ jsx48(DialogFooter, { children: footer }),
5672
+ confirming && /* @__PURE__ */ jsxs36(
5505
5673
  DialogFooter,
5506
5674
  {
5507
5675
  role: "alertdialog",
5508
5676
  "aria-label": "Discard unsaved changes?",
5509
5677
  children: [
5510
- /* @__PURE__ */ jsx47(DiscardPrompt, { children: "Discard unsaved changes?" }),
5511
- /* @__PURE__ */ jsx47(
5678
+ /* @__PURE__ */ jsx48(DiscardPrompt, { children: "Discard unsaved changes?" }),
5679
+ /* @__PURE__ */ jsx48(
5512
5680
  Button,
5513
5681
  {
5514
5682
  variant: "ghost",
@@ -5517,7 +5685,7 @@ function ModalDialog({ entry, isTop, onClose }) {
5517
5685
  children: "Keep editing"
5518
5686
  }
5519
5687
  ),
5520
- /* @__PURE__ */ jsx47(
5688
+ /* @__PURE__ */ jsx48(
5521
5689
  Button,
5522
5690
  {
5523
5691
  variant: "primary",
@@ -5541,7 +5709,7 @@ function ModalDialog({ entry, isTop, onClose }) {
5541
5709
  document.body
5542
5710
  ) });
5543
5711
  }
5544
- var Backdrop = styled41.div`
5712
+ var Backdrop = styled42.div`
5545
5713
  position: fixed;
5546
5714
  inset: 0;
5547
5715
  background: rgba(0, 0, 0, 0.72);
@@ -5550,7 +5718,7 @@ var Backdrop = styled41.div`
5550
5718
  justify-content: center;
5551
5719
  z-index: var(--z-modal);
5552
5720
  `;
5553
- var Dialog = styled41.div`
5721
+ var Dialog = styled42.div`
5554
5722
  background: var(--color-surface-panel);
5555
5723
  border: 1px solid var(--color-border-strong);
5556
5724
  border-radius: var(--radius-floating);
@@ -5562,7 +5730,7 @@ var Dialog = styled41.div`
5562
5730
  flex-direction: column;
5563
5731
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.6);
5564
5732
  `;
5565
- var DialogHeader = styled41.div`
5733
+ var DialogHeader = styled42.div`
5566
5734
  display: flex;
5567
5735
  align-items: center;
5568
5736
  justify-content: space-between;
@@ -5570,11 +5738,11 @@ var DialogHeader = styled41.div`
5570
5738
  border-bottom: 1px solid var(--color-border-subtle);
5571
5739
  flex-shrink: 0;
5572
5740
  `;
5573
- var DialogTitle = styled41.h2`
5741
+ var DialogTitle = styled42.h2`
5574
5742
  margin: 0;
5575
5743
  ${titleText}
5576
5744
  `;
5577
- var CloseButton = styled41.button`
5745
+ var CloseButton = styled42.button`
5578
5746
  background: none;
5579
5747
  border: none;
5580
5748
  color: var(--color-text-faint);
@@ -5595,14 +5763,14 @@ var CloseButton = styled41.button`
5595
5763
  justify-content: center;
5596
5764
  }
5597
5765
  `;
5598
- var DialogBody = styled41.div`
5766
+ var DialogBody = styled42.div`
5599
5767
  padding: var(--inset-modal-body);
5600
5768
  overflow-y: auto;
5601
5769
  ${focusRingInset}
5602
5770
  -webkit-overflow-scrolling: touch;
5603
5771
  flex: 1;
5604
5772
  `;
5605
- var DialogFooter = styled41.div`
5773
+ var DialogFooter = styled42.div`
5606
5774
  display: flex;
5607
5775
  align-items: center;
5608
5776
  justify-content: flex-end;
@@ -5611,7 +5779,7 @@ var DialogFooter = styled41.div`
5611
5779
  border-top: 1px solid var(--color-border-subtle);
5612
5780
  flex-shrink: 0;
5613
5781
  `;
5614
- var DiscardPrompt = styled41.span`
5782
+ var DiscardPrompt = styled42.span`
5615
5783
  margin-right: auto;
5616
5784
  font-size: var(--font-size-compact);
5617
5785
  color: var(--color-text-primary);
@@ -5619,9 +5787,9 @@ var DiscardPrompt = styled41.span`
5619
5787
 
5620
5788
  // src/Notice.tsx
5621
5789
  import { useEffect as useEffect12, useRef as useRef14, useState as useState15 } from "react";
5622
- import styled42 from "styled-components";
5623
- import { Fragment as Fragment16, jsx as jsx48, jsxs as jsxs36 } from "react/jsx-runtime";
5624
- var Notice__Root = styled42(Block__Root)`
5790
+ import styled43 from "styled-components";
5791
+ import { Fragment as Fragment16, jsx as jsx49, jsxs as jsxs37 } from "react/jsx-runtime";
5792
+ var Notice__Root = styled43(Block__Root)`
5625
5793
  --gap-related: var(--gap-related-comfortable);
5626
5794
  --bleed-inline: 0px;
5627
5795
 
@@ -5664,9 +5832,9 @@ function Notice({
5664
5832
  $tone: tone
5665
5833
  });
5666
5834
  if (role !== void 0) return block;
5667
- return /* @__PURE__ */ jsxs36(Fragment16, { children: [
5835
+ return /* @__PURE__ */ jsxs37(Fragment16, { children: [
5668
5836
  block,
5669
- /* @__PURE__ */ jsx48(LiveRegion, { visuallyHidden: true, children: said })
5837
+ /* @__PURE__ */ jsx49(LiveRegion, { visuallyHidden: true, children: said })
5670
5838
  ] });
5671
5839
  }
5672
5840
  function spokenText(root) {
@@ -5678,25 +5846,407 @@ function spokenText(root) {
5678
5846
  return runs.join(" ").replace(/\s+/g, " ").trim();
5679
5847
  }
5680
5848
 
5849
+ // src/reckoningMarkDraw.tsx
5850
+ import { jsx as jsx50 } from "react/jsx-runtime";
5851
+ var HELD_SQUARE_HALF = 0.89;
5852
+ var GHOST_OPACITY = 0.45;
5853
+ function ReckoningMarkSvg({
5854
+ kind,
5855
+ x,
5856
+ y,
5857
+ scale = 1,
5858
+ ghost = false
5859
+ }) {
5860
+ const spec = RECKONING_MARK[kind];
5861
+ const r = spec.canvasRadius * scale;
5862
+ const common = {
5863
+ fill: spec.color,
5864
+ opacity: ghost ? GHOST_OPACITY : void 0,
5865
+ "data-reckoning-mark": kind,
5866
+ "aria-hidden": true
5867
+ };
5868
+ if (kind === "held") {
5869
+ const half = r * HELD_SQUARE_HALF;
5870
+ return /* @__PURE__ */ jsx50(
5871
+ "rect",
5872
+ {
5873
+ x: x - half,
5874
+ y: y - half,
5875
+ width: 2 * half,
5876
+ height: 2 * half,
5877
+ ...common
5878
+ }
5879
+ );
5880
+ }
5881
+ const points = `${x},${y - r} ${x + r},${y + r * 0.8} ${x - r},${y + r * 0.8}`;
5882
+ return /* @__PURE__ */ jsx50("polygon", { points, ...common });
5883
+ }
5884
+ function resolvedColor(canvas, cssVar, fallback) {
5885
+ const v = getComputedStyle(canvas).getPropertyValue(cssVar).trim();
5886
+ return v || fallback;
5887
+ }
5888
+ function paintReckoningMark(canvas, ctx, kind, x, y, { ghost = false, scale = 1 } = {}) {
5889
+ const spec = RECKONING_MARK[kind];
5890
+ const r = spec.canvasRadius * scale;
5891
+ ctx.save();
5892
+ ctx.globalAlpha = ghost ? GHOST_OPACITY : 1;
5893
+ ctx.fillStyle = resolvedColor(canvas, spec.cssVar, spec.fallback);
5894
+ ctx.beginPath();
5895
+ if (kind === "held") {
5896
+ const half = r * HELD_SQUARE_HALF;
5897
+ ctx.rect(x - half, y - half, 2 * half, 2 * half);
5898
+ } else {
5899
+ ctx.moveTo(x, y - r);
5900
+ ctx.lineTo(x + r, y + r * 0.8);
5901
+ ctx.lineTo(x - r, y + r * 0.8);
5902
+ ctx.closePath();
5903
+ }
5904
+ ctx.fill();
5905
+ ctx.restore();
5906
+ }
5907
+ function paintReckonedPosition(canvas, ctx, { held, modelled }, options = {}) {
5908
+ if (held !== void 0 && modelled !== void 0) {
5909
+ ctx.save();
5910
+ ctx.globalAlpha = GHOST_OPACITY;
5911
+ ctx.strokeStyle = resolvedColor(
5912
+ canvas,
5913
+ RECKONING_MARK.modelled.cssVar,
5914
+ RECKONING_MARK.modelled.fallback
5915
+ );
5916
+ ctx.lineWidth = 1;
5917
+ ctx.setLineDash([2, 3]);
5918
+ ctx.beginPath();
5919
+ ctx.moveTo(held.x, held.y);
5920
+ ctx.lineTo(modelled.x, modelled.y);
5921
+ ctx.stroke();
5922
+ ctx.restore();
5923
+ }
5924
+ if (held !== void 0) {
5925
+ paintReckoningMark(canvas, ctx, "held", held.x, held.y, {
5926
+ ...options,
5927
+ ghost: modelled !== void 0
5928
+ });
5929
+ }
5930
+ if (modelled !== void 0) {
5931
+ paintReckoningMark(
5932
+ canvas,
5933
+ ctx,
5934
+ "modelled",
5935
+ modelled.x,
5936
+ modelled.y,
5937
+ options
5938
+ );
5939
+ }
5940
+ }
5941
+
5942
+ // src/PlotCrosshair.tsx
5943
+ import { jsx as jsx51, jsxs as jsxs38 } from "react/jsx-runtime";
5944
+ var ROW_PX = 14;
5945
+ var PAD_PX = 5;
5946
+ var CHAR_PX = 6.2;
5947
+ var GAP_PX = 10;
5948
+ var MARK_PX = 12;
5949
+ var EDGE_PX = 6;
5950
+ var SWATCH_PX = 8;
5951
+ var DOT_PX = 4.5;
5952
+ var SWATCH_GAP_PX = 4;
5953
+ var MAX_COMPACT_LABEL_CHARS = 12;
5954
+ var FULL_MIN_PLOT_W = 190;
5955
+ var FULL_MIN_PLOT_H = 80;
5956
+ function shortened(label, chars) {
5957
+ if (chars < 1) return "";
5958
+ return label.length <= chars ? label : `${label.slice(0, Math.max(1, chars - 1))}\u2026`;
5959
+ }
5960
+ function layoutCard(plot, heading, allRows, column) {
5961
+ const room = column ?? plot;
5962
+ const plotW = room.x1 - room.x0;
5963
+ const plotH = plot.y1 - plot.y0;
5964
+ const full = plotW >= FULL_MIN_PLOT_W && plotH >= FULL_MIN_PLOT_H;
5965
+ const named = full || column !== void 0;
5966
+ const rows = full || column ? allRows : allRows.filter((row) => !row.detail);
5967
+ const compactRoom = plotW - EDGE_PX * 2 - PAD_PX * 2 - SWATCH_PX - SWATCH_GAP_PX;
5968
+ const stacked = column !== void 0;
5969
+ const stackedChars = Math.floor(compactRoom / CHAR_PX);
5970
+ const valueText = (row) => shortened(
5971
+ row.value ?? NULL_DISPLAY,
5972
+ stackedChars - (row.currency ? row.currency.length + 2 : 0)
5973
+ );
5974
+ const text = (row) => {
5975
+ const value5 = row.value ?? NULL_DISPLAY;
5976
+ if (stacked) return shortened(row.label, stackedChars);
5977
+ if (full) return `${row.label} ${value5}`;
5978
+ const room2 = Math.floor((compactRoom - value5.length * CHAR_PX) / CHAR_PX) - 1 - (row.modelled ? 2 : 0);
5979
+ const label = shortened(row.label, Math.min(room2, MAX_COMPACT_LABEL_CHARS));
5980
+ if (label !== "") return `${label} ${value5}`;
5981
+ const chars = Math.floor(compactRoom / CHAR_PX) - (row.modelled ? 2 : 0);
5982
+ return shortened(value5, chars);
5983
+ };
5984
+ const currencyText = (row) => (full || stacked) && row.currency ? row.currency : "";
5985
+ const currencyW = (row) => currencyText(row) ? GAP_PX + currencyText(row).length * CHAR_PX + (row.modelled ? MARK_PX : 0) : row.modelled ? MARK_PX : 0;
5986
+ const swatchW = full ? 0 : SWATCH_PX + SWATCH_GAP_PX;
5987
+ const headingChars = Math.floor((plotW - EDGE_PX * 2 - PAD_PX * 2) / CHAR_PX);
5988
+ const textW = Math.max(
5989
+ ...rows.map(
5990
+ (row) => stacked ? swatchW + Math.max(
5991
+ text(row).length * CHAR_PX,
5992
+ valueText(row).length * CHAR_PX + currencyW(row)
5993
+ ) : swatchW + text(row).length * CHAR_PX + currencyW(row)
5994
+ ),
5995
+ named ? Math.min(heading.length, headingChars) * CHAR_PX : 0
5996
+ );
5997
+ const headRows = named ? 1 : 0;
5998
+ const cardH = (rows.length * (stacked ? 2 : 1) + headRows) * ROW_PX + PAD_PX * 2;
5999
+ return {
6000
+ full,
6001
+ named,
6002
+ headingChars,
6003
+ stacked,
6004
+ rows,
6005
+ text,
6006
+ valueText,
6007
+ currencyText,
6008
+ // A column card spans its column, so the captions standing under it line up with it.
6009
+ cardW: stacked ? plotW : Math.min(textW + PAD_PX * 2, plotW - EDGE_PX * 2),
6010
+ cardH,
6011
+ headRows,
6012
+ fits: cardH <= plotH - EDGE_PX * 2
6013
+ };
6014
+ }
6015
+ function crossesBox(trace, x, y, w, h) {
6016
+ const inside = (px, py) => px >= x && px <= x + w && py >= y && py <= y + h;
6017
+ for (let i = 1; i < trace.cx.length; i++) {
6018
+ const [ax, ay, bx, by] = [
6019
+ trace.cx[i - 1],
6020
+ trace.cy[i - 1],
6021
+ trace.cx[i],
6022
+ trace.cy[i]
6023
+ ];
6024
+ if (![ax, ay, bx, by].every(Number.isFinite)) continue;
6025
+ const steps = Math.max(1, Math.ceil(Math.hypot(bx - ax, by - ay) / ROW_PX));
6026
+ for (let k = 0; k <= steps; k++) {
6027
+ if (inside(ax + (bx - ax) * k / steps, ay + (by - ay) * k / steps)) {
6028
+ return true;
6029
+ }
6030
+ }
6031
+ }
6032
+ return false;
6033
+ }
6034
+ function resolveCard({
6035
+ x,
6036
+ plot,
6037
+ heading,
6038
+ rows: allRows,
6039
+ column,
6040
+ traces = []
6041
+ }) {
6042
+ const layout = layoutCard(plot, heading, allRows, column);
6043
+ const { rows, cardW, cardH, fits } = layout;
6044
+ const cardY0 = plot.y0 + EDGE_PX;
6045
+ const dots = rows.flatMap(
6046
+ (row) => row.y === void 0 || row.y === null ? [] : [row.y]
6047
+ );
6048
+ const clearOfDots = (cardX, cardY) => dots.every(
6049
+ (dy) => x + DOT_PX < cardX || x - DOT_PX > cardX + cardW || dy + DOT_PX < cardY || dy - DOT_PX > cardY + cardH
6050
+ );
6051
+ const roomRight = plot.x1 - x - EDGE_PX;
6052
+ const rightFirst = roomRight >= cardW || roomRight >= x - plot.x0;
6053
+ const clampX = (v) => Math.max(plot.x0 + EDGE_PX, Math.min(plot.x1 - EDGE_PX - cardW, v));
6054
+ const sideXs = rightFirst ? [x + EDGE_PX, x - EDGE_PX - cardW] : [x - EDGE_PX - cardW, x + EDGE_PX];
6055
+ const corners = [cardY0, plot.y1 - EDGE_PX - cardH].flatMap(
6056
+ (cy) => sideXs.map((cx) => ({ cardX: clampX(cx), cardY: cy }))
6057
+ );
6058
+ const clearOfTraces = (cardX, cardY) => traces.every((t) => !crossesBox(t, cardX, cardY, cardW, cardH));
6059
+ const overPlot = corners.find(
6060
+ (c) => clearOfDots(c.cardX, c.cardY) && clearOfTraces(c.cardX, c.cardY)
6061
+ ) ?? corners.find((c) => clearOfDots(c.cardX, c.cardY));
6062
+ const place2 = !fits ? void 0 : column ? { cardX: column.x0, cardY: column.y0 + EDGE_PX } : overPlot;
6063
+ return { layout, place: place2 };
6064
+ }
6065
+ function plotCrosshairShowsCard(props) {
6066
+ return resolveCard(props).place !== void 0;
6067
+ }
6068
+ function PlotCrosshair({
6069
+ x,
6070
+ plot,
6071
+ heading,
6072
+ rows: allRows,
6073
+ column
6074
+ }) {
6075
+ const { layout, place: place2 } = resolveCard({
6076
+ x,
6077
+ plot,
6078
+ heading,
6079
+ rows: allRows,
6080
+ column
6081
+ });
6082
+ const {
6083
+ full,
6084
+ named,
6085
+ headingChars,
6086
+ stacked,
6087
+ rows,
6088
+ text,
6089
+ valueText,
6090
+ currencyText,
6091
+ cardW,
6092
+ cardH,
6093
+ headRows
6094
+ } = layout;
6095
+ const drawn = place2 !== void 0;
6096
+ const cardX = place2?.cardX ?? 0;
6097
+ const cardY = place2?.cardY ?? 0;
6098
+ const textX = (cx) => cx + PAD_PX + (full ? 0 : SWATCH_PX + SWATCH_GAP_PX);
6099
+ return /* @__PURE__ */ jsxs38("g", { pointerEvents: "none", "data-plot-crosshair": "", children: [
6100
+ /* @__PURE__ */ jsx51(
6101
+ "line",
6102
+ {
6103
+ x1: x,
6104
+ y1: plot.y0,
6105
+ x2: x,
6106
+ y2: plot.y1,
6107
+ stroke: "var(--color-text-primary)",
6108
+ strokeWidth: 1,
6109
+ opacity: 0.7
6110
+ }
6111
+ ),
6112
+ rows.map(
6113
+ (row) => row.y === void 0 || row.y === null ? null : /* @__PURE__ */ jsx51(
6114
+ "circle",
6115
+ {
6116
+ cx: x,
6117
+ cy: row.y,
6118
+ r: 3.5,
6119
+ fill: row.color,
6120
+ stroke: "var(--color-text-primary)",
6121
+ strokeWidth: 1
6122
+ },
6123
+ row.id
6124
+ )
6125
+ ),
6126
+ drawn && /* @__PURE__ */ jsxs38("g", { "data-plot-crosshair-card": "", children: [
6127
+ /* @__PURE__ */ jsx51(
6128
+ "rect",
6129
+ {
6130
+ x: cardX,
6131
+ y: cardY,
6132
+ width: cardW,
6133
+ height: cardH,
6134
+ rx: 3,
6135
+ fill: "var(--color-surface-panel)",
6136
+ stroke: "var(--color-border-strong)"
6137
+ }
6138
+ ),
6139
+ named && /* @__PURE__ */ jsx51(
6140
+ "text",
6141
+ {
6142
+ x: cardX + PAD_PX,
6143
+ y: cardY + PAD_PX + 10,
6144
+ fill: "var(--color-text-muted)",
6145
+ fontSize: 10,
6146
+ children: shortened(heading, headingChars)
6147
+ }
6148
+ ),
6149
+ rows.map((row, i) => {
6150
+ const lines = stacked ? 2 : 1;
6151
+ const labelBaseline = cardY + PAD_PX + (i * lines + headRows) * ROW_PX + 10;
6152
+ const baseline = labelBaseline + (stacked ? ROW_PX : 0);
6153
+ return /* @__PURE__ */ jsxs38("g", { "data-plot-crosshair-row": row.id, children: [
6154
+ !full && /* @__PURE__ */ jsx51(
6155
+ "rect",
6156
+ {
6157
+ x: cardX + PAD_PX,
6158
+ y: labelBaseline - 8,
6159
+ width: SWATCH_PX,
6160
+ height: SWATCH_PX,
6161
+ fill: row.color,
6162
+ "data-plot-crosshair-swatch": ""
6163
+ }
6164
+ ),
6165
+ /* @__PURE__ */ jsx51(
6166
+ "text",
6167
+ {
6168
+ x: textX(cardX),
6169
+ y: labelBaseline,
6170
+ fill: row.value === null || stacked ? "var(--color-text-faint)" : row.color,
6171
+ fontSize: 10,
6172
+ style: { whiteSpace: "pre" },
6173
+ children: text(row)
6174
+ }
6175
+ ),
6176
+ stacked && /* @__PURE__ */ jsx51(
6177
+ "text",
6178
+ {
6179
+ x: textX(cardX),
6180
+ y: baseline,
6181
+ fill: row.value === null ? "var(--color-text-faint)" : row.color,
6182
+ fontSize: 10,
6183
+ style: { whiteSpace: "pre" },
6184
+ children: valueText(row)
6185
+ }
6186
+ ),
6187
+ row.modelled && /* @__PURE__ */ jsx51(
6188
+ ReckoningMarkSvg,
6189
+ {
6190
+ kind: "modelled",
6191
+ x: cardX + cardW - PAD_PX - currencyText(row).length * CHAR_PX - (currencyText(row) ? 8 : 4),
6192
+ y: baseline - 3
6193
+ }
6194
+ ),
6195
+ currencyText(row) && /* @__PURE__ */ jsx51(
6196
+ "text",
6197
+ {
6198
+ x: cardX + cardW - PAD_PX,
6199
+ y: baseline,
6200
+ textAnchor: "end",
6201
+ fill: "var(--color-text-faint)",
6202
+ fontSize: 10,
6203
+ children: currencyText(row)
6204
+ }
6205
+ )
6206
+ ] }, row.id);
6207
+ })
6208
+ ] })
6209
+ ] });
6210
+ }
6211
+
6212
+ // src/plotReadoutPlacement.ts
6213
+ var BESIDE_MIN_WIDTH = 480;
6214
+ var BESIDE_MIN_HEIGHT = 110;
6215
+ var COLUMN_MIN_PX = 112;
6216
+ var COLUMN_MAX_PX = 260;
6217
+ var COLUMN_MAX_SHARE = 0.4;
6218
+ var PLOT_KEEPS_PX = 300;
6219
+ function placePlotReadouts({
6220
+ width,
6221
+ height,
6222
+ contentWidth
6223
+ }) {
6224
+ const columnWidth = Math.max(COLUMN_MIN_PX, Math.ceil(contentWidth));
6225
+ if (width < BESIDE_MIN_WIDTH || height < BESIDE_MIN_HEIGHT || columnWidth > Math.min(COLUMN_MAX_PX, width * COLUMN_MAX_SHARE) || width - columnWidth < PLOT_KEEPS_PX) {
6226
+ return { placement: "overlay" };
6227
+ }
6228
+ return { placement: "beside", columnWidth };
6229
+ }
6230
+
5681
6231
  // src/ReadFrameControl.tsx
5682
6232
  import {
5683
6233
  readFrameChoicesEqual
5684
6234
  } from "@ksp-gonogo/sitrep-sdk/frames";
5685
- import { jsx as jsx49, jsxs as jsxs37 } from "react/jsx-runtime";
6235
+ import { jsx as jsx52, jsxs as jsxs39 } from "react/jsx-runtime";
5686
6236
  function ReadFrameControl({
5687
6237
  id,
5688
6238
  label,
5689
- value: value4,
6239
+ value: value5,
5690
6240
  options,
5691
6241
  onChange,
5692
6242
  hint
5693
6243
  }) {
5694
6244
  const selectedIndex = options.findIndex(
5695
- (option) => readFrameChoicesEqual(option.choice, value4)
6245
+ (option) => readFrameChoicesEqual(option.choice, value5)
5696
6246
  );
5697
- return /* @__PURE__ */ jsxs37(Field, { children: [
5698
- /* @__PURE__ */ jsx49(FieldLabel, { htmlFor: id, children: label }),
5699
- /* @__PURE__ */ jsxs37(
6247
+ return /* @__PURE__ */ jsxs39(Field, { children: [
6248
+ /* @__PURE__ */ jsx52(FieldLabel, { htmlFor: id, children: label }),
6249
+ /* @__PURE__ */ jsxs39(
5700
6250
  Select,
5701
6251
  {
5702
6252
  id,
@@ -5706,8 +6256,8 @@ function ReadFrameControl({
5706
6256
  if (option !== void 0) onChange(option.choice);
5707
6257
  },
5708
6258
  children: [
5709
- selectedIndex === -1 && /* @__PURE__ */ jsx49("option", { value: "", disabled: true }),
5710
- options.map((option, index) => /* @__PURE__ */ jsx49(
6259
+ selectedIndex === -1 && /* @__PURE__ */ jsx52("option", { value: "", disabled: true }),
6260
+ options.map((option, index) => /* @__PURE__ */ jsx52(
5711
6261
  "option",
5712
6262
  {
5713
6263
  value: index,
@@ -5718,43 +6268,43 @@ function ReadFrameControl({
5718
6268
  ]
5719
6269
  }
5720
6270
  ),
5721
- hint !== void 0 && /* @__PURE__ */ jsx49(FieldHint, { children: hint })
6271
+ hint !== void 0 && /* @__PURE__ */ jsx52(FieldHint, { children: hint })
5722
6272
  ] });
5723
6273
  }
5724
6274
 
5725
6275
  // src/ReadOnlyField.tsx
5726
- import styled43 from "styled-components";
5727
- import { jsx as jsx50, jsxs as jsxs38 } from "react/jsx-runtime";
6276
+ import styled44 from "styled-components";
6277
+ import { jsx as jsx53, jsxs as jsxs40 } from "react/jsx-runtime";
5728
6278
  function ReadOnlyField({
5729
6279
  label,
5730
6280
  description,
5731
- value: value4,
6281
+ value: value5,
5732
6282
  className
5733
6283
  }) {
5734
- return /* @__PURE__ */ jsxs38(ReadOnlyField__List, { className, children: [
5735
- /* @__PURE__ */ jsxs38(ReadOnlyField__Term, { children: [
5736
- /* @__PURE__ */ jsx50(ReadOnlyField__Label, { children: label }),
5737
- description !== void 0 && description !== null && /* @__PURE__ */ jsx50(ReadOnlyField__Description, { children: description })
6284
+ return /* @__PURE__ */ jsxs40(ReadOnlyField__List, { className, children: [
6285
+ /* @__PURE__ */ jsxs40(ReadOnlyField__Term, { children: [
6286
+ /* @__PURE__ */ jsx53(ReadOnlyField__Label, { children: label }),
6287
+ description !== void 0 && description !== null && /* @__PURE__ */ jsx53(ReadOnlyField__Description, { children: description })
5738
6288
  ] }),
5739
- /* @__PURE__ */ jsx50(ReadOnlyField__Value, { $prose: typeof value4 === "string", children: /* @__PURE__ */ jsx50(ReadOnlyFieldContent, { value: value4 }) })
6289
+ /* @__PURE__ */ jsx53(ReadOnlyField__Value, { $prose: typeof value5 === "string", children: /* @__PURE__ */ jsx53(ReadOnlyFieldContent, { value: value5 }) })
5740
6290
  ] });
5741
6291
  }
5742
6292
  function ReadOnlyFieldContent({
5743
- value: value4
6293
+ value: value5
5744
6294
  }) {
5745
- if (value4 === null || value4 === void 0) return /* @__PURE__ */ jsx50(NullValue, {});
5746
- if (typeof value4 === "object") return /* @__PURE__ */ jsx50(Unit, { value: value4 });
5747
- if (typeof value4 === "boolean") return value4 ? "On" : "Off";
5748
- return value4;
6295
+ if (value5 === null || value5 === void 0) return /* @__PURE__ */ jsx53(NullValue, {});
6296
+ if (typeof value5 === "object") return /* @__PURE__ */ jsx53(Unit, { value: value5 });
6297
+ if (typeof value5 === "boolean") return value5 ? "On" : "Off";
6298
+ return value5;
5749
6299
  }
5750
- var ReadOnlyField__List = styled43.dl`
6300
+ var ReadOnlyField__List = styled44.dl`
5751
6301
  display: flex;
5752
6302
  align-items: baseline;
5753
6303
  justify-content: space-between;
5754
6304
  gap: var(--gap-field-term);
5755
6305
  margin: 0;
5756
6306
  `;
5757
- var ReadOnlyField__Term = styled43.dt`
6307
+ var ReadOnlyField__Term = styled44.dt`
5758
6308
  display: flex;
5759
6309
  flex-direction: column;
5760
6310
  gap: var(--gap-caption);
@@ -5762,16 +6312,16 @@ var ReadOnlyField__Term = styled43.dt`
5762
6312
  /* Grows into the space a short value leaves and yields to a long one. */
5763
6313
  flex: 1 1 auto;
5764
6314
  `;
5765
- var ReadOnlyField__Label = styled43.span`
6315
+ var ReadOnlyField__Label = styled44.span`
5766
6316
  font-size: var(--font-size-value);
5767
6317
  color: var(--color-text-primary);
5768
6318
  `;
5769
- var ReadOnlyField__Description = styled43.span`
6319
+ var ReadOnlyField__Description = styled44.span`
5770
6320
  font-size: var(--font-size-compact);
5771
6321
  color: var(--color-text-dim);
5772
6322
  max-width: 32em;
5773
6323
  `;
5774
- var ReadOnlyField__Value = styled43.dd`
6324
+ var ReadOnlyField__Value = styled44.dd`
5775
6325
  margin: 0;
5776
6326
  min-width: 0;
5777
6327
  text-align: right;
@@ -5788,9 +6338,9 @@ var ReadOnlyField__Value = styled43.dd`
5788
6338
  `;
5789
6339
 
5790
6340
  // src/Readout.tsx
5791
- import styled44, { css as css11 } from "styled-components";
5792
- import { jsx as jsx51 } from "react/jsx-runtime";
5793
- var Readout__Box = styled44.div`
6341
+ import styled45, { css as css11 } from "styled-components";
6342
+ import { jsx as jsx54 } from "react/jsx-runtime";
6343
+ var Readout__Box = styled45.div`
5794
6344
  display: ${({ $size }) => $size === "hero" ? "flex" : "inline-flex"};
5795
6345
  font-weight: 700;
5796
6346
  letter-spacing: 0.04em;
@@ -5818,9 +6368,9 @@ function Readout({
5818
6368
  tone = "neutral",
5819
6369
  ...rest
5820
6370
  }) {
5821
- return /* @__PURE__ */ jsx51(Readout__Box, { $size: size, $tone: tone, ...rest });
6371
+ return /* @__PURE__ */ jsx54(Readout__Box, { $size: size, $tone: tone, ...rest });
5822
6372
  }
5823
- var ReadoutCaption = styled44.span`
6373
+ var ReadoutCaption = styled45.span`
5824
6374
  font-size: var(--font-size-caption);
5825
6375
  font-weight: 400;
5826
6376
  letter-spacing: 0.05em;
@@ -5829,8 +6379,8 @@ var ReadoutCaption = styled44.span`
5829
6379
  `;
5830
6380
 
5831
6381
  // src/Row.tsx
5832
- import styled45, { css as css12 } from "styled-components";
5833
- import { jsx as jsx52 } from "react/jsx-runtime";
6382
+ import styled46, { css as css12 } from "styled-components";
6383
+ import { jsx as jsx55 } from "react/jsx-runtime";
5834
6384
  function RowBase({
5835
6385
  as,
5836
6386
  interactive = false,
@@ -5841,7 +6391,7 @@ function RowBase({
5841
6391
  children,
5842
6392
  ...rest
5843
6393
  }) {
5844
- return /* @__PURE__ */ jsx52(
6394
+ return /* @__PURE__ */ jsx55(
5845
6395
  Row__Root,
5846
6396
  {
5847
6397
  as: as ?? "li",
@@ -5855,7 +6405,7 @@ function RowBase({
5855
6405
  }
5856
6406
  );
5857
6407
  }
5858
- var RowName = styled45.span`
6408
+ var RowName = styled46.span`
5859
6409
  overflow: hidden;
5860
6410
  text-overflow: ellipsis;
5861
6411
  white-space: nowrap;
@@ -5864,7 +6414,7 @@ var RowName = styled45.span`
5864
6414
  color: var(--color-text-primary);
5865
6415
  `;
5866
6416
  var WRAPPED_NAME_FLOOR = "min(12ch, 100%)";
5867
- var Row__Root = styled45.li`
6417
+ var Row__Root = styled46.li`
5868
6418
  display: flex;
5869
6419
  justify-content: space-between;
5870
6420
  align-items: center;
@@ -5908,99 +6458,6 @@ var Row__Root = styled45.li`
5908
6458
  `;
5909
6459
  var Row = Object.assign(RowBase, { Name: RowName });
5910
6460
 
5911
- // src/reckoningMarkDraw.tsx
5912
- import { jsx as jsx53 } from "react/jsx-runtime";
5913
- var HELD_SQUARE_HALF = 0.89;
5914
- var GHOST_OPACITY = 0.45;
5915
- function ReckoningMarkSvg({
5916
- kind,
5917
- x,
5918
- y,
5919
- scale = 1,
5920
- ghost = false
5921
- }) {
5922
- const spec = RECKONING_MARK[kind];
5923
- const r = spec.canvasRadius * scale;
5924
- const common = {
5925
- fill: spec.color,
5926
- opacity: ghost ? GHOST_OPACITY : void 0,
5927
- "data-reckoning-mark": kind,
5928
- "aria-hidden": true
5929
- };
5930
- if (kind === "held") {
5931
- const half = r * HELD_SQUARE_HALF;
5932
- return /* @__PURE__ */ jsx53(
5933
- "rect",
5934
- {
5935
- x: x - half,
5936
- y: y - half,
5937
- width: 2 * half,
5938
- height: 2 * half,
5939
- ...common
5940
- }
5941
- );
5942
- }
5943
- const points = `${x},${y - r} ${x + r},${y + r * 0.8} ${x - r},${y + r * 0.8}`;
5944
- return /* @__PURE__ */ jsx53("polygon", { points, ...common });
5945
- }
5946
- function resolvedColor(canvas, cssVar, fallback) {
5947
- const v = getComputedStyle(canvas).getPropertyValue(cssVar).trim();
5948
- return v || fallback;
5949
- }
5950
- function paintReckoningMark(canvas, ctx, kind, x, y, { ghost = false, scale = 1 } = {}) {
5951
- const spec = RECKONING_MARK[kind];
5952
- const r = spec.canvasRadius * scale;
5953
- ctx.save();
5954
- ctx.globalAlpha = ghost ? GHOST_OPACITY : 1;
5955
- ctx.fillStyle = resolvedColor(canvas, spec.cssVar, spec.fallback);
5956
- ctx.beginPath();
5957
- if (kind === "held") {
5958
- const half = r * HELD_SQUARE_HALF;
5959
- ctx.rect(x - half, y - half, 2 * half, 2 * half);
5960
- } else {
5961
- ctx.moveTo(x, y - r);
5962
- ctx.lineTo(x + r, y + r * 0.8);
5963
- ctx.lineTo(x - r, y + r * 0.8);
5964
- ctx.closePath();
5965
- }
5966
- ctx.fill();
5967
- ctx.restore();
5968
- }
5969
- function paintReckonedPosition(canvas, ctx, { held, modelled }, options = {}) {
5970
- if (held !== void 0 && modelled !== void 0) {
5971
- ctx.save();
5972
- ctx.globalAlpha = GHOST_OPACITY;
5973
- ctx.strokeStyle = resolvedColor(
5974
- canvas,
5975
- RECKONING_MARK.modelled.cssVar,
5976
- RECKONING_MARK.modelled.fallback
5977
- );
5978
- ctx.lineWidth = 1;
5979
- ctx.setLineDash([2, 3]);
5980
- ctx.beginPath();
5981
- ctx.moveTo(held.x, held.y);
5982
- ctx.lineTo(modelled.x, modelled.y);
5983
- ctx.stroke();
5984
- ctx.restore();
5985
- }
5986
- if (held !== void 0) {
5987
- paintReckoningMark(canvas, ctx, "held", held.x, held.y, {
5988
- ...options,
5989
- ghost: modelled !== void 0
5990
- });
5991
- }
5992
- if (modelled !== void 0) {
5993
- paintReckoningMark(
5994
- canvas,
5995
- ctx,
5996
- "modelled",
5997
- modelled.x,
5998
- modelled.y,
5999
- options
6000
- );
6001
- }
6002
- }
6003
-
6004
6461
  // src/resourceColor.ts
6005
6462
  var SATURATION_PCT = 65;
6006
6463
  var LIGHTNESS_MIN_PCT = 38;
@@ -6079,8 +6536,8 @@ function fnv1a(str) {
6079
6536
  }
6080
6537
  return hash >>> 0;
6081
6538
  }
6082
- function positiveMod(value4, modulus) {
6083
- return (value4 % modulus + modulus) % modulus;
6539
+ function positiveMod(value5, modulus) {
6540
+ return (value5 % modulus + modulus) % modulus;
6084
6541
  }
6085
6542
  function memberLightness(key) {
6086
6543
  const hash = fnv1a(`light:${key}`);
@@ -6118,8 +6575,8 @@ function resourceColor(name) {
6118
6575
  }
6119
6576
 
6120
6577
  // src/SelectableRow.tsx
6121
- import styled46, { css as css13 } from "styled-components";
6122
- import { jsx as jsx54 } from "react/jsx-runtime";
6578
+ import styled47, { css as css13 } from "styled-components";
6579
+ import { jsx as jsx56 } from "react/jsx-runtime";
6123
6580
  function SelectableRow({
6124
6581
  selected,
6125
6582
  gap = "caption",
@@ -6128,7 +6585,7 @@ function SelectableRow({
6128
6585
  children,
6129
6586
  ...rest
6130
6587
  }) {
6131
- return /* @__PURE__ */ jsx54(
6588
+ return /* @__PURE__ */ jsx56(
6132
6589
  SelectableRow__Root,
6133
6590
  {
6134
6591
  type: "button",
@@ -6142,7 +6599,7 @@ function SelectableRow({
6142
6599
  }
6143
6600
  );
6144
6601
  }
6145
- var SelectableRow__Root = styled46.button`
6602
+ var SelectableRow__Root = styled47.button`
6146
6603
  display: flex;
6147
6604
  ${({ $layout }) => $layout === "split" ? css13`
6148
6605
  justify-content: space-between;
@@ -6184,14 +6641,14 @@ var SelectableRow__Root = styled46.button`
6184
6641
 
6185
6642
  // src/Slider.tsx
6186
6643
  import { forwardRef as forwardRef4 } from "react";
6187
- import styled47 from "styled-components";
6188
- import { jsx as jsx55 } from "react/jsx-runtime";
6644
+ import styled48 from "styled-components";
6645
+ import { jsx as jsx57 } from "react/jsx-runtime";
6189
6646
  var Slider = forwardRef4(
6190
6647
  function Slider2(props, ref) {
6191
- return /* @__PURE__ */ jsx55(Slider__Input, { ref, type: "range", ...props });
6648
+ return /* @__PURE__ */ jsx57(Slider__Input, { ref, type: "range", ...props });
6192
6649
  }
6193
6650
  );
6194
- var Slider__Input = styled47.input`
6651
+ var Slider__Input = styled48.input`
6195
6652
  width: 100%;
6196
6653
  min-width: 0;
6197
6654
  margin: 0;
@@ -6208,8 +6665,8 @@ var Slider__Input = styled47.input`
6208
6665
  `;
6209
6666
 
6210
6667
  // src/Stat.tsx
6211
- import styled48 from "styled-components";
6212
- import { jsx as jsx56, jsxs as jsxs39 } from "react/jsx-runtime";
6668
+ import styled49 from "styled-components";
6669
+ import { jsx as jsx58, jsxs as jsxs41 } from "react/jsx-runtime";
6213
6670
  function Stat({
6214
6671
  label,
6215
6672
  children,
@@ -6217,13 +6674,13 @@ function Stat({
6217
6674
  tone = "neutral",
6218
6675
  ...rest
6219
6676
  }) {
6220
- return /* @__PURE__ */ jsxs39(Stat__Root, { ...rest, children: [
6221
- /* @__PURE__ */ jsx56(Stat__Label, { children: label }),
6222
- /* @__PURE__ */ jsx56(Stat__Figure, { $tone: tone, children }),
6223
- detail !== void 0 && detail !== null && /* @__PURE__ */ jsx56(Stat__Detail, { children: detail })
6677
+ return /* @__PURE__ */ jsxs41(Stat__Root, { ...rest, children: [
6678
+ /* @__PURE__ */ jsx58(Stat__Label, { children: label }),
6679
+ /* @__PURE__ */ jsx58(Stat__Figure, { $tone: tone, children }),
6680
+ detail !== void 0 && detail !== null && /* @__PURE__ */ jsx58(Stat__Detail, { children: detail })
6224
6681
  ] });
6225
6682
  }
6226
- var Stat__Root = styled48.dl`
6683
+ var Stat__Root = styled49.dl`
6227
6684
  display: flex;
6228
6685
  flex-direction: column;
6229
6686
  gap: var(--gap-caption);
@@ -6234,13 +6691,13 @@ var Stat__Root = styled48.dl`
6234
6691
  border: 1px solid var(--color-border-subtle);
6235
6692
  border-radius: var(--radius-regular);
6236
6693
  `;
6237
- var Stat__Label = styled48.dt`
6694
+ var Stat__Label = styled49.dt`
6238
6695
  font-size: var(--font-size-caption);
6239
6696
  letter-spacing: 0.1em;
6240
6697
  text-transform: uppercase;
6241
6698
  color: var(--color-text-muted);
6242
6699
  `;
6243
- var Stat__Figure = styled48.dd`
6700
+ var Stat__Figure = styled49.dd`
6244
6701
  margin: 0;
6245
6702
  min-width: 0;
6246
6703
  /* Bottom-aligned, so figures line up across the strip even where one label wraps. */
@@ -6255,7 +6712,7 @@ var Stat__Figure = styled48.dd`
6255
6712
  font-variant-numeric: tabular-nums;
6256
6713
  color: ${({ $tone }) => TONE_TEXT[$tone]};
6257
6714
  `;
6258
- var Stat__Detail = styled48.dd`
6715
+ var Stat__Detail = styled49.dd`
6259
6716
  margin: 0;
6260
6717
  min-width: 0;
6261
6718
  font-size: var(--font-size-compact);
@@ -6263,34 +6720,36 @@ var Stat__Detail = styled48.dd`
6263
6720
  `;
6264
6721
 
6265
6722
  // src/StatContributions.tsx
6266
- import { Fragment as Fragment17, jsx as jsx57 } from "react/jsx-runtime";
6723
+ import { Fragment as Fragment17, jsx as jsx59 } from "react/jsx-runtime";
6267
6724
  function StatContributions({ slot }) {
6268
6725
  const entries = useContributionsBySlotId(slot);
6269
6726
  if (entries.length === 0) return null;
6270
- return /* @__PURE__ */ jsx57(Fragment17, { children: entries.map((entry) => /* @__PURE__ */ jsx57(
6727
+ return /* @__PURE__ */ jsx59(Fragment17, { children: entries.map((entry) => /* @__PURE__ */ jsx59(
6271
6728
  Stat,
6272
6729
  {
6273
6730
  label: entry.label,
6274
6731
  detail: entry.detail,
6275
6732
  tone: entry.tone ?? "neutral",
6276
- children: /* @__PURE__ */ jsx57(StatFigure, { entry })
6733
+ children: /* @__PURE__ */ jsx59(StatFigure, { entry })
6277
6734
  },
6278
6735
  entry.id
6279
6736
  )) });
6280
6737
  }
6281
6738
  function StatFigure({ entry }) {
6282
- if (entry.value !== void 0) return /* @__PURE__ */ jsx57(Unit, { value: entry.value });
6283
- if (entry.text !== void 0) return /* @__PURE__ */ jsx57(Fragment17, { children: entry.text });
6284
- return /* @__PURE__ */ jsx57(NullValue, {});
6739
+ if (entry.value !== void 0) return /* @__PURE__ */ jsx59(Unit, { value: entry.value });
6740
+ if (entry.text === void 0) return /* @__PURE__ */ jsx59(NullValue, {});
6741
+ const marking = heldMarking(entry.held);
6742
+ if (marking === null) return /* @__PURE__ */ jsx59(Fragment17, { children: entry.text });
6743
+ return /* @__PURE__ */ jsx59(HeldFigure, { kind: marking.kind, caption: marking.caption, children: entry.text });
6285
6744
  }
6286
6745
 
6287
6746
  // src/Stepper.tsx
6288
6747
  import { useCallback as useCallback8, useId as useId12 } from "react";
6289
- import styled49 from "styled-components";
6290
- import { jsx as jsx58, jsxs as jsxs40 } from "react/jsx-runtime";
6748
+ import styled50 from "styled-components";
6749
+ import { jsx as jsx60, jsxs as jsxs42 } from "react/jsx-runtime";
6291
6750
  function Stepper({
6292
6751
  options,
6293
- value: value4,
6752
+ value: value5,
6294
6753
  onChange,
6295
6754
  label,
6296
6755
  format = String,
@@ -6299,7 +6758,7 @@ function Stepper({
6299
6758
  "data-testid": testId
6300
6759
  }) {
6301
6760
  const describedBy = useId12();
6302
- const index = options.indexOf(value4);
6761
+ const index = options.indexOf(value5);
6303
6762
  const atStart = index <= 0;
6304
6763
  const atEnd = index >= options.length - 1;
6305
6764
  const step = useCallback8(
@@ -6309,16 +6768,16 @@ function Stepper({
6309
6768
  }
6310
6769
  const clamped = Math.min(Math.max(to, 0), options.length - 1);
6311
6770
  const next = options[clamped];
6312
- if (next !== value4) {
6771
+ if (next !== value5) {
6313
6772
  onChange(next);
6314
6773
  }
6315
6774
  },
6316
- [disabled, onChange, options, value4]
6775
+ [disabled, onChange, options, value5]
6317
6776
  );
6318
6777
  const back = () => step(index < 0 ? 0 : index - 1);
6319
6778
  const forward = () => step(index < 0 ? options.length - 1 : index + 1);
6320
- return /* @__PURE__ */ jsxs40(Stepper__Body, { "data-testid": testId, children: [
6321
- /* @__PURE__ */ jsx58(
6779
+ return /* @__PURE__ */ jsxs42(Stepper__Body, { "data-testid": testId, children: [
6780
+ /* @__PURE__ */ jsx60(
6322
6781
  Stepper__Step,
6323
6782
  {
6324
6783
  type: "button",
@@ -6328,7 +6787,7 @@ function Stepper({
6328
6787
  children: "\u2212"
6329
6788
  }
6330
6789
  ),
6331
- /* @__PURE__ */ jsx58(
6790
+ /* @__PURE__ */ jsx60(
6332
6791
  Stepper__Value,
6333
6792
  {
6334
6793
  role: "spinbutton",
@@ -6337,7 +6796,7 @@ function Stepper({
6337
6796
  "aria-valuenow": index < 0 ? void 0 : index,
6338
6797
  "aria-valuemin": 0,
6339
6798
  "aria-valuemax": Math.max(options.length - 1, 0),
6340
- "aria-valuetext": format(value4),
6799
+ "aria-valuetext": format(value5),
6341
6800
  "aria-disabled": disabled || void 0,
6342
6801
  "aria-describedby": children == null ? void 0 : describedBy,
6343
6802
  onKeyDown: (event) => {
@@ -6364,10 +6823,10 @@ function Stepper({
6364
6823
  break;
6365
6824
  }
6366
6825
  },
6367
- children: format(value4)
6826
+ children: format(value5)
6368
6827
  }
6369
6828
  ),
6370
- /* @__PURE__ */ jsx58(
6829
+ /* @__PURE__ */ jsx60(
6371
6830
  Stepper__Step,
6372
6831
  {
6373
6832
  type: "button",
@@ -6377,16 +6836,16 @@ function Stepper({
6377
6836
  children: "+"
6378
6837
  }
6379
6838
  ),
6380
- children != null && /* @__PURE__ */ jsx58(Stepper__Note, { id: describedBy, children })
6839
+ children != null && /* @__PURE__ */ jsx60(Stepper__Note, { id: describedBy, children })
6381
6840
  ] });
6382
6841
  }
6383
- var Stepper__Body = styled49.div`
6842
+ var Stepper__Body = styled50.div`
6384
6843
  display: inline-grid;
6385
6844
  grid-template-columns: auto 1fr auto;
6386
6845
  align-items: center;
6387
6846
  gap: var(--gap-stepper);
6388
6847
  `;
6389
- var Stepper__Step = styled49.button`
6848
+ var Stepper__Step = styled50.button`
6390
6849
  display: inline-flex;
6391
6850
  align-items: center;
6392
6851
  justify-content: center;
@@ -6421,7 +6880,7 @@ var Stepper__Step = styled49.button`
6421
6880
  min-width: 44px;
6422
6881
  }
6423
6882
  `;
6424
- var Stepper__Value = styled49.div`
6883
+ var Stepper__Value = styled50.div`
6425
6884
  text-align: center;
6426
6885
  font-family: var(--font-family-mono);
6427
6886
  font-size: var(--font-size-value);
@@ -6438,17 +6897,17 @@ var Stepper__Value = styled49.div`
6438
6897
  opacity: 0.4;
6439
6898
  }
6440
6899
  `;
6441
- var Stepper__Note = styled49.div`
6900
+ var Stepper__Note = styled50.div`
6442
6901
  grid-column: 1 / -1;
6443
6902
  font-size: var(--font-size-compact);
6444
6903
  color: var(--color-text-muted);
6445
6904
  `;
6446
6905
 
6447
6906
  // src/StreamStatusBadge.tsx
6448
- import { jsx as jsx59 } from "react/jsx-runtime";
6907
+ import { jsx as jsx61 } from "react/jsx-runtime";
6449
6908
  function StreamStatusBadge({ status }) {
6450
6909
  const label = formatStreamStatus(status);
6451
- return /* @__PURE__ */ jsx59(LiveRegion, { children: label !== null && /* @__PURE__ */ jsx59(Badge, { tone: severityFromStreamStatus(status), size: "sm", children: label }) });
6910
+ return /* @__PURE__ */ jsx61(LiveRegion, { children: label !== null && /* @__PURE__ */ jsx61(Badge, { tone: severityFromStreamStatus(status), size: "sm", children: label }) });
6452
6911
  }
6453
6912
 
6454
6913
  // src/sizeDelta.ts
@@ -6522,8 +6981,8 @@ import {
6522
6981
  useRef as useRef15,
6523
6982
  useState as useState16
6524
6983
  } from "react";
6525
- import styled50 from "styled-components";
6526
- import { Fragment as Fragment18, jsx as jsx60, jsxs as jsxs41 } from "react/jsx-runtime";
6984
+ import styled51 from "styled-components";
6985
+ import { Fragment as Fragment18, jsx as jsx62, jsxs as jsxs43 } from "react/jsx-runtime";
6527
6986
  var TABS_PANEL_MIN_WIDTH = 240;
6528
6987
  var TABS_PANEL_GAP = 8;
6529
6988
  function shouldExpandTabs(containerWidth, panelCount) {
@@ -6655,18 +7114,18 @@ function Tabs({
6655
7114
  [resolved, active?.id, activateByIndex]
6656
7115
  );
6657
7116
  if (expanded) {
6658
- return /* @__PURE__ */ jsx60(Tabs__Root, { ref: sizeRef, "data-tabs-root": "", className, children: /* @__PURE__ */ jsx60(
7117
+ return /* @__PURE__ */ jsx62(Tabs__Root, { ref: sizeRef, "data-tabs-root": "", className, children: /* @__PURE__ */ jsx62(
6659
7118
  Grid,
6660
7119
  {
6661
7120
  minColWidth: `${TABS_PANEL_MIN_WIDTH}px`,
6662
7121
  align: "start",
6663
7122
  gap: "related-comfortable",
6664
- children: selectable.map((tab) => /* @__PURE__ */ jsxs41(Section, { children: [
6665
- /* @__PURE__ */ jsxs41(SectionTitle, { as: "h3", $rule: true, children: [
7123
+ children: selectable.map((tab) => /* @__PURE__ */ jsxs43(Section, { children: [
7124
+ /* @__PURE__ */ jsxs43(SectionTitle, { as: "h3", $rule: true, children: [
6666
7125
  tab.label,
6667
- tab.indicator && /* @__PURE__ */ jsxs41(Fragment18, { children: [
6668
- /* @__PURE__ */ jsx60(Tabs__Dot, { "aria-hidden": "true" }),
6669
- /* @__PURE__ */ jsx60(VisuallyHidden, { children: ", needs attention" })
7126
+ tab.indicator && /* @__PURE__ */ jsxs43(Fragment18, { children: [
7127
+ /* @__PURE__ */ jsx62(Tabs__Dot, { "aria-hidden": "true" }),
7128
+ /* @__PURE__ */ jsx62(VisuallyHidden, { children: ", needs attention" })
6670
7129
  ] })
6671
7130
  ] }),
6672
7131
  tab.content
@@ -6674,16 +7133,16 @@ function Tabs({
6674
7133
  }
6675
7134
  ) });
6676
7135
  }
6677
- return /* @__PURE__ */ jsxs41(Tabs__Root, { ref: sizeRef, "data-tabs-root": "", className, children: [
6678
- /* @__PURE__ */ jsxs41(Tabs__BarShell, { children: [
6679
- /* @__PURE__ */ jsx60(Tabs__Scroller, { ref: scrollerRef, children: /* @__PURE__ */ jsxs41(
7136
+ return /* @__PURE__ */ jsxs43(Tabs__Root, { ref: sizeRef, "data-tabs-root": "", className, children: [
7137
+ /* @__PURE__ */ jsxs43(Tabs__BarShell, { children: [
7138
+ /* @__PURE__ */ jsx62(Tabs__Scroller, { ref: scrollerRef, children: /* @__PURE__ */ jsxs43(
6680
7139
  Tabs__Bar,
6681
7140
  {
6682
7141
  role: "tablist",
6683
7142
  "aria-label": ariaLabel,
6684
7143
  "aria-labelledby": ariaLabelledBy,
6685
7144
  children: [
6686
- blob && /* @__PURE__ */ jsx60(
7145
+ blob && /* @__PURE__ */ jsx62(
6687
7146
  Tabs__Blob,
6688
7147
  {
6689
7148
  "aria-hidden": "true",
@@ -6692,7 +7151,7 @@ function Tabs({
6692
7151
  ),
6693
7152
  resolved.map((tab) => {
6694
7153
  const isActive = tab.id === active?.id;
6695
- return /* @__PURE__ */ jsxs41(
7154
+ return /* @__PURE__ */ jsxs43(
6696
7155
  Tabs__Button,
6697
7156
  {
6698
7157
  ref: (el) => {
@@ -6713,9 +7172,9 @@ function Tabs({
6713
7172
  $compact: compact,
6714
7173
  children: [
6715
7174
  tab.label,
6716
- tab.indicator && /* @__PURE__ */ jsxs41(Fragment18, { children: [
6717
- /* @__PURE__ */ jsx60(Tabs__Dot, { "aria-hidden": "true" }),
6718
- /* @__PURE__ */ jsx60("span", { id: `${uid}${tab.id}-attention`, hidden: true, children: "Needs attention" })
7175
+ tab.indicator && /* @__PURE__ */ jsxs43(Fragment18, { children: [
7176
+ /* @__PURE__ */ jsx62(Tabs__Dot, { "aria-hidden": "true" }),
7177
+ /* @__PURE__ */ jsx62("span", { id: `${uid}${tab.id}-attention`, hidden: true, children: "Needs attention" })
6719
7178
  ] })
6720
7179
  ]
6721
7180
  },
@@ -6725,10 +7184,10 @@ function Tabs({
6725
7184
  ]
6726
7185
  }
6727
7186
  ) }),
6728
- /* @__PURE__ */ jsx60(InlineOverflowGlow, { $position: "left", $visible: overflow.left }),
6729
- /* @__PURE__ */ jsx60(InlineOverflowGlow, { $position: "right", $visible: overflow.right })
7187
+ /* @__PURE__ */ jsx62(InlineOverflowGlow, { $position: "left", $visible: overflow.left }),
7188
+ /* @__PURE__ */ jsx62(InlineOverflowGlow, { $position: "right", $visible: overflow.right })
6730
7189
  ] }),
6731
- active && /* @__PURE__ */ jsx60(
7190
+ active && /* @__PURE__ */ jsx62(
6732
7191
  Tabs__Panel,
6733
7192
  {
6734
7193
  role: "tabpanel",
@@ -6739,7 +7198,7 @@ function Tabs({
6739
7198
  )
6740
7199
  ] });
6741
7200
  }
6742
- var Tabs__Root = styled50.div`
7201
+ var Tabs__Root = styled51.div`
6743
7202
  display: flex;
6744
7203
  flex-direction: column;
6745
7204
  gap: var(--gap-tabs-panel);
@@ -6747,11 +7206,11 @@ var Tabs__Root = styled50.div`
6747
7206
  flex: 1;
6748
7207
  min-height: 0;
6749
7208
  `;
6750
- var Tabs__BarShell = styled50.div`
7209
+ var Tabs__BarShell = styled51.div`
6751
7210
  position: relative;
6752
7211
  margin-inline: calc(-1 * var(--bleed-inline));
6753
7212
  `;
6754
- var Tabs__Scroller = styled50.div`
7213
+ var Tabs__Scroller = styled51.div`
6755
7214
  display: flex;
6756
7215
  padding-inline: var(--bleed-inline);
6757
7216
  overflow-x: auto;
@@ -6765,7 +7224,7 @@ var Tabs__Scroller = styled50.div`
6765
7224
  display: none;
6766
7225
  }
6767
7226
  `;
6768
- var Tabs__Bar = styled50.div`
7227
+ var Tabs__Bar = styled51.div`
6769
7228
  position: relative;
6770
7229
  flex: 1 0 auto;
6771
7230
  display: flex;
@@ -6775,7 +7234,7 @@ var Tabs__Bar = styled50.div`
6775
7234
  padding: var(--inset-tab-track);
6776
7235
  flex-wrap: nowrap;
6777
7236
  `;
6778
- var Tabs__Blob = styled50.span`
7237
+ var Tabs__Blob = styled51.span`
6779
7238
  position: absolute;
6780
7239
  top: var(--inset-tab-track);
6781
7240
  bottom: var(--inset-tab-track);
@@ -6791,7 +7250,7 @@ var Tabs__Blob = styled50.span`
6791
7250
  transition: none;
6792
7251
  }
6793
7252
  `;
6794
- var Tabs__Dot = styled50.span`
7253
+ var Tabs__Dot = styled51.span`
6795
7254
  display: inline-block;
6796
7255
  width: 7px;
6797
7256
  height: 7px;
@@ -6800,7 +7259,7 @@ var Tabs__Dot = styled50.span`
6800
7259
  border-radius: var(--radius-circle);
6801
7260
  background: var(--color-warn-mark);
6802
7261
  `;
6803
- var Tabs__Button = styled50.button`
7262
+ var Tabs__Button = styled51.button`
6804
7263
  /* Transparent: the blob behind it is the selected background. */
6805
7264
  background: transparent;
6806
7265
  border: none;
@@ -6852,7 +7311,7 @@ var Tabs__Button = styled50.button`
6852
7311
  ${({ $compact }) => $compact ? "padding: var(--inset-tab-compact-touch);" : "padding: var(--inset-control-touch);"}
6853
7312
  }
6854
7313
  `;
6855
- var Tabs__Panel = styled50.div`
7314
+ var Tabs__Panel = styled51.div`
6856
7315
  display: flex;
6857
7316
  flex-direction: column;
6858
7317
  flex: 1;
@@ -6862,15 +7321,28 @@ var Tabs__Panel = styled50.div`
6862
7321
  // src/Tape.tsx
6863
7322
  import { bandIn as bandIn3 } from "@ksp-gonogo/sitrep-sdk";
6864
7323
  import { useEffect as useEffect14, useRef as useRef16, useState as useState17 } from "react";
6865
- import styled51 from "styled-components";
6866
- import { Fragment as Fragment19, jsx as jsx61, jsxs as jsxs42 } from "react/jsx-runtime";
7324
+ import styled52 from "styled-components";
7325
+ import { Fragment as Fragment19, jsx as jsx63, jsxs as jsxs44 } from "react/jsx-runtime";
7326
+ var FIGURE_CLEARANCE_PX = 9;
6867
7327
  var PAD_TOP = 12;
6868
7328
  var PAD_BOTTOM = 12;
6869
7329
  var TRACK_X = 52;
6870
7330
  var TRACK_W = 10;
7331
+ var MAX_TICK_DECIMALS = 4;
7332
+ function exactMarks(ticks, scale, withDecimals) {
7333
+ const figures = (s) => ticks.map((t) => Number.parseFloat(s.mark(t).replace(/[^\d.-]/g, "")));
7334
+ const exact = figures(withDecimals(MAX_TICK_DECIMALS));
7335
+ const isExact = (s) => figures(s).every((figure, i) => figure === exact[i]);
7336
+ if (isExact(scale)) return scale;
7337
+ for (let decimals = 0; decimals < MAX_TICK_DECIMALS; decimals++) {
7338
+ const candidate = withDecimals(decimals);
7339
+ if (isExact(candidate)) return candidate;
7340
+ }
7341
+ return withDecimals(MAX_TICK_DECIMALS);
7342
+ }
6871
7343
  function Tape({
6872
7344
  labelSide = "left",
6873
- value: value4,
7345
+ value: value5,
6874
7346
  min,
6875
7347
  max,
6876
7348
  width = 92,
@@ -6882,7 +7354,7 @@ function Tape({
6882
7354
  groundLine,
6883
7355
  seaLevel,
6884
7356
  format,
6885
- ariaLabel
7357
+ "aria-label": ariaLabel
6886
7358
  }) {
6887
7359
  const wrapRef = useRef16(null);
6888
7360
  const [measured, setMeasured] = useState17(height);
@@ -6900,7 +7372,7 @@ function Tape({
6900
7372
  return () => ro.disconnect();
6901
7373
  }, [fillHeight]);
6902
7374
  const h = fillHeight ? measured : height;
6903
- const resolved = resolveCurrency(value4);
7375
+ const resolved = resolveCurrency(value5);
6904
7376
  const { shown, held, caption, band } = resolved;
6905
7377
  const { anchor, tip } = useTooltip(caption);
6906
7378
  const current = shown?.magnitude ?? Number.NaN;
@@ -6950,8 +7422,8 @@ function Tape({
6950
7422
  const x1 = trackX - 4;
6951
7423
  const x2 = trackX + TRACK_W + 4;
6952
7424
  const mid = trackX + TRACK_W / 2;
6953
- return /* @__PURE__ */ jsxs42("g", { "data-level": dashed ? "sea" : "ground", children: [
6954
- /* @__PURE__ */ jsx61(
7425
+ return /* @__PURE__ */ jsxs44("g", { "data-level": dashed ? "sea" : "ground", children: [
7426
+ /* @__PURE__ */ jsx63(
6955
7427
  "line",
6956
7428
  {
6957
7429
  x1,
@@ -6963,7 +7435,7 @@ function Tape({
6963
7435
  strokeDasharray: dashed ? "3 2" : void 0
6964
7436
  }
6965
7437
  ),
6966
- beyond !== 0 && /* @__PURE__ */ jsx61(
7438
+ beyond !== 0 && /* @__PURE__ */ jsx63(
6967
7439
  "polygon",
6968
7440
  {
6969
7441
  "data-off-scale": "true",
@@ -6976,9 +7448,16 @@ function Tape({
6976
7448
  const ticks = [];
6977
7449
  const step = tickStep?.magnitude ?? 0;
6978
7450
  if (step > 0 && span > 0) {
6979
- const first = Math.ceil(axisMin / step) * step;
6980
- for (let t = first; t <= axisMax + 1e-9; t += step) ticks.push(t);
7451
+ const firstIndex = Math.ceil(axisMin / step);
7452
+ const lastIndex = Math.floor(axisMax / step + 1e-9);
7453
+ for (let i = firstIndex; i <= lastIndex; i++)
7454
+ ticks.push(i === 0 ? 0 : i * step);
6981
7455
  }
7456
+ const tickScale = exactMarks(
7457
+ ticks,
7458
+ scale,
7459
+ (decimals) => quantityScale(max, { format, decimals })
7460
+ );
6982
7461
  const pointerY = yOf(clamped);
6983
7462
  const onScale = (y) => usable > 0 ? (PAD_TOP + usable - y) / usable : 0;
6984
7463
  const drawnInterval = interval !== null && standsApart(
@@ -6986,7 +7465,7 @@ function Tape({
6986
7465
  [onScale(onRail(interval.lo)), onScale(onRail(interval.hi))],
6987
7466
  placedOnScale()
6988
7467
  ) ? interval : null;
6989
- return /* @__PURE__ */ jsxs42(
7468
+ return /* @__PURE__ */ jsxs44(
6990
7469
  Tape__Meter,
6991
7470
  {
6992
7471
  ref: wrapRef,
@@ -7008,7 +7487,7 @@ function Tape({
7008
7487
  },
7009
7488
  style: fillHeight ? { height: "100%" } : void 0,
7010
7489
  children: [
7011
- /* @__PURE__ */ jsxs42(
7490
+ /* @__PURE__ */ jsxs44(
7012
7491
  "svg",
7013
7492
  {
7014
7493
  width,
@@ -7022,7 +7501,7 @@ function Tape({
7022
7501
  height: "auto"
7023
7502
  },
7024
7503
  children: [
7025
- /* @__PURE__ */ jsx61(
7504
+ /* @__PURE__ */ jsx63(
7026
7505
  "rect",
7027
7506
  {
7028
7507
  x: trackX,
@@ -7037,7 +7516,7 @@ function Tape({
7037
7516
  const yHi = onRail(z.from.max(z.to));
7038
7517
  const yLo = onRail(z.from.min(z.to));
7039
7518
  const h2 = Math.max(0, yLo - yHi);
7040
- return /* @__PURE__ */ jsx61("g", { children: /* @__PURE__ */ jsx61(
7519
+ return /* @__PURE__ */ jsx63("g", { children: /* @__PURE__ */ jsx63(
7041
7520
  "rect",
7042
7521
  {
7043
7522
  x: trackX,
@@ -7053,8 +7532,11 @@ function Tape({
7053
7532
  groundLine !== void 0 && span > 0 && drawLevel(groundLine, false),
7054
7533
  ticks.map((t) => {
7055
7534
  const y = yOf(t);
7056
- return /* @__PURE__ */ jsxs42("g", { children: [
7057
- /* @__PURE__ */ jsx61(
7535
+ const underFigure = hasFigure && Math.abs(
7536
+ y - Math.max(trackTop + 4, Math.min(trackBottom - 4, pointerY))
7537
+ ) < FIGURE_CLEARANCE_PX;
7538
+ return /* @__PURE__ */ jsxs44("g", { children: [
7539
+ /* @__PURE__ */ jsx63(
7058
7540
  "line",
7059
7541
  {
7060
7542
  x1: mirrored ? trackX + TRACK_W + 4 : trackX - 4,
@@ -7065,7 +7547,7 @@ function Tape({
7065
7547
  strokeWidth: 1
7066
7548
  }
7067
7549
  ),
7068
- /* @__PURE__ */ jsx61(
7550
+ !underFigure && /* @__PURE__ */ jsx63(
7069
7551
  "text",
7070
7552
  {
7071
7553
  x: labelX,
@@ -7074,7 +7556,7 @@ function Tape({
7074
7556
  dominantBaseline: "middle",
7075
7557
  fontSize: 8,
7076
7558
  fill: "var(--color-text-faint)",
7077
- children: scale.mark(t)
7559
+ children: tickScale.mark(t)
7078
7560
  }
7079
7561
  )
7080
7562
  ] }, `tick-${t}`);
@@ -7083,8 +7565,8 @@ function Tape({
7083
7565
  const { bounds } = m;
7084
7566
  const y = onRail(m.value);
7085
7567
  const color = m.color ?? "var(--color-accent-fg)";
7086
- return /* @__PURE__ */ jsxs42("g", { "data-marker": m.label, children: [
7087
- /* @__PURE__ */ jsx61(
7568
+ return /* @__PURE__ */ jsxs44("g", { "data-marker": m.label, children: [
7569
+ /* @__PURE__ */ jsx63(
7088
7570
  "line",
7089
7571
  {
7090
7572
  x1: trackX,
@@ -7096,7 +7578,7 @@ function Tape({
7096
7578
  strokeDasharray: "2 2"
7097
7579
  }
7098
7580
  ),
7099
- /* @__PURE__ */ jsx61(
7581
+ /* @__PURE__ */ jsx63(
7100
7582
  "polygon",
7101
7583
  {
7102
7584
  points: mirrored ? `${trackX},${y} ${trackX - 5},${y - 3} ${trackX - 5},${y + 3}` : `${trackX + TRACK_W},${y} ${trackX + TRACK_W + 5},${y - 3} ${trackX + TRACK_W + 5},${y + 3}`,
@@ -7107,7 +7589,7 @@ function Tape({
7107
7589
  ),
7108
7590
  bounds !== void 0 && ["lo", "hi"].map((end) => {
7109
7591
  const by = onRail(bounds[end]);
7110
- return /* @__PURE__ */ jsx61(
7592
+ return /* @__PURE__ */ jsx63(
7111
7593
  InstrumentBound,
7112
7594
  {
7113
7595
  end,
@@ -7123,7 +7605,7 @@ function Tape({
7123
7605
  }),
7124
7606
  drawnInterval !== null && ["lo", "hi"].map((end) => {
7125
7607
  const y = onRail(drawnInterval[end]);
7126
- return /* @__PURE__ */ jsx61(
7608
+ return /* @__PURE__ */ jsx63(
7127
7609
  InstrumentBound,
7128
7610
  {
7129
7611
  end,
@@ -7135,8 +7617,8 @@ function Tape({
7135
7617
  end
7136
7618
  );
7137
7619
  }),
7138
- hasFigure && /* @__PURE__ */ jsxs42(Fragment19, { children: [
7139
- /* @__PURE__ */ jsx61(
7620
+ hasFigure && /* @__PURE__ */ jsxs44(Fragment19, { children: [
7621
+ /* @__PURE__ */ jsx63(
7140
7622
  "line",
7141
7623
  {
7142
7624
  x1: trackX - 6,
@@ -7147,7 +7629,7 @@ function Tape({
7147
7629
  strokeWidth: 2
7148
7630
  }
7149
7631
  ),
7150
- /* @__PURE__ */ jsxs42(
7632
+ /* @__PURE__ */ jsxs44(
7151
7633
  "text",
7152
7634
  {
7153
7635
  x: mirrored ? labelX + 2 : labelX - 2,
@@ -7159,12 +7641,12 @@ function Tape({
7159
7641
  fill: "var(--color-accent-fg)",
7160
7642
  children: [
7161
7643
  scale.mark(safe),
7162
- held && /* @__PURE__ */ jsx61(InstrumentHeldMark, { size: 5 })
7644
+ held && /* @__PURE__ */ jsx63(InstrumentHeldMark, { size: 5 })
7163
7645
  ]
7164
7646
  }
7165
7647
  )
7166
7648
  ] }),
7167
- !hasFigure && /* @__PURE__ */ jsx61(
7649
+ !hasFigure && /* @__PURE__ */ jsx63(
7168
7650
  InstrumentNoFigure,
7169
7651
  {
7170
7652
  x: mirrored ? labelX + 8 : labelX - 8,
@@ -7173,7 +7655,7 @@ function Tape({
7173
7655
  children: NULL_DISPLAY
7174
7656
  }
7175
7657
  ),
7176
- scale.symbol !== "" && /* @__PURE__ */ jsx61(
7658
+ scale.symbol !== "" && /* @__PURE__ */ jsx63(
7177
7659
  "text",
7178
7660
  {
7179
7661
  x: trackX + TRACK_W / 2,
@@ -7192,17 +7674,17 @@ function Tape({
7192
7674
  }
7193
7675
  );
7194
7676
  }
7195
- var Tape__Meter = styled51.div`
7677
+ var Tape__Meter = styled52.div`
7196
7678
  display: block;
7197
7679
  max-width: 100%;
7198
7680
  `;
7199
7681
 
7200
7682
  // src/TextField.tsx
7201
7683
  import { useId as useId14 } from "react";
7202
- import { jsx as jsx62, jsxs as jsxs43 } from "react/jsx-runtime";
7684
+ import { jsx as jsx64, jsxs as jsxs45 } from "react/jsx-runtime";
7203
7685
  function TextField({
7204
7686
  label,
7205
- value: value4,
7687
+ value: value5,
7206
7688
  onChange,
7207
7689
  invalid,
7208
7690
  placeholder,
@@ -7212,9 +7694,9 @@ function TextField({
7212
7694
  }) {
7213
7695
  const id = useId14();
7214
7696
  const errorId = `${id}-invalid`;
7215
- return /* @__PURE__ */ jsxs43(Field, { children: [
7216
- /* @__PURE__ */ jsx62(FieldLabel, { htmlFor: id, children: label }),
7217
- /* @__PURE__ */ jsx62(
7697
+ return /* @__PURE__ */ jsxs45(Field, { children: [
7698
+ /* @__PURE__ */ jsx64(FieldLabel, { htmlFor: id, children: label }),
7699
+ /* @__PURE__ */ jsx64(
7218
7700
  Input,
7219
7701
  {
7220
7702
  "aria-describedby": invalid == null ? void 0 : errorId,
@@ -7226,10 +7708,10 @@ function TextField({
7226
7708
  onChange: (e) => onChange(e.target.value),
7227
7709
  placeholder,
7228
7710
  type: "text",
7229
- value: value4
7711
+ value: value5
7230
7712
  }
7231
7713
  ),
7232
- invalid != null && /* @__PURE__ */ jsx62(FieldHint, { id: errorId, children: /* @__PURE__ */ jsx62(Text, { size: "xs", tone: "warn", children: invalid }) })
7714
+ invalid != null && /* @__PURE__ */ jsx64(FieldHint, { id: errorId, children: /* @__PURE__ */ jsx64(Text, { size: "xs", tone: "warn", children: invalid }) })
7233
7715
  ] });
7234
7716
  }
7235
7717
 
@@ -7237,13 +7719,13 @@ function TextField({
7237
7719
  import {
7238
7720
  TrajectoryKindLike
7239
7721
  } from "@ksp-gonogo/sitrep-sdk/spine";
7240
- import { jsx as jsx63, jsxs as jsxs44 } from "react/jsx-runtime";
7722
+ import { jsx as jsx65, jsxs as jsxs46 } from "react/jsx-runtime";
7241
7723
  function trajectoryWithheldCopy(withheld) {
7242
7724
  switch (withheld.reason) {
7243
7725
  case "no-horizon-stated":
7244
7726
  return {
7245
7727
  heading: "NO HORIZON STATED",
7246
- detail: "Nothing has said how far these elements answer for."
7728
+ detail: "Nothing says how far ahead these orbital elements can be trusted."
7247
7729
  };
7248
7730
  case "past-horizon":
7249
7731
  return withheld.trajectoryKind === TrajectoryKindLike.Integrated ? {
@@ -7251,7 +7733,7 @@ function trajectoryWithheldCopy(withheld) {
7251
7733
  detail: "The trajectory is not computed this far ahead yet."
7252
7734
  } : {
7253
7735
  heading: "PAST HORIZON",
7254
- detail: "These elements do not answer for the instant on screen."
7736
+ detail: "These orbital elements cannot be trusted this far ahead."
7255
7737
  };
7256
7738
  case "shape-not-stated":
7257
7739
  return {
@@ -7275,15 +7757,15 @@ function TrajectoryWithheldNote({
7275
7757
  compact = false
7276
7758
  }) {
7277
7759
  const { heading, detail } = trajectoryWithheldCopy(withheld);
7278
- return /* @__PURE__ */ jsx63(Tooltip, { text: compact ? detail : void 0, focusable: true, children: /* @__PURE__ */ jsxs44(Stack, { role: "status", children: [
7279
- /* @__PURE__ */ jsx63(Text, { size: "xs", children: heading }),
7280
- !compact && /* @__PURE__ */ jsx63(Text, { level: "muted", size: "xs", children: detail })
7760
+ return /* @__PURE__ */ jsx65(Tooltip, { text: compact ? detail : void 0, focusable: true, children: /* @__PURE__ */ jsxs46(Stack, { role: "status", children: [
7761
+ /* @__PURE__ */ jsx65(Text, { size: "xs", children: heading }),
7762
+ !compact && /* @__PURE__ */ jsx65(Text, { level: "muted", size: "xs", children: detail })
7281
7763
  ] }) });
7282
7764
  }
7283
7765
 
7284
7766
  // src/Truncate.tsx
7285
- import styled52 from "styled-components";
7286
- var Truncate = styled52.span`
7767
+ import styled53 from "styled-components";
7768
+ var Truncate = styled53.span`
7287
7769
  /* Its own theme colour rather than whatever the nearest element gives it, so no ancestor's default can reach the words. */
7288
7770
  color: var(--color-neutral-text);
7289
7771
  overflow: hidden;
@@ -7296,15 +7778,15 @@ var Truncate = styled52.span`
7296
7778
  // src/UnitInput.tsx
7297
7779
  import {
7298
7780
  affineVectorUnitFor,
7299
- value as value3
7781
+ value as value4
7300
7782
  } from "@ksp-gonogo/sitrep-sdk";
7301
7783
  import { useId as useId15, useState as useState18 } from "react";
7302
- import styled53 from "styled-components";
7303
- import { jsx as jsx64, jsxs as jsxs45 } from "react/jsx-runtime";
7784
+ import styled54 from "styled-components";
7785
+ import { jsx as jsx66, jsxs as jsxs47 } from "react/jsx-runtime";
7304
7786
  var INSTANT_WHEEL_PX = 112;
7305
7787
  function worth(symbol, unit) {
7306
7788
  try {
7307
- return value3(symbol, 1).in(unit).magnitude;
7789
+ return value4(symbol, 1).in(unit).magnitude;
7308
7790
  } catch {
7309
7791
  return Number.NaN;
7310
7792
  }
@@ -7330,28 +7812,28 @@ function UnitInput({
7330
7812
  }) {
7331
7813
  const id = useId15();
7332
7814
  const { shown: current, held, caption } = resolveCurrency(input);
7333
- const name = held ? /* @__PURE__ */ jsx64(HeldFigure, { caption, children: label }) : label;
7815
+ const name = held ? /* @__PURE__ */ jsx66(HeldFigure, { caption, children: label }) : label;
7334
7816
  const bounds = range;
7335
7817
  const magnitude = current ? current.magnitude : Number.NaN;
7336
7818
  const [typing, setTyping] = useState18({});
7337
7819
  const typed = (index) => typing[index] ?? null;
7338
7820
  const type = (index, next) => setTyping((held2) => ({ ...held2, [index]: next }));
7339
- const wheel = rate ? /* @__PURE__ */ jsxs45(Stack, { gap: "related-packed", children: [
7340
- /* @__PURE__ */ jsx64(
7821
+ const wheel = rate ? /* @__PURE__ */ jsxs47(Stack, { gap: "related-packed", children: [
7822
+ /* @__PURE__ */ jsx66(
7341
7823
  JogWheel,
7342
7824
  {
7343
7825
  mode: "rate",
7344
- ariaLabel: `${label} rate`,
7826
+ "aria-label": `${label} rate`,
7345
7827
  value: magnitude,
7346
7828
  step: rate.step,
7347
7829
  stepsPerSecond: rate.stepsPerSecond,
7348
7830
  disabled: disabled || !Number.isFinite(magnitude),
7349
7831
  format: isInstant(unit) ? caretDate : void 0,
7350
7832
  width: isInstant(unit) ? INSTANT_WHEEL_PX : void 0,
7351
- onChange: (next) => onChange(value3(unit, next))
7833
+ onChange: (next) => onChange(value4(unit, next))
7352
7834
  }
7353
7835
  ),
7354
- /* @__PURE__ */ jsx64(
7836
+ /* @__PURE__ */ jsx66(
7355
7837
  Text,
7356
7838
  {
7357
7839
  level: "faint",
@@ -7361,17 +7843,17 @@ function UnitInput({
7361
7843
  )
7362
7844
  ] }) : null;
7363
7845
  if (isInstant(unit)) {
7364
- return /* @__PURE__ */ jsxs45(Control, { children: [
7365
- /* @__PURE__ */ jsx64(GroupName, { "aria-hidden": "true", children: name }),
7366
- /* @__PURE__ */ jsxs45(Stack, { gap: "related-dense", children: [
7367
- /* @__PURE__ */ jsx64(
7846
+ return /* @__PURE__ */ jsxs47(Control, { children: [
7847
+ /* @__PURE__ */ jsx66(GroupName, { "aria-hidden": "true", children: name }),
7848
+ /* @__PURE__ */ jsxs47(Stack, { gap: "related-dense", children: [
7849
+ /* @__PURE__ */ jsx66(
7368
7850
  MissionDateField,
7369
7851
  {
7370
7852
  label: held && caption !== null ? `${label}, ${caption}` : label,
7371
7853
  value: Number.isFinite(magnitude) ? magnitude : null,
7372
7854
  disabled,
7373
7855
  steps: rate ? [] : void 0,
7374
- onChange: (ut) => onChange(value3(unit, ut))
7856
+ onChange: (ut) => onChange(value4(unit, ut))
7375
7857
  }
7376
7858
  ),
7377
7859
  wheel
@@ -7394,12 +7876,12 @@ function UnitInput({
7394
7876
  0
7395
7877
  );
7396
7878
  type(index, { text, against: amount });
7397
- onChange(value3(unit, total));
7879
+ onChange(value4(unit, total));
7398
7880
  };
7399
- return /* @__PURE__ */ jsxs45(Control, { children: [
7400
- /* @__PURE__ */ jsx64(GroupName, { id: `${id}-label`, children: name }),
7401
- /* @__PURE__ */ jsx64(RungRow, { role: "group", "aria-labelledby": `${id}-label`, children: rungs.map((symbol, index) => /* @__PURE__ */ jsxs45(RungCell, { children: [
7402
- /* @__PURE__ */ jsx64(
7881
+ return /* @__PURE__ */ jsxs47(Control, { children: [
7882
+ /* @__PURE__ */ jsx66(GroupName, { id: `${id}-label`, children: name }),
7883
+ /* @__PURE__ */ jsx66(RungRow, { role: "group", "aria-labelledby": `${id}-label`, children: rungs.map((symbol, index) => /* @__PURE__ */ jsxs47(RungCell, { children: [
7884
+ /* @__PURE__ */ jsx66(
7403
7885
  RungField,
7404
7886
  {
7405
7887
  type: "number",
@@ -7409,7 +7891,7 @@ function UnitInput({
7409
7891
  onChange: (event) => emit2(index, event.target.value)
7410
7892
  }
7411
7893
  ),
7412
- /* @__PURE__ */ jsx64(UnitSymbol, { "aria-hidden": "true", children: String(symbol) })
7894
+ /* @__PURE__ */ jsx66(UnitSymbol, { "aria-hidden": "true", children: String(symbol) })
7413
7895
  ] }, String(symbol))) }),
7414
7896
  wheel
7415
7897
  ] });
@@ -7418,13 +7900,13 @@ function UnitInput({
7418
7900
  const amount = readNumber(text);
7419
7901
  type(0, { text, against: amount ?? magnitude });
7420
7902
  if (amount !== void 0) {
7421
- onChange(value3(unit, amount));
7903
+ onChange(value4(unit, amount));
7422
7904
  }
7423
7905
  };
7424
- return /* @__PURE__ */ jsxs45(Control, { children: [
7425
- /* @__PURE__ */ jsx64(FieldName, { htmlFor: id, children: name }),
7426
- /* @__PURE__ */ jsxs45(ValueRow, { children: [
7427
- /* @__PURE__ */ jsx64(
7906
+ return /* @__PURE__ */ jsxs47(Control, { children: [
7907
+ /* @__PURE__ */ jsx66(FieldName, { htmlFor: id, children: name }),
7908
+ /* @__PURE__ */ jsxs47(ValueRow, { children: [
7909
+ /* @__PURE__ */ jsx66(
7428
7910
  SingleField,
7429
7911
  {
7430
7912
  id,
@@ -7437,9 +7919,9 @@ function UnitInput({
7437
7919
  onChange: (event) => emit(event.target.value)
7438
7920
  }
7439
7921
  ),
7440
- /* @__PURE__ */ jsx64(UnitSymbol, { "aria-hidden": "true", children: unit })
7922
+ /* @__PURE__ */ jsx66(UnitSymbol, { "aria-hidden": "true", children: unit })
7441
7923
  ] }),
7442
- bounds ? /* @__PURE__ */ jsx64(
7924
+ bounds ? /* @__PURE__ */ jsx66(
7443
7925
  Slider,
7444
7926
  {
7445
7927
  disabled,
@@ -7448,7 +7930,7 @@ function UnitInput({
7448
7930
  max: bounds.max,
7449
7931
  step: bounds.step ?? (bounds.max - bounds.min) / 100,
7450
7932
  value: Number.isFinite(magnitude) ? magnitude : bounds.min,
7451
- onChange: (event) => onChange(value3(unit, readNumber(event.target.value) ?? bounds.min))
7933
+ onChange: (event) => onChange(value4(unit, readNumber(event.target.value) ?? bounds.min))
7452
7934
  }
7453
7935
  ) : null,
7454
7936
  wheel
@@ -7479,7 +7961,7 @@ function readNumber(text) {
7479
7961
  function round(n) {
7480
7962
  return Number.isFinite(n) ? Math.round(n * 1e6) / 1e6 : 0;
7481
7963
  }
7482
- var Control = styled53.div`
7964
+ var Control = styled54.div`
7483
7965
  display: flex;
7484
7966
  flex-direction: column;
7485
7967
  gap: var(--gap-field-label-compact);
@@ -7490,19 +7972,19 @@ var nameStyles = `
7490
7972
  letter-spacing: 0.06em;
7491
7973
  text-transform: uppercase;
7492
7974
  `;
7493
- var FieldName = styled53.label`
7975
+ var FieldName = styled54.label`
7494
7976
  ${nameStyles}
7495
7977
  `;
7496
- var GroupName = styled53.span`
7978
+ var GroupName = styled54.span`
7497
7979
  ${nameStyles}
7498
7980
  `;
7499
- var ValueRow = styled53.div`
7981
+ var ValueRow = styled54.div`
7500
7982
  display: grid;
7501
7983
  grid-template-columns: 1fr auto;
7502
7984
  align-items: center;
7503
7985
  gap: var(--gap-value-tag);
7504
7986
  `;
7505
- var SingleField = styled53.input`
7987
+ var SingleField = styled54.input`
7506
7988
  background: var(--color-surface-panel);
7507
7989
  border: 1px solid var(--color-border-subtle);
7508
7990
  color: var(--color-text-primary);
@@ -7515,21 +7997,21 @@ var SingleField = styled53.input`
7515
7997
 
7516
7998
  ${focusRing}
7517
7999
  `;
7518
- var UnitSymbol = styled53.span`
8000
+ var UnitSymbol = styled54.span`
7519
8001
  font-size: var(--font-size-compact);
7520
8002
  color: var(--color-text-faint);
7521
8003
  `;
7522
- var RungRow = styled53.div`
8004
+ var RungRow = styled54.div`
7523
8005
  display: flex;
7524
8006
  gap: var(--gap-unit-parts);
7525
8007
  `;
7526
- var RungCell = styled53.div`
8008
+ var RungCell = styled54.div`
7527
8009
  display: grid;
7528
8010
  grid-template-columns: 1fr auto;
7529
8011
  align-items: center;
7530
8012
  gap: var(--gap-unit-suffix);
7531
8013
  `;
7532
- var RungField = styled53(SingleField)`
8014
+ var RungField = styled54(SingleField)`
7533
8015
  width: 4.5em;
7534
8016
  `;
7535
8017
 
@@ -7553,7 +8035,7 @@ function usePrefersReducedMotion() {
7553
8035
  }
7554
8036
 
7555
8037
  // src/vesselMark.tsx
7556
- import { jsx as jsx65, jsxs as jsxs46 } from "react/jsx-runtime";
8038
+ import { jsx as jsx67, jsxs as jsxs48 } from "react/jsx-runtime";
7557
8039
  var SQUARE_HALF = 0.86;
7558
8040
  var TRIANGLE = [
7559
8041
  [0, -1.15],
@@ -7627,7 +8109,7 @@ function VesselMarkSvg({
7627
8109
  keyline = false
7628
8110
  }) {
7629
8111
  const corners = state === "current" ? "" : cornersOf(state, 0, 0, r).map(([px, py]) => `${px},${py}`).join(" ");
7630
- return /* @__PURE__ */ jsxs46("g", { "data-vessel-mark": state, transform: `translate(${x} ${y})`, ...HIDDEN, children: [
8112
+ return /* @__PURE__ */ jsxs48("g", { "data-vessel-mark": state, transform: `translate(${x} ${y})`, ...HIDDEN, children: [
7631
8113
  keyline && KEYLINE_RINGS.map(({ ring, color, widths }) => {
7632
8114
  const border = {
7633
8115
  "data-vessel-keyline": ring,
@@ -7636,9 +8118,9 @@ function VesselMarkSvg({
7636
8118
  strokeWidth: keylineStroke(state, r, widths),
7637
8119
  strokeLinejoin: "round"
7638
8120
  };
7639
- return state === "current" ? /* @__PURE__ */ jsx65("circle", { r, ...border }, ring) : /* @__PURE__ */ jsx65("polygon", { points: corners, ...border }, ring);
8121
+ return state === "current" ? /* @__PURE__ */ jsx67("circle", { r, ...border }, ring) : /* @__PURE__ */ jsx67("polygon", { points: corners, ...border }, ring);
7640
8122
  }),
7641
- state === "current" ? /* @__PURE__ */ jsx65("circle", { r, fill: VESSEL_MARK.color }) : /* @__PURE__ */ jsx65(
8123
+ state === "current" ? /* @__PURE__ */ jsx67("circle", { r, fill: VESSEL_MARK.color }) : /* @__PURE__ */ jsx67(
7642
8124
  "polygon",
7643
8125
  {
7644
8126
  points: corners,
@@ -7728,12 +8210,12 @@ function paintVesselPositions(canvas, ctx, positions, radius = 4, options = {})
7728
8210
  }
7729
8211
 
7730
8212
  // src/WidgetMeters.tsx
7731
- import { jsx as jsx66 } from "react/jsx-runtime";
8213
+ import { jsx as jsx68 } from "react/jsx-runtime";
7732
8214
  function WidgetMeters({ row, style }) {
7733
8215
  const entries = useContributions("meters");
7734
8216
  const mine = entries.filter((entry) => entry.row === row);
7735
8217
  if (mine.length === 0) return null;
7736
- return /* @__PURE__ */ jsx66(MeterStack, { style, role: "group", "aria-label": "meters", children: mine.map((entry) => /* @__PURE__ */ jsx66(
8218
+ return /* @__PURE__ */ jsx68(MeterStack, { style, role: "group", "aria-label": "meters", children: mine.map((entry) => /* @__PURE__ */ jsx68(
7737
8219
  Meter,
7738
8220
  {
7739
8221
  label: entry.label,
@@ -7747,15 +8229,15 @@ function WidgetMeters({ row, style }) {
7747
8229
 
7748
8230
  // src/WidgetScope.tsx
7749
8231
  import { createContext as createContext3, useContext as useContext3, useMemo as useMemo5 } from "react";
7750
- import { jsx as jsx67 } from "react/jsx-runtime";
8232
+ import { jsx as jsx69 } from "react/jsx-runtime";
7751
8233
  var WidgetScopeContext = createContext3(null);
7752
8234
  function WidgetScopeProvider({
7753
8235
  widget,
7754
8236
  scope,
7755
8237
  children
7756
8238
  }) {
7757
- const value4 = useMemo5(() => ({ widget, scope }), [widget, scope]);
7758
- return /* @__PURE__ */ jsx67(WidgetScopeContext.Provider, { value: value4, children });
8239
+ const value5 = useMemo5(() => ({ widget, scope }), [widget, scope]);
8240
+ return /* @__PURE__ */ jsx69(WidgetScopeContext.Provider, { value: value5, children });
7759
8241
  }
7760
8242
  function useWidgetScope(componentId) {
7761
8243
  const published = useContext3(WidgetScopeContext);
@@ -7764,22 +8246,119 @@ function useWidgetScope(componentId) {
7764
8246
  }
7765
8247
 
7766
8248
  // src/widgetDeclaredTopics.ts
7767
- function widgetDeclaredTopics(def) {
8249
+ function widgetDeclaredTopics(def, config) {
7768
8250
  if (!def) return [];
7769
8251
  return dedupe([
7770
8252
  ...def.channels ?? [],
7771
8253
  ...def.optionalChannels ?? [],
7772
- ...def.dataRequirements ?? []
8254
+ ...def.dataRequirements ?? [],
8255
+ ...configTopics(def, config)
7773
8256
  ]);
7774
8257
  }
7775
- function widgetDrawnFields(def) {
8258
+ function widgetDrawnFields(def, config) {
8259
+ if (!def) return [];
8260
+ if (def.fields && def.fields.length > 0) {
8261
+ return dedupe([...def.fields, ...configTopics(def, config)]);
8262
+ }
8263
+ return widgetDeclaredTopics(def, config);
8264
+ }
8265
+ function widgetDrawnFamilies(def) {
7776
8266
  if (!def) return [];
7777
- if (def.fields && def.fields.length > 0) return dedupe(def.fields);
7778
- return widgetDeclaredTopics(def);
8267
+ return dedupe([
8268
+ ...def.channelFamilies ?? [],
8269
+ ...def.optionalChannelFamilies ?? []
8270
+ ]);
8271
+ }
8272
+ function configTopics(def, config) {
8273
+ if (!def.channelsFromConfig || config === void 0) return [];
8274
+ return def.channelsFromConfig(config);
7779
8275
  }
7780
8276
  function dedupe(values) {
7781
8277
  return [...new Set(values)];
7782
8278
  }
8279
+
8280
+ // src/wrappedMap.ts
8281
+ function splitAtPoleCrossings(points) {
8282
+ if (points.length === 0) return [];
8283
+ const runs = [[points[0]]];
8284
+ for (let i = 1; i < points.length; i++) {
8285
+ if (crossesAPole(points[i - 1], points[i])) runs.push([points[i]]);
8286
+ else runs[runs.length - 1].push(points[i]);
8287
+ }
8288
+ return runs;
8289
+ }
8290
+ function wrapPath(points, period, viewMin, viewMax) {
8291
+ if (points.length === 0 || !(period > 0)) return [];
8292
+ const xs = [points[0].x];
8293
+ let min = xs[0];
8294
+ let max = xs[0];
8295
+ for (let i = 1; i < points.length; i++) {
8296
+ const previous = xs[i - 1];
8297
+ const x = previous + wrapToHalfPeriod(points[i].x - previous, period);
8298
+ xs.push(x);
8299
+ if (x < min) min = x;
8300
+ if (x > max) max = x;
8301
+ }
8302
+ return repeatsInView(min, max, viewMin, viewMax, period).map(
8303
+ (shift) => points.map((point, i) => ({ ...point, x: xs[i] + shift }))
8304
+ );
8305
+ }
8306
+ function repeatsInView(min, max, viewMin, viewMax, period) {
8307
+ if (!(period > 0) || !Number.isFinite(min) || !Number.isFinite(max))
8308
+ return [];
8309
+ const first = Math.ceil((viewMin - max) / period);
8310
+ const last = Math.floor((viewMax - min) / period);
8311
+ const shifts = [];
8312
+ for (let k = first; k <= last; k++) shifts.push(k * period + 0);
8313
+ return shifts;
8314
+ }
8315
+ function wrapToHalfPeriod(delta, period) {
8316
+ const half = period / 2;
8317
+ return ((delta + half) % period + period) % period - half;
8318
+ }
8319
+ function crossesAPole(a, b) {
8320
+ const u = unitVector(a);
8321
+ const v = unitVector(b);
8322
+ const separation = angleBetween(u, v);
8323
+ if (separation === 0) return false;
8324
+ const normal = normalise(cross2(u, v));
8325
+ if (normal === null) return false;
8326
+ const missDistance = Math.asin(Math.min(1, Math.abs(normal[2])));
8327
+ if (missDistance >= separation) return false;
8328
+ const pole = [0, 0, a.lat + b.lat >= 0 ? 1 : -1];
8329
+ const closest = normalise(subtractProjection(pole, normal));
8330
+ if (closest === null) return false;
8331
+ const span = dot(u, v);
8332
+ return dot(u, closest) > span && dot(v, closest) > span;
8333
+ }
8334
+ function unitVector({ lat, lon }) {
8335
+ const phi = lat * Math.PI / 180;
8336
+ const lambda = lon * Math.PI / 180;
8337
+ const c = Math.cos(phi);
8338
+ return [c * Math.cos(lambda), c * Math.sin(lambda), Math.sin(phi)];
8339
+ }
8340
+ function dot(a, b) {
8341
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
8342
+ }
8343
+ function cross2(a, b) {
8344
+ return [
8345
+ a[1] * b[2] - a[2] * b[1],
8346
+ a[2] * b[0] - a[0] * b[2],
8347
+ a[0] * b[1] - a[1] * b[0]
8348
+ ];
8349
+ }
8350
+ function angleBetween(a, b) {
8351
+ return Math.acos(Math.max(-1, Math.min(1, dot(a, b))));
8352
+ }
8353
+ function subtractProjection(v, n) {
8354
+ const k = dot(v, n);
8355
+ return [v[0] - k * n[0], v[1] - k * n[1], v[2] - k * n[2]];
8356
+ }
8357
+ function normalise(v) {
8358
+ const length = Math.hypot(v[0], v[1], v[2]);
8359
+ if (length < 1e-12) return null;
8360
+ return [v[0] / length, v[1] / length, v[2] / length];
8361
+ }
7783
8362
  export {
7784
8363
  ARM_TIMEOUT_MS,
7785
8364
  ActionMenu,
@@ -7794,6 +8373,7 @@ export {
7794
8373
  AugmentSettingsProvider,
7795
8374
  AugmentSlot,
7796
8375
  AutoEmptyState,
8376
+ AvatarStack,
7797
8377
  Badge,
7798
8378
  Band,
7799
8379
  BellIcon,
@@ -7915,6 +8495,7 @@ export {
7915
8495
  PauseIcon,
7916
8496
  PencilIcon,
7917
8497
  PlayIcon,
8498
+ PlotCrosshair,
7918
8499
  PlusIcon,
7919
8500
  ProgradeIcon,
7920
8501
  PushUpIcon,
@@ -8000,7 +8581,6 @@ export {
8000
8581
  asQuantityish,
8001
8582
  audioCaptureSupport,
8002
8583
  badgeFace,
8003
- bandClaim,
8004
8584
  clearAugments,
8005
8585
  commandFailedSentence,
8006
8586
  commandFoundSentence,
@@ -8028,7 +8608,11 @@ export {
8028
8608
  gridFloor,
8029
8609
  gridToPixels,
8030
8610
  groupComboboxOptions,
8611
+ heldFigureOf,
8612
+ heldGradeOf,
8613
+ heldMarking,
8031
8614
  heldWord,
8615
+ initialsOf,
8032
8616
  kspCalendar,
8033
8617
  kspYearDays,
8034
8618
  magnitudeOf,
@@ -8041,11 +8625,14 @@ export {
8041
8625
  paintVesselMark,
8042
8626
  paintVesselPositions,
8043
8627
  placeGraphNotice,
8628
+ placePlotReadouts,
8044
8629
  placedOnScale,
8630
+ plotCrosshairShowsCard,
8045
8631
  quantityScale,
8046
8632
  railTagKey,
8047
8633
  reckoningBasisPhrase,
8048
8634
  registerAugment,
8635
+ repeatsInView,
8049
8636
  resolveCurrency,
8050
8637
  resourceColor,
8051
8638
  ribbonBoundaryX,
@@ -8057,6 +8644,7 @@ export {
8057
8644
  showsTiny,
8058
8645
  sizeDeltaFor,
8059
8646
  speakQuantity,
8647
+ splitAtPoleCrossings,
8060
8648
  standsApart,
8061
8649
  toInFlightListItems,
8062
8650
  toneEdge,
@@ -8094,9 +8682,11 @@ export {
8094
8682
  utOfParts,
8095
8683
  waveformPath,
8096
8684
  widgetDeclaredTopics,
8685
+ widgetDrawnFamilies,
8097
8686
  widgetDrawnFields,
8098
8687
  withSizeDelta,
8099
8688
  worstSeverity,
8689
+ wrapPath,
8100
8690
  writeQuantity,
8101
8691
  writtenAs,
8102
8692
  writtenQuantity