@le-space/ui 0.3.20 → 0.3.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@le-space/ui",
3
- "version": "0.3.20",
3
+ "version": "0.3.22",
4
4
  "description": "Floating Aleph sponsor relay UI components for Svelte and React.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -36,8 +36,8 @@
36
36
  "access": "public"
37
37
  },
38
38
  "dependencies": {
39
- "@le-space/browser": "0.3.20",
40
- "@le-space/core": "0.3.20",
39
+ "@le-space/browser": "0.3.22",
40
+ "@le-space/core": "0.3.22",
41
41
  "viem": "^2.38.5"
42
42
  },
43
43
  "peerDependencies": {
package/react/index.d.ts CHANGED
@@ -303,7 +303,7 @@ declare class SponsorRelayController {
303
303
  private runtimeCooldownByHash;
304
304
  private runtimeDetailsByHash;
305
305
  private debugEnabled;
306
- private lastRuntimeReadyHash;
306
+ private lastCompletedDeploymentHash;
307
307
  constructor(props?: SponsorRelayProps);
308
308
  subscribeToDeploymentProgress(listener: DeploymentProgressListener): () => void;
309
309
  subscribe(subscriber: SponsorRelaySubscriber): () => void;
package/react/index.js CHANGED
@@ -39,7 +39,7 @@ var RECENT_INSTANCE_RUNTIME_GRACE_MS = 10 * 60 * 1e3;
39
39
  var DEPLOYMENT_PENDING_WARNING_MS = 3 * 60 * 1e3;
40
40
 
41
41
  // src/shared/package-version.ts
42
- var UI_PACKAGE_VERSION = "0.3.20";
42
+ var UI_PACKAGE_VERSION = "0.3.22";
43
43
 
44
44
  // src/shared/format.ts
45
45
  function shortHash(value, head = 8, tail = 6) {
@@ -2951,7 +2951,7 @@ var SponsorRelayController = class {
2951
2951
  runtimeCooldownByHash = /* @__PURE__ */ new Map();
2952
2952
  runtimeDetailsByHash = /* @__PURE__ */ new Map();
2953
2953
  debugEnabled;
2954
- lastRuntimeReadyHash = null;
2954
+ lastCompletedDeploymentHash = null;
2955
2955
  constructor(props = {}) {
2956
2956
  this.props = props;
2957
2957
  this.state = defaultState(props);
@@ -3063,7 +3063,7 @@ var SponsorRelayController = class {
3063
3063
  this.emitProgress({
3064
3064
  stage: "deployment-confirmed",
3065
3065
  label: "Applying relay networking",
3066
- progress: 94,
3066
+ progress: 93,
3067
3067
  status: "info",
3068
3068
  itemHash: args.itemHash,
3069
3069
  detail: "Publishing the host port mapping into the guest relay configuration."
@@ -3099,7 +3099,7 @@ var SponsorRelayController = class {
3099
3099
  this.emitProgress({
3100
3100
  stage: "deployment-confirmed",
3101
3101
  label: "Publishing relay config",
3102
- progress: 94,
3102
+ progress: 93,
3103
3103
  status: "info",
3104
3104
  itemHash: args.itemHash,
3105
3105
  detail: "Publishing runtime networking into the Aleph guest bootstrap config aggregate."
@@ -3196,7 +3196,7 @@ var SponsorRelayController = class {
3196
3196
  this.emitProgress({
3197
3197
  stage: "publishing-bootstrap",
3198
3198
  label: "Waiting for guest bootstrap registration",
3199
- progress: 96,
3199
+ progress: 97,
3200
3200
  status: "info",
3201
3201
  itemHash: args.itemHash,
3202
3202
  detail: "Waiting for the relay VM to publish its own bootstrap registration to Aleph."
@@ -3251,7 +3251,7 @@ var SponsorRelayController = class {
3251
3251
  }
3252
3252
  const currentProgress = this.state.deploymentProgress;
3253
3253
  const currentProgressIsForLatestHash = currentProgress.itemHash === itemHash || currentProgress.itemHash == null && currentProgress.stage !== "idle" && currentProgress.stage !== "error";
3254
- const keepTerminalSuccess = this.lastRuntimeReadyHash === itemHash || currentProgressIsForLatestHash && currentProgress.stage === "completed" && currentProgress.status === "success";
3254
+ const keepTerminalSuccess = this.lastCompletedDeploymentHash === itemHash || currentProgressIsForLatestHash && currentProgress.stage === "completed" && currentProgress.status === "success";
3255
3255
  const status = latest.details.messageStatus;
3256
3256
  if (status === "rejected") {
3257
3257
  this.emitProgress({
@@ -3305,12 +3305,12 @@ var SponsorRelayController = class {
3305
3305
  return;
3306
3306
  }
3307
3307
  this.emitProgress({
3308
- stage: "completed",
3308
+ stage: "deployment-confirmed",
3309
3309
  label: "Runtime ready",
3310
- progress: 100,
3311
- status: "success",
3310
+ progress: 92,
3311
+ status: "info",
3312
3312
  itemHash,
3313
- detail: "Deployment processed and runtime networking is available."
3313
+ detail: "Deployment processed and runtime networking is available. Finishing relay setup and bootstrap verification."
3314
3314
  });
3315
3315
  }
3316
3316
  canSkipRuntimeRefresh(instance) {
@@ -3761,7 +3761,7 @@ var SponsorRelayController = class {
3761
3761
  crnHash: candidateCrn.hash,
3762
3762
  crnName: candidateCrn.name
3763
3763
  });
3764
- this.lastRuntimeReadyHash = null;
3764
+ this.lastCompletedDeploymentHash = null;
3765
3765
  const inspection = await waitForDeploymentResult2(result.itemHash, {
3766
3766
  rootfsRef: this.state.manifest.rootfsItemHash,
3767
3767
  apiHost: this.client.apiHost,
@@ -3867,12 +3867,12 @@ var SponsorRelayController = class {
3867
3867
  onAttempt: (runtime2) => {
3868
3868
  if (runtime2.hostIpv4 && Object.keys(runtime2.mappedPorts ?? {}).length > 0) {
3869
3869
  this.emitProgress({
3870
- stage: "completed",
3870
+ stage: "deployment-confirmed",
3871
3871
  label: "Runtime ready",
3872
- progress: 100,
3873
- status: "success",
3872
+ progress: 92,
3873
+ status: "info",
3874
3874
  itemHash: result.itemHash,
3875
- detail: "Runtime networking and mapped ports are now available."
3875
+ detail: "Runtime networking and mapped ports are now available. Finishing relay setup and bootstrap verification."
3876
3876
  });
3877
3877
  return;
3878
3878
  }
@@ -3892,7 +3892,6 @@ var SponsorRelayController = class {
3892
3892
  );
3893
3893
  }
3894
3894
  this.trace("deploy:runtime-ready", runtime);
3895
- this.lastRuntimeReadyHash = result.itemHash;
3896
3895
  this.rememberRuntimeDetails(result.itemHash, {
3897
3896
  messageStatus: "processed",
3898
3897
  allocationSource: runtime.allocation?.source ?? null,
@@ -3917,12 +3916,21 @@ var SponsorRelayController = class {
3917
3916
  this.emitProgress({
3918
3917
  stage: "refreshing-instances",
3919
3918
  label: "Refreshing instances",
3920
- progress: 96,
3919
+ progress: 99,
3921
3920
  status: "info",
3922
3921
  itemHash: result.itemHash,
3923
3922
  detail: "Reloading deployments and runtime state."
3924
3923
  });
3925
3924
  await this.refresh();
3925
+ this.lastCompletedDeploymentHash = result.itemHash;
3926
+ this.emitProgress({
3927
+ stage: "completed",
3928
+ label: "Relay ready",
3929
+ progress: 100,
3930
+ status: "success",
3931
+ itemHash: result.itemHash,
3932
+ detail: "Relay runtime, setup, metadata, and bootstrap registration are confirmed."
3933
+ });
3926
3934
  return;
3927
3935
  } catch (error) {
3928
3936
  lastError = error instanceof Error ? error : new Error(String(error));
@@ -4192,6 +4200,12 @@ function progressBadgeLabel(stage) {
4192
4200
  }
4193
4201
  }
4194
4202
  var COMPLETED_PROGRESS_VISIBLE_MS = 12e3;
4203
+ var POLLING_STAGES = /* @__PURE__ */ new Set([
4204
+ "waiting-for-aleph",
4205
+ "deployment-confirmed",
4206
+ "publishing-bootstrap",
4207
+ "refreshing-instances"
4208
+ ]);
4195
4209
  function isDeploymentProgressVisible(state) {
4196
4210
  const stage = state.deploymentProgress.stage;
4197
4211
  if (stage === "idle") {
@@ -4205,6 +4219,21 @@ function isDeploymentProgressVisible(state) {
4205
4219
  }
4206
4220
  return true;
4207
4221
  }
4222
+ function pollingIndicator(state) {
4223
+ if (state.busy.refreshing) {
4224
+ return {
4225
+ label: "Checking relay state",
4226
+ detail: state.statusText || "Refreshing relay sponsor data from Aleph and the selected CRN."
4227
+ };
4228
+ }
4229
+ if (!POLLING_STAGES.has(state.deploymentProgress.stage)) {
4230
+ return null;
4231
+ }
4232
+ return {
4233
+ label: state.deploymentProgress.label || "Polling relay state",
4234
+ detail: state.deploymentProgress.detail || state.statusText || "Waiting for the next confirmed relay state from Aleph."
4235
+ };
4236
+ }
4208
4237
  function launcherIndicator(state) {
4209
4238
  if (state.deploymentProgress.stage !== "idle" && state.deploymentProgress.stage !== "completed") {
4210
4239
  return {
@@ -4346,6 +4375,7 @@ function SponsorRelayFab(props) {
4346
4375
  }, [launcherMode]);
4347
4376
  const progressActive = state.deploymentProgress.stage !== "idle" && state.deploymentProgress.stage !== "completed" && state.deploymentProgress.stage !== "error";
4348
4377
  const deploymentProgressVisible = isDeploymentProgressVisible(state);
4378
+ const pollingState = pollingIndicator(state);
4349
4379
  const pulseScale = progressActive ? 1.03 : hovered ? 1.015 : 1;
4350
4380
  const pulseShadow = progressActive ? `0 0 0 4px ${progressToneColor(indicator.tone)}22, 0 12px 28px rgba(15, 23, 42, 0.22)` : successFlash ? `0 0 0 5px rgba(55, 214, 122, 0.22), 0 14px 32px rgba(55, 214, 122, 0.22)` : launcherMode === "inline" ? hovered ? "var(--le-space-sponsor-relay-launcher-hover-shadow, 0 14px 30px rgba(79, 70, 229, 0.28))" : "var(--le-space-sponsor-relay-launcher-shadow, 0 10px 24px rgba(99, 102, 241, 0.22))" : void 0;
4351
4381
  const inlineButtonBackground = themedLauncherBackground;
@@ -4366,6 +4396,7 @@ function SponsorRelayFab(props) {
4366
4396
  };
4367
4397
  const launcherLabel = launcherMode === "inline" && compactInlineLabel ? "Relay" : "Sponsor Relay";
4368
4398
  return /* @__PURE__ */ jsxs(Fragment, { children: [
4399
+ /* @__PURE__ */ jsx("style", { children: `@keyframes leSpaceRelayPulse { 0%, 100% { transform: scale(1); opacity: 0.74; } 50% { transform: scale(1.22); opacity: 1; } }` }),
4369
4400
  /* @__PURE__ */ jsxs(
4370
4401
  "button",
4371
4402
  {
@@ -4460,7 +4491,8 @@ function SponsorRelayFab(props) {
4460
4491
  background: progressToneColor(indicator.tone),
4461
4492
  boxShadow: `0 0 0 ${progressActive ? "4px" : "3px"} ${progressToneColor(indicator.tone)}22`,
4462
4493
  transform: `scale(${progressActive ? 1.12 : successFlash ? 1.18 : 1})`,
4463
- transition: "transform 180ms ease, box-shadow 220ms ease"
4494
+ transition: "transform 180ms ease, box-shadow 220ms ease",
4495
+ animation: pollingState ? "leSpaceRelayPulse 1.6s ease-in-out infinite" : void 0
4464
4496
  }
4465
4497
  }
4466
4498
  ),
@@ -4542,6 +4574,52 @@ function SponsorRelayFab(props) {
4542
4574
  ),
4543
4575
  /* @__PURE__ */ jsx("p", { style: { color: "#9fb2ca" }, children: state.statusText }),
4544
4576
  state.errorText ? /* @__PURE__ */ jsx("p", { style: { color: "#ffd9d9" }, children: state.errorText }) : null,
4577
+ pollingState ? /* @__PURE__ */ jsxs(
4578
+ "div",
4579
+ {
4580
+ "aria-live": "polite",
4581
+ style: {
4582
+ marginTop: "0.25rem",
4583
+ marginBottom: "0.8rem",
4584
+ padding: "0.7rem 0.8rem",
4585
+ borderRadius: "1rem",
4586
+ border: "1px solid rgba(125, 211, 252, 0.18)",
4587
+ background: "linear-gradient(180deg, rgba(59, 130, 246, 0.12), rgba(59, 130, 246, 0.05))",
4588
+ display: "grid",
4589
+ gap: "0.28rem"
4590
+ },
4591
+ children: [
4592
+ /* @__PURE__ */ jsxs(
4593
+ "div",
4594
+ {
4595
+ style: {
4596
+ display: "inline-flex",
4597
+ alignItems: "center",
4598
+ gap: "0.45rem"
4599
+ },
4600
+ children: [
4601
+ /* @__PURE__ */ jsx(
4602
+ "span",
4603
+ {
4604
+ "aria-hidden": "true",
4605
+ style: {
4606
+ width: "0.62rem",
4607
+ height: "0.62rem",
4608
+ borderRadius: "999px",
4609
+ background: progressToneColor("info"),
4610
+ boxShadow: `0 0 0 3px ${progressToneColor("info")}22`,
4611
+ animation: "leSpaceRelayPulse 1.6s ease-in-out infinite"
4612
+ }
4613
+ }
4614
+ ),
4615
+ /* @__PURE__ */ jsx("strong", { style: { fontSize: "0.88rem" }, children: pollingState.label })
4616
+ ]
4617
+ }
4618
+ ),
4619
+ /* @__PURE__ */ jsx("small", { style: { color: "#9fb2ca", lineHeight: 1.35 }, children: pollingState.detail })
4620
+ ]
4621
+ }
4622
+ ) : null,
4545
4623
  deploymentProgressVisible ? /* @__PURE__ */ jsxs(
4546
4624
  "div",
4547
4625
  {
package/shared/index.d.ts CHANGED
@@ -304,7 +304,7 @@ declare const STALE_INSTANCE_ALLOCATION_COOLDOWN_MS: number;
304
304
  declare const RECENT_INSTANCE_RUNTIME_GRACE_MS: number;
305
305
  declare const DEPLOYMENT_PENDING_WARNING_MS: number;
306
306
 
307
- declare const UI_PACKAGE_VERSION = "0.3.20";
307
+ declare const UI_PACKAGE_VERSION = "0.3.22";
308
308
 
309
309
  interface RootfsRequiredPortForward {
310
310
  port: number;
@@ -353,7 +353,7 @@ declare class SponsorRelayController {
353
353
  private runtimeCooldownByHash;
354
354
  private runtimeDetailsByHash;
355
355
  private debugEnabled;
356
- private lastRuntimeReadyHash;
356
+ private lastCompletedDeploymentHash;
357
357
  constructor(props?: SponsorRelayProps);
358
358
  subscribeToDeploymentProgress(listener: DeploymentProgressListener): () => void;
359
359
  subscribe(subscriber: SponsorRelaySubscriber): () => void;
package/shared/index.js CHANGED
@@ -38,7 +38,7 @@ var RECENT_INSTANCE_RUNTIME_GRACE_MS = 10 * 60 * 1e3;
38
38
  var DEPLOYMENT_PENDING_WARNING_MS = 3 * 60 * 1e3;
39
39
 
40
40
  // src/shared/package-version.ts
41
- var UI_PACKAGE_VERSION = "0.3.20";
41
+ var UI_PACKAGE_VERSION = "0.3.22";
42
42
 
43
43
  // src/shared/format.ts
44
44
  function shortHash(value, head = 8, tail = 6) {
@@ -2950,7 +2950,7 @@ var SponsorRelayController = class {
2950
2950
  runtimeCooldownByHash = /* @__PURE__ */ new Map();
2951
2951
  runtimeDetailsByHash = /* @__PURE__ */ new Map();
2952
2952
  debugEnabled;
2953
- lastRuntimeReadyHash = null;
2953
+ lastCompletedDeploymentHash = null;
2954
2954
  constructor(props = {}) {
2955
2955
  this.props = props;
2956
2956
  this.state = defaultState(props);
@@ -3062,7 +3062,7 @@ var SponsorRelayController = class {
3062
3062
  this.emitProgress({
3063
3063
  stage: "deployment-confirmed",
3064
3064
  label: "Applying relay networking",
3065
- progress: 94,
3065
+ progress: 93,
3066
3066
  status: "info",
3067
3067
  itemHash: args.itemHash,
3068
3068
  detail: "Publishing the host port mapping into the guest relay configuration."
@@ -3098,7 +3098,7 @@ var SponsorRelayController = class {
3098
3098
  this.emitProgress({
3099
3099
  stage: "deployment-confirmed",
3100
3100
  label: "Publishing relay config",
3101
- progress: 94,
3101
+ progress: 93,
3102
3102
  status: "info",
3103
3103
  itemHash: args.itemHash,
3104
3104
  detail: "Publishing runtime networking into the Aleph guest bootstrap config aggregate."
@@ -3195,7 +3195,7 @@ var SponsorRelayController = class {
3195
3195
  this.emitProgress({
3196
3196
  stage: "publishing-bootstrap",
3197
3197
  label: "Waiting for guest bootstrap registration",
3198
- progress: 96,
3198
+ progress: 97,
3199
3199
  status: "info",
3200
3200
  itemHash: args.itemHash,
3201
3201
  detail: "Waiting for the relay VM to publish its own bootstrap registration to Aleph."
@@ -3250,7 +3250,7 @@ var SponsorRelayController = class {
3250
3250
  }
3251
3251
  const currentProgress = this.state.deploymentProgress;
3252
3252
  const currentProgressIsForLatestHash = currentProgress.itemHash === itemHash || currentProgress.itemHash == null && currentProgress.stage !== "idle" && currentProgress.stage !== "error";
3253
- const keepTerminalSuccess = this.lastRuntimeReadyHash === itemHash || currentProgressIsForLatestHash && currentProgress.stage === "completed" && currentProgress.status === "success";
3253
+ const keepTerminalSuccess = this.lastCompletedDeploymentHash === itemHash || currentProgressIsForLatestHash && currentProgress.stage === "completed" && currentProgress.status === "success";
3254
3254
  const status = latest.details.messageStatus;
3255
3255
  if (status === "rejected") {
3256
3256
  this.emitProgress({
@@ -3304,12 +3304,12 @@ var SponsorRelayController = class {
3304
3304
  return;
3305
3305
  }
3306
3306
  this.emitProgress({
3307
- stage: "completed",
3307
+ stage: "deployment-confirmed",
3308
3308
  label: "Runtime ready",
3309
- progress: 100,
3310
- status: "success",
3309
+ progress: 92,
3310
+ status: "info",
3311
3311
  itemHash,
3312
- detail: "Deployment processed and runtime networking is available."
3312
+ detail: "Deployment processed and runtime networking is available. Finishing relay setup and bootstrap verification."
3313
3313
  });
3314
3314
  }
3315
3315
  canSkipRuntimeRefresh(instance) {
@@ -3760,7 +3760,7 @@ var SponsorRelayController = class {
3760
3760
  crnHash: candidateCrn.hash,
3761
3761
  crnName: candidateCrn.name
3762
3762
  });
3763
- this.lastRuntimeReadyHash = null;
3763
+ this.lastCompletedDeploymentHash = null;
3764
3764
  const inspection = await waitForDeploymentResult2(result.itemHash, {
3765
3765
  rootfsRef: this.state.manifest.rootfsItemHash,
3766
3766
  apiHost: this.client.apiHost,
@@ -3866,12 +3866,12 @@ var SponsorRelayController = class {
3866
3866
  onAttempt: (runtime2) => {
3867
3867
  if (runtime2.hostIpv4 && Object.keys(runtime2.mappedPorts ?? {}).length > 0) {
3868
3868
  this.emitProgress({
3869
- stage: "completed",
3869
+ stage: "deployment-confirmed",
3870
3870
  label: "Runtime ready",
3871
- progress: 100,
3872
- status: "success",
3871
+ progress: 92,
3872
+ status: "info",
3873
3873
  itemHash: result.itemHash,
3874
- detail: "Runtime networking and mapped ports are now available."
3874
+ detail: "Runtime networking and mapped ports are now available. Finishing relay setup and bootstrap verification."
3875
3875
  });
3876
3876
  return;
3877
3877
  }
@@ -3891,7 +3891,6 @@ var SponsorRelayController = class {
3891
3891
  );
3892
3892
  }
3893
3893
  this.trace("deploy:runtime-ready", runtime);
3894
- this.lastRuntimeReadyHash = result.itemHash;
3895
3894
  this.rememberRuntimeDetails(result.itemHash, {
3896
3895
  messageStatus: "processed",
3897
3896
  allocationSource: runtime.allocation?.source ?? null,
@@ -3916,12 +3915,21 @@ var SponsorRelayController = class {
3916
3915
  this.emitProgress({
3917
3916
  stage: "refreshing-instances",
3918
3917
  label: "Refreshing instances",
3919
- progress: 96,
3918
+ progress: 99,
3920
3919
  status: "info",
3921
3920
  itemHash: result.itemHash,
3922
3921
  detail: "Reloading deployments and runtime state."
3923
3922
  });
3924
3923
  await this.refresh();
3924
+ this.lastCompletedDeploymentHash = result.itemHash;
3925
+ this.emitProgress({
3926
+ stage: "completed",
3927
+ label: "Relay ready",
3928
+ progress: 100,
3929
+ status: "success",
3930
+ itemHash: result.itemHash,
3931
+ detail: "Relay runtime, setup, metadata, and bootstrap registration are confirmed."
3932
+ });
3925
3933
  return;
3926
3934
  } catch (error) {
3927
3935
  lastError = error instanceof Error ? error : new Error(String(error));
@@ -42,6 +42,15 @@ export let apiHost = undefined
42
42
  const versionLabel = resolvedVersion.trim()
43
43
  ? (resolvedVersion.trim().startsWith('v') ? resolvedVersion.trim() : `v${resolvedVersion.trim()}`)
44
44
  : ''
45
+ const pollingStages = new Set(['waiting-for-aleph', 'deployment-confirmed', 'publishing-bootstrap', 'refreshing-instances'])
46
+
47
+ $: pollingActive = state.busy.refreshing || pollingStages.has(state.deploymentProgress.stage)
48
+ $: pollingLabel = state.busy.refreshing
49
+ ? 'Checking relay state'
50
+ : (state.deploymentProgress.label || 'Polling relay state')
51
+ $: pollingDetail = state.busy.refreshing
52
+ ? (state.statusText || 'Refreshing relay sponsor data from Aleph and the selected CRN.')
53
+ : (state.deploymentProgress.detail || state.statusText || 'Waiting for the next confirmed relay state from Aleph.')
45
54
 
46
55
  onMount(async () => {
47
56
  const unsubscribe = controller.subscribe((next) => {
@@ -113,6 +122,16 @@ export let apiHost = undefined
113
122
  {/if}
114
123
  <p class="status-text">{state.statusText}</p>
115
124
 
125
+ {#if pollingActive}
126
+ <div class="polling-row" aria-live="polite">
127
+ <div class="polling-head">
128
+ <StatusLed tone="idle" pulse={true} />
129
+ <strong>{pollingLabel}</strong>
130
+ </div>
131
+ <small>{pollingDetail}</small>
132
+ </div>
133
+ {/if}
134
+
116
135
  <div class="grid">
117
136
  <label class="field">
118
137
  <span>Instance Name</span>
@@ -319,6 +338,31 @@ export let apiHost = undefined
319
338
  justify-content: space-between;
320
339
  }
321
340
 
341
+ .polling-row {
342
+ display: grid;
343
+ gap: 0.28rem;
344
+ margin: 0.25rem 0 0.8rem;
345
+ padding: 0.7rem 0.85rem;
346
+ border-radius: 1rem;
347
+ background: linear-gradient(180deg, rgba(59, 130, 246, 0.12), rgba(59, 130, 246, 0.05));
348
+ border: 1px solid rgba(125, 211, 252, 0.18);
349
+ }
350
+
351
+ .polling-head {
352
+ display: inline-flex;
353
+ align-items: center;
354
+ gap: 0.45rem;
355
+ }
356
+
357
+ .polling-row strong {
358
+ font-size: 0.88rem;
359
+ }
360
+
361
+ .polling-row small {
362
+ color: var(--relay-text-dim);
363
+ line-height: 1.35;
364
+ }
365
+
322
366
  .eyebrow,
323
367
  .mini-label,
324
368
  .field span,