/* @utf/halo 0.2.0 *//*! @utf/halo v0.2.0 -- generated by scripts/build.mjs. Edit src/, not dist/. */
/* ============================================================
   @utf/halo -- design tokens (:root)
   Single source of truth for Halo's color / space / type scale.
   Consumers import these via @utf/halo/tokens.css or the full bundle.
   ============================================================ */
:root {
  color-scheme: dark;  /* native dark scrollbars / form controls / autofill to match the dark UI */
  /* ---------- Color: Surface tiers ---------- */
  --color-background: #0A0B0F;
  --color-surface: #14151C;
  --color-elevated: #1E2029;
  --color-overlay: rgba(10, 11, 15, 0.72);

  /* ---------- Color: Borders ---------- */
  --color-border: #2A2D38;
  --color-border-strong: #3A3D4A;
  --color-border-soft: rgba(255, 255, 255, 0.04);

  /* ---------- Color: Foreground ---------- */
  --color-text-primary: #F2F4F8;
  --color-text-secondary: #9AA0AE;
  --color-text-muted: #5C6170;
  --color-text-inverse: #0A0B0F;

  /* ---------- Color: Brand ---------- */
  --color-primary: #5B6BFF;
  --color-primary-hover: #7886FF;
  --color-primary-pressed: #4A59E6;
  --color-primary-soft: rgba(91, 107, 255, 0.12);

  /* ---------- Color: Signal ---------- */
  --color-success: #2BE08C;
  --color-warning: #F5D547;
  --color-info: #3DD7E5;
  --color-danger: #FF3A5C;

  --color-success-soft: rgba(43, 224, 140, 0.12);
  --color-warning-soft: rgba(245, 213, 71, 0.14);
  --color-info-soft: rgba(61, 215, 229, 0.14);
  --color-danger-soft: rgba(255, 58, 92, 0.14);

  /* "error" is an alias of "danger" (app markup emits data-tone="error") */
  --color-error: var(--color-danger);
  --color-error-soft: var(--color-danger-soft);

  /* ---------- Typography ---------- */
  --font-display: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Inter", sans-serif;
  --font-body: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Inter", sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  --text-display-size: clamp(2.75rem, 6vw, 4.5rem);
  --text-display-weight: 600;
  --text-display-tracking: -0.03em;
  --text-display-leading: 1.04;

  --text-headline-lg-size: 2.25rem;
  --text-headline-lg-weight: 600;
  --text-headline-lg-tracking: -0.02em;
  --text-headline-lg-leading: 1.12;

  --text-headline-md-size: 1.5rem;
  --text-headline-md-weight: 600;
  --text-headline-md-tracking: -0.015em;
  --text-headline-md-leading: 1.2;

  --text-title-md-size: 1.125rem;
  --text-title-md-weight: 600;
  --text-title-md-tracking: -0.01em;
  --text-title-md-leading: 1.3;

  --text-body-md-size: 0.9375rem;
  --text-body-md-weight: 400;
  --text-body-md-tracking: -0.005em;
  --text-body-md-leading: 1.55;

  --text-body-sm-size: 0.8125rem;
  --text-body-sm-weight: 400;
  --text-body-sm-tracking: 0;
  --text-body-sm-leading: 1.5;

  --text-label-sm-size: 0.75rem;
  --text-label-sm-weight: 500;
  --text-label-sm-tracking: 0.08em;
  --text-label-sm-leading: 1.2;

  --text-mono-sm-size: 0.8125rem;
  --text-mono-sm-weight: 500;
  --text-mono-sm-tracking: 0;
  --text-mono-sm-leading: 1.4;

  --text-metric-size: 2.5rem;
  --text-metric-weight: 600;
  --text-metric-tracking: -0.02em;
  --text-metric-leading: 1;

  /* ---------- Spacing ---------- */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-8: 32px;
  --space-10: 40px;
  --space-12: 48px;
  --space-16: 64px;
  --space-20: 80px;

  /* ---------- Radius ---------- */
  --radius-none: 0px;
  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 16px;
  --radius-xl: 24px;
  --radius-full: 999px;

  /* ---------- Border ---------- */
  --border-width: 1px;
  --border-width-thick: 1.5px;

  /* ---------- Elevation ---------- */
  --shadow-sm: 0 1px 0 rgba(255, 255, 255, 0.02) inset, 0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow-md: 0 8px 24px rgba(0, 0, 0, 0.45), 0 1px 0 rgba(255, 255, 255, 0.03) inset;
  --shadow-lg: 0 24px 60px rgba(0, 0, 0, 0.55), 0 1px 0 rgba(255, 255, 255, 0.04) inset;

  /* ---------- Focus ---------- */
  --focus-ring: 0 0 0 3px rgba(91, 107, 255, 0.35);
  --focus-ring-color: rgba(91, 107, 255, 0.35);

  /* ---------- Motion ---------- */
  --motion-fast: 120ms;
  --motion-base: 150ms;
  --motion-slow: 240ms;
  --easing-standard: cubic-bezier(0.2, 0.6, 0.2, 1);

  /* ---------- Layout ---------- */
  --container-max: 1200px;
  --container-pad: clamp(20px, 4vw, 48px);
}

/* ============================================================
   @utf/halo -- base, typography, layout & components
   (reset, .t-* type scale, layout primitives, .btn/.card/.input/
    .modal/.table/.toggle/... and daisyUI-compatible component names)
   ============================================================ */
/* =============================================================
   Reset and base
   ============================================================= */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
}

body {
  background-color: var(--color-background);
  color: var(--color-text-primary);
  font-family: var(--font-body);
  font-size: var(--text-body-md-size);
  line-height: var(--text-body-md-leading);
  letter-spacing: var(--text-body-md-tracking);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

::selection {
  background-color: var(--color-primary-soft);
  color: var(--color-text-primary);
}

img,
svg {
  display: block;
  max-width: 100%;
}

hr {
  border: 0;
  border-top: var(--border-width) solid var(--color-border);
  margin: 0;
}

/* =============================================================
   Typography utilities
   ============================================================= */

.t-display {
  font-family: var(--font-display);
  font-size: var(--text-display-size);
  font-weight: var(--text-display-weight);
  letter-spacing: var(--text-display-tracking);
  line-height: var(--text-display-leading);
  color: var(--color-text-primary);
  margin: 0;
}

.t-headline-lg {
  font-family: var(--font-display);
  font-size: var(--text-headline-lg-size);
  font-weight: var(--text-headline-lg-weight);
  letter-spacing: var(--text-headline-lg-tracking);
  line-height: var(--text-headline-lg-leading);
  color: var(--color-text-primary);
  margin: 0;
}

.t-headline-md {
  font-family: var(--font-display);
  font-size: var(--text-headline-md-size);
  font-weight: var(--text-headline-md-weight);
  letter-spacing: var(--text-headline-md-tracking);
  line-height: var(--text-headline-md-leading);
  color: var(--color-text-primary);
  margin: 0;
}

.t-title-md {
  font-family: var(--font-display);
  font-size: var(--text-title-md-size);
  font-weight: var(--text-title-md-weight);
  letter-spacing: var(--text-title-md-tracking);
  line-height: var(--text-title-md-leading);
  color: var(--color-text-primary);
  margin: 0;
}

.t-body-md {
  font-family: var(--font-body);
  font-size: var(--text-body-md-size);
  font-weight: var(--text-body-md-weight);
  letter-spacing: var(--text-body-md-tracking);
  line-height: var(--text-body-md-leading);
  color: var(--color-text-secondary);
  margin: 0;
}

.t-body-sm {
  font-family: var(--font-body);
  font-size: var(--text-body-sm-size);
  font-weight: var(--text-body-sm-weight);
  letter-spacing: var(--text-body-sm-tracking);
  line-height: var(--text-body-sm-leading);
  color: var(--color-text-secondary);
  margin: 0;
}

.t-label-sm {
  font-family: var(--font-display);
  font-size: var(--text-label-sm-size);
  font-weight: var(--text-label-sm-weight);
  letter-spacing: var(--text-label-sm-tracking);
  line-height: var(--text-label-sm-leading);
  color: var(--color-text-secondary);
  text-transform: uppercase;
  margin: 0;
}

.t-mono-sm {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm-size);
  font-weight: var(--text-mono-sm-weight);
  letter-spacing: var(--text-mono-sm-tracking);
  line-height: var(--text-mono-sm-leading);
  color: var(--color-text-primary);
  margin: 0;
}

/* Eyebrow label with inline layout (no leading dot; cf. .eyebrow which has one) */
.t-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-display);
  font-size: var(--text-label-sm-size);
  font-weight: var(--text-label-sm-weight);
  letter-spacing: var(--text-label-sm-tracking);
  line-height: var(--text-label-sm-leading);
  text-transform: uppercase;
  color: var(--color-text-secondary);
}

.t-mono { font-family: var(--font-mono); }

.t-metric {
  font-family: var(--font-mono);
  font-size: var(--text-metric-size);
  font-weight: var(--text-metric-weight);
  letter-spacing: var(--text-metric-tracking);
  line-height: var(--text-metric-leading);
  color: var(--color-text-primary);
  font-variant-numeric: tabular-nums;
  margin: 0;
}

.t-muted {
  color: var(--color-text-muted);
}

.t-primary {
  color: var(--color-text-primary);
}

.t-secondary {
  color: var(--color-text-secondary);
}

/* =============================================================
   Layout primitives
   ============================================================= */

.container {
  width: 100%;
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--container-pad);
}

.stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.stack-sm { gap: var(--space-2); }
.stack-md { gap: var(--space-4); }
.stack-lg { gap: var(--space-6); }
.stack-xl { gap: var(--space-10); }

.row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.row-between {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.grid-2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-4); }
.grid-3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-4); }
.grid-4 { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-4); }

@media (max-width: 720px) {
  .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; }
}

.divider {
  height: 1px;
  background: var(--color-border);
  border: 0;
  width: 100%;
}

/* =============================================================
   Surfaces
   ============================================================= */

.surface {
  background-color: var(--color-surface);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-lg);
}

.surface-elevated {
  background-color: var(--color-elevated);
  border: var(--border-width) solid var(--color-border-strong);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
}

/* =============================================================
   Eyebrow + Section header
   ============================================================= */

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--color-text-secondary);
  font-family: var(--font-display);
  font-size: var(--text-label-sm-size);
  font-weight: var(--text-label-sm-weight);
  letter-spacing: var(--text-label-sm-tracking);
  text-transform: uppercase;
}

.eyebrow::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: var(--radius-full);
  background-color: var(--color-primary);
  box-shadow: 0 0 0 4px var(--color-primary-soft);
}

/* =============================================================
   Buttons
   ============================================================= */

.btn {
  --btn-h: 40px;
  --btn-pad-x: 18px;
  --btn-radius: var(--radius-md);
  --btn-fs: 0.875rem;
  --btn-fw: 500;

  appearance: none;
  -webkit-appearance: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  height: var(--btn-h);
  padding-inline: var(--btn-pad-x);
  border-radius: var(--btn-radius);
  border: var(--border-width) solid transparent;
  font-family: var(--font-display);
  font-size: var(--btn-fs);
  font-weight: var(--btn-fw);
  letter-spacing: -0.005em;
  line-height: 1;
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
  background: transparent;
  color: var(--color-text-primary);
  transition:
    background-color var(--motion-base) var(--easing-standard),
    border-color var(--motion-base) var(--easing-standard),
    color var(--motion-base) var(--easing-standard),
    box-shadow var(--motion-base) var(--easing-standard),
    transform var(--motion-fast) var(--easing-standard);
}

.btn:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

.btn:disabled,
.btn.btn-disabled,
.btn[aria-disabled="true"] {
  opacity: 0.5;
  cursor: not-allowed;
  pointer-events: none;
}

.btn svg,
.btn > i,
.btn .icon {
  width: 16px;
  height: 16px;
  max-width: 16px;
  max-height: 16px;
  flex-shrink: 0;
  stroke-width: 1.75;
}

.btn-sm svg,
.btn-sm > i {
  width: 14px;
  height: 14px;
  max-width: 14px;
  max-height: 14px;
}

.btn-lg svg,
.btn-lg > i {
  width: 18px;
  height: 18px;
  max-width: 18px;
  max-height: 18px;
}

.btn-icon svg,
.btn-icon > i {
  width: 18px;
  height: 18px;
  max-width: 18px;
  max-height: 18px;
}

.btn-icon.btn-sm svg,
.btn-icon.btn-sm > i {
  width: 16px;
  height: 16px;
  max-width: 16px;
  max-height: 16px;
}

.btn-icon.btn-lg svg,
.btn-icon.btn-lg > i {
  width: 20px;
  height: 20px;
  max-width: 20px;
  max-height: 20px;
}

/* Variants */

.btn-primary {
  background-color: var(--color-primary);
  color: #FFFFFF;
  border-color: var(--color-primary);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18);
}
.btn-primary:hover { background-color: var(--color-primary-hover); border-color: var(--color-primary-hover); }
.btn-primary:active { background-color: var(--color-primary-pressed); border-color: var(--color-primary-pressed); transform: translateY(1px); }

.btn-secondary {
  background-color: var(--color-surface);
  color: var(--color-text-primary);
  border-color: var(--color-border-strong);
}
.btn-secondary:hover { background-color: var(--color-elevated); border-color: var(--color-border-strong); }
.btn-secondary:active { transform: translateY(1px); }

.btn-tertiary {
  background-color: transparent;
  color: var(--color-text-secondary);
  border-color: transparent;
}
.btn-tertiary:hover { background-color: var(--color-surface); color: var(--color-text-primary); }
.btn-tertiary:active { background-color: var(--color-elevated); }

.btn-danger {
  background-color: var(--color-danger);
  color: #FFFFFF;
  border-color: var(--color-danger);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18);
}
.btn-danger:hover { background-color: color-mix(in srgb, var(--color-danger) 86%, black); }

/* Sizes */

.btn-sm {
  --btn-h: 32px;
  --btn-pad-x: 12px;
  --btn-fs: 0.8125rem;
  --btn-radius: 8px;
}

.btn-lg {
  --btn-h: 48px;
  --btn-pad-x: 22px;
  --btn-fs: 0.9375rem;
}

.btn-icon {
  padding-inline: 0;
  width: var(--btn-h);
  aspect-ratio: 1 / 1;
}

/* =============================================================
   Inputs and form fields
   ============================================================= */

.field {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.field-label {
  font-family: var(--font-display);
  font-size: var(--text-label-sm-size);
  font-weight: var(--text-label-sm-weight);
  letter-spacing: var(--text-label-sm-tracking);
  text-transform: uppercase;
  color: var(--color-text-secondary);
}

.field-help {
  font-family: var(--font-body);
  font-size: var(--text-body-sm-size);
  color: var(--color-text-muted);
}

.field-help.is-error {
  color: var(--color-danger);
}

.input,
.textarea,
.select {
  appearance: none;
  -webkit-appearance: none;
  width: 100%;
  height: 40px;
  background-color: var(--color-surface);
  color: var(--color-text-primary);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-md);
  padding-inline: 14px;
  font-family: var(--font-body);
  font-size: var(--text-body-md-size);
  letter-spacing: var(--text-body-md-tracking);
  line-height: 1;
  transition:
    border-color var(--motion-base) var(--easing-standard),
    background-color var(--motion-base) var(--easing-standard),
    box-shadow var(--motion-base) var(--easing-standard);
}

.input::placeholder,
.textarea::placeholder,
.select::placeholder {
  color: var(--color-text-muted);
}

.input:hover,
.textarea:hover,
.select:hover {
  border-color: var(--color-border-strong);
}

.input:focus,
.textarea:focus,
.select:focus {
  outline: none;
  border-color: var(--color-primary);
  box-shadow: var(--focus-ring);
}

.input:disabled,
.textarea:disabled,
.select:disabled {
  opacity: 0.4;
  pointer-events: none;
}

.input.is-invalid,
.textarea.is-invalid,
.select.is-invalid {
  border-color: var(--color-danger);
  box-shadow: 0 0 0 3px var(--color-danger-soft);
}

.textarea {
  height: auto;
  padding: 12px 14px;
  line-height: 1.5;
  resize: vertical;
  min-height: 96px;
}

.select {
  background-image:
    linear-gradient(45deg, transparent 50%, var(--color-text-secondary) 50%),
    linear-gradient(135deg, var(--color-text-secondary) 50%, transparent 50%);
  background-position:
    calc(100% - 18px) 50%,
    calc(100% - 13px) 50%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  padding-right: 36px;
}

.input-group {
  position: relative;
  display: flex;
  align-items: center;
}

.input-group .input {
  padding-left: 38px;
}

.input-group .input-icon {
  position: absolute;
  left: 12px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  color: var(--color-text-muted);
  pointer-events: none;
}

.input-group .input-icon > svg,
.input-group .input-icon > i {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}

/* Size variants (app parity: covers daisyUI input-sm etc.) */
.input.is-sm, .select.is-sm { height: 32px; padding-inline: 10px; font-size: var(--text-body-sm-size); }
.textarea.is-sm { padding: 8px 10px; min-height: 72px; font-size: var(--text-body-sm-size); }
.input.is-lg, .select.is-lg { height: 48px; padding-inline: 16px; }

/* =============================================================
   Cards
   ============================================================= */

.card {
  background-color: var(--color-surface);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  position: relative;
  transition:
    border-color var(--motion-base) var(--easing-standard),
    background-color var(--motion-base) var(--easing-standard);
}

.card:hover {
  border-color: var(--color-border-strong);
}

.card-eyebrow {
  font-family: var(--font-display);
  font-size: var(--text-label-sm-size);
  font-weight: var(--text-label-sm-weight);
  letter-spacing: var(--text-label-sm-tracking);
  text-transform: uppercase;
  color: var(--color-text-secondary);
}

.card-title {
  font-family: var(--font-display);
  font-size: var(--text-title-md-size);
  font-weight: var(--text-title-md-weight);
  letter-spacing: var(--text-title-md-tracking);
  color: var(--color-text-primary);
  margin: 0;
}

.card-body {
  font-family: var(--font-body);
  font-size: var(--text-body-md-size);
  line-height: var(--text-body-md-leading);
  color: var(--color-text-secondary);
  margin: 0;
}

.card-footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-2);
  padding-top: var(--space-2);
  margin-top: auto;
}

.card-media {
  margin: calc(var(--space-6) * -1) calc(var(--space-6) * -1) 0;
  height: 160px;
  border-bottom: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  background:
    radial-gradient(circle at 25% 30%, rgba(91, 107, 255, 0.35), transparent 55%),
    radial-gradient(circle at 75% 70%, rgba(61, 215, 229, 0.22), transparent 55%),
    linear-gradient(135deg, #14151C 0%, #1E2029 100%);
}

.card-elevated {
  background-color: var(--color-elevated);
  border-color: var(--color-border-strong);
  box-shadow: var(--shadow-md);
}

.card-accent::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 2px;
  background-color: var(--color-primary);
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
}

.card-accent[data-accent="success"]::before { background-color: var(--color-success); }
.card-accent[data-accent="warning"]::before { background-color: var(--color-warning); }
.card-accent[data-accent="info"]::before { background-color: var(--color-info); }
.card-accent[data-accent="danger"]::before { background-color: var(--color-danger); }

/* Unpadded bordered surface -- wraps tables/lists that own their internal spacing */
.panel {
  background-color: var(--color-surface);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-md);
}
.panel[data-tone="danger"] { border-color: color-mix(in srgb, var(--color-danger) 40%, var(--color-border)); }

/* Denser card + danger tone tint (distilled from the app's .halo-card) */
.card-compact { padding: var(--space-4); border-radius: var(--radius-md); gap: var(--space-3); }
.card[data-tone="danger"] { border-color: color-mix(in srgb, var(--color-danger) 40%, var(--color-border)); }

/* =============================================================
   Checkboxes and radios
   ============================================================= */

.check {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  cursor: pointer;
  user-select: none;
  color: var(--color-text-primary);
  font-size: var(--text-body-md-size);
}

.check input[type="checkbox"],
.check input[type="radio"] {
  appearance: none;
  -webkit-appearance: none;
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  background-color: var(--color-surface);
  border: var(--border-width) solid var(--color-border-strong);
  border-radius: 6px;
  position: relative;
  cursor: pointer;
  transition:
    background-color var(--motion-base) var(--easing-standard),
    border-color var(--motion-base) var(--easing-standard),
    box-shadow var(--motion-base) var(--easing-standard);
}

.check input[type="radio"] {
  border-radius: var(--radius-full);
}

.check input[type="checkbox"]:hover,
.check input[type="radio"]:hover {
  border-color: var(--color-primary-hover);
}

.check input[type="checkbox"]:focus-visible,
.check input[type="radio"]:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

.check input[type="checkbox"]:checked,
.check input[type="radio"]:checked {
  background-color: var(--color-primary);
  border-color: var(--color-primary);
}

.check input[type="checkbox"]:checked::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'><polyline points='20 6 9 17 4 12'/></svg>");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 12px 12px;
}

.check input[type="radio"]:checked::after {
  content: "";
  position: absolute;
  inset: 4px;
  background-color: #FFFFFF;
  border-radius: var(--radius-full);
}

.check input:disabled {
  opacity: 0.4;
  pointer-events: none;
}

/* Switch (pill toggle) */

.switch {
  position: relative;
  display: inline-flex;
  align-items: center;
  width: 36px;
  height: 20px;
  cursor: pointer;
}

.switch input {
  position: absolute;
  inset: 0;
  opacity: 0;
  cursor: pointer;
}

.switch .switch-track {
  position: absolute;
  inset: 0;
  background-color: var(--color-elevated);
  border: var(--border-width) solid var(--color-border-strong);
  border-radius: var(--radius-full);
  transition: background-color var(--motion-base) var(--easing-standard), border-color var(--motion-base) var(--easing-standard);
}

.switch .switch-thumb {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 14px;
  height: 14px;
  background-color: var(--color-text-secondary);
  border-radius: var(--radius-full);
  transition: transform var(--motion-base) var(--easing-standard), background-color var(--motion-base) var(--easing-standard);
}

.switch input:checked ~ .switch-track {
  background-color: var(--color-primary);
  border-color: var(--color-primary);
}

.switch input:checked ~ .switch-thumb {
  transform: translateX(16px);
  background-color: #FFFFFF;
}

.switch input:focus-visible ~ .switch-track {
  box-shadow: var(--focus-ring);
}

/* =============================================================
   Tabs (pill-style segmented control)
   ============================================================= */

.tabs {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px;
  background-color: var(--color-surface);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-full);
}

.tab {
  appearance: none;
  -webkit-appearance: none;
  background: transparent;
  border: var(--border-width) solid transparent;
  border-radius: var(--radius-full);
  color: var(--color-text-secondary);
  font-family: var(--font-display);
  font-size: 0.8125rem;
  font-weight: 500;
  letter-spacing: -0.005em;
  height: 32px;
  padding-inline: 14px;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  cursor: pointer;
  transition:
    background-color var(--motion-base) var(--easing-standard),
    color var(--motion-base) var(--easing-standard),
    border-color var(--motion-base) var(--easing-standard);
}

.tab:hover {
  background-color: var(--color-elevated);
  color: var(--color-text-primary);
}

.tab[aria-selected="true"],
.tab.is-active {
  background-color: var(--color-elevated);
  color: var(--color-text-primary);
  border-color: var(--color-primary);
}

.tab:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

.tab svg,
.tab > i {
  width: 14px;
  height: 14px;
  max-width: 14px;
  max-height: 14px;
  flex-shrink: 0;
  stroke-width: 1.75;
}

.stat-tile .stat-head svg,
.stat-tile .stat-head > i,
.stat-tile .stat-eyebrow svg,
.stat-tile .stat-eyebrow > i {
  width: 14px;
  height: 14px;
  max-width: 14px;
  max-height: 14px;
  flex-shrink: 0;
}

/* =============================================================
   Chips, badges, signal pills
   ============================================================= */

.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  height: 24px;
  padding-inline: 10px;
  border-radius: var(--radius-full);
  background-color: var(--color-primary-soft);
  color: var(--color-primary-hover);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0;
  white-space: nowrap;
  border: var(--border-width) solid transparent;
  text-transform: none;
}

.chip[data-tone="success"] { background-color: var(--color-success-soft); color: var(--color-success); }
.chip[data-tone="warning"] { background-color: var(--color-warning-soft); color: var(--color-warning); }
.chip[data-tone="info"] { background-color: var(--color-info-soft); color: var(--color-info); }
.chip[data-tone="danger"],
.chip[data-tone="error"] { background-color: var(--color-danger-soft); color: var(--color-danger); }
.chip[data-tone="neutral"] { background-color: var(--color-elevated); color: var(--color-text-secondary); border-color: var(--color-border); }
.chip-sm { height: 21px; padding-inline: 9px; font-size: 0.66rem; }

/* Water-fill progress pill (generic, distilled from the app's countdown-pill):
   set --fill (0..1) + data-tone; the fill drains left-to-right as --fill drops. */
.chip.is-progress {
  --_tone: var(--color-primary);
  background:
    linear-gradient(to right,
      color-mix(in srgb, var(--_tone) 26%, transparent) calc(var(--fill, 1) * 100%),
      color-mix(in srgb, var(--_tone) 7%, transparent) calc(var(--fill, 1) * 100%));
  color: var(--_tone);
  border-color: color-mix(in srgb, var(--_tone) 24%, transparent);
}
.chip.is-progress[data-tone="warning"] { --_tone: var(--color-warning); }
.chip.is-progress[data-tone="danger"],
.chip.is-progress[data-tone="error"] { --_tone: var(--color-danger); }
.chip.is-progress[data-tone="info"] { --_tone: var(--color-info); }
.chip.is-progress[data-tone="success"] { --_tone: var(--color-success); }

.chip svg,
.chip > i,
.chip .icon {
  width: 12px;
  height: 12px;
  max-width: 12px;
  max-height: 12px;
  flex-shrink: 0;
  stroke-width: 1.75;
}

.badge-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: var(--radius-full);
  background-color: var(--color-primary);
}

.badge-dot[data-tone="success"] { background-color: var(--color-success); }
.badge-dot[data-tone="warning"] { background-color: var(--color-warning); }
.badge-dot[data-tone="info"] { background-color: var(--color-info); }
.badge-dot[data-tone="danger"],
.badge-dot[data-tone="error"] { background-color: var(--color-danger); }

/* =============================================================
   Signature element: Stat Tile
   ============================================================= */

.stat-tile {
  position: relative;
  background-color: var(--color-surface);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  overflow: hidden;
  transition:
    border-color var(--motion-base) var(--easing-standard),
    transform var(--motion-base) var(--easing-standard);
}

.stat-tile::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 2px;
  background-color: var(--color-primary);
  opacity: 0.9;
}

.stat-tile[data-tone="success"]::before { background-color: var(--color-success); }
.stat-tile[data-tone="warning"]::before { background-color: var(--color-warning); }
.stat-tile[data-tone="info"]::before { background-color: var(--color-info); }
.stat-tile[data-tone="danger"]::before { background-color: var(--color-danger); }

.stat-tile:hover {
  border-color: var(--color-border-strong);
}

.stat-tile .stat-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.stat-tile .stat-eyebrow {
  font-family: var(--font-display);
  font-size: var(--text-label-sm-size);
  font-weight: var(--text-label-sm-weight);
  letter-spacing: var(--text-label-sm-tracking);
  text-transform: uppercase;
  color: var(--color-text-secondary);
}

/* Flat markup (eyebrow directly under .stat-tile, no .stat-head wrapper):
   let it host a trailing icon. Nested .stat-head .stat-eyebrow is unaffected. */
.stat-tile > .stat-eyebrow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.stat-tile .stat-value {
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: 2.25rem;
  letter-spacing: -0.02em;
  line-height: 1;
  color: var(--color-text-primary);
  font-variant-numeric: tabular-nums;
}

.stat-tile .stat-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.stat-tile .stat-foot {
  font-family: var(--font-body);
  font-size: var(--text-body-sm-size);
  color: var(--color-text-muted);
}

.stat-tile .stat-spark {
  width: 96px;
  height: 32px;
  color: var(--color-primary);
}

.stat-tile[data-tone="success"] .stat-spark { color: var(--color-success); }
.stat-tile[data-tone="warning"] .stat-spark { color: var(--color-warning); }
.stat-tile[data-tone="info"] .stat-spark { color: var(--color-info); }
.stat-tile[data-tone="danger"] .stat-spark { color: var(--color-danger); }

.stat-tile.stat-sm { padding: var(--space-4); gap: var(--space-3); }
.stat-tile.stat-sm .stat-value { font-size: 1.75rem; }
.stat-tile.stat-sm .stat-spark { width: 72px; height: 24px; }

.stat-tile.stat-lg { padding: var(--space-6); gap: var(--space-5); }
.stat-tile.stat-lg .stat-value { font-size: 2.75rem; }
.stat-tile.stat-lg .stat-spark { width: 120px; height: 40px; }

/* =============================================================
   Navigation primitives
   ============================================================= */

.nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 64px;
  border-bottom: var(--border-width) solid var(--color-border);
}

.nav-brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-display);
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--color-text-primary);
  text-decoration: none;
}

.nav-brand-mark {
  width: 24px;
  height: 24px;
  border-radius: var(--radius-sm);
  background:
    conic-gradient(from 220deg at 50% 50%, var(--color-primary), #1E2029, var(--color-primary));
  border: var(--border-width) solid var(--color-border-strong);
}

.nav-links {
  display: inline-flex;
  align-items: center;
  gap: var(--space-6);
}

.nav-link {
  font-family: var(--font-display);
  font-size: 0.875rem;
  color: var(--color-text-secondary);
  text-decoration: none;
  transition: color var(--motion-base) var(--easing-standard);
}

.nav-link:hover,
.nav-link[aria-current="page"] {
  color: var(--color-text-primary);
}

/* =============================================================
   Swatches and token tiles
   ============================================================= */

.swatch {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.swatch-chip {
  height: 92px;
  border-radius: var(--radius-md);
  border: var(--border-width) solid var(--color-border);
}

.swatch-name {
  font-family: var(--font-display);
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--color-text-primary);
}

.swatch-hex {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  color: var(--color-text-muted);
}

/* =============================================================
   daisyUI-compatible components (for the UTF.link frontend port)
   Same class names/structure as daisyUI 5 so UTF.link markup ports as a
   dependency swap, styled in the Halo aesthetic (generalized from opentoken's
   own patterns: .switch, .share-modal, .atable, .tip-toast, .*-menu popovers).
   ============================================================= */

/* ---- Button variants (base .btn is defined above) ---- */
.btn-ghost { background: transparent; border-color: transparent; color: var(--color-text-secondary); }
.btn-ghost:hover { background: var(--color-elevated); color: var(--color-text-primary); }
.btn-outline { background: transparent; border-color: var(--color-border-strong); color: var(--color-text-primary); }
.btn-outline:hover { border-color: var(--color-primary); background: var(--color-elevated); }
.btn-error { background: var(--color-danger); border-color: var(--color-danger); color: #fff; }
.btn-error:hover { background: color-mix(in srgb, var(--color-danger) 86%, black); }
.btn-info { background: var(--color-info); border-color: var(--color-info); color: var(--color-text-inverse); }
.btn-success { background: var(--color-success); border-color: var(--color-success); color: var(--color-text-inverse); }
.btn-warning { background: var(--color-warning); border-color: var(--color-warning); color: var(--color-text-inverse); }
.btn-neutral { background: var(--color-elevated); border-color: var(--color-border-strong); color: var(--color-text-primary); }
.btn-neutral:hover { background: var(--color-surface); }
.btn-xs { --btn-h: 26px; --btn-pad-x: 9px; --btn-fs: 0.72rem; --btn-radius: var(--radius-sm); }
.btn-circle { --btn-pad-x: 0; width: var(--btn-h); padding: 0; border-radius: var(--radius-full); }
.btn-block { width: 100%; }

/* ---- Toggle: daisyUI single-element <input type="checkbox" class="toggle">,
   with Halo's .switch look (track + sliding thumb, primary when checked). ---- */
.toggle {
  --tg-w: 40px; --tg-h: 24px; --tg-p: 3px;
  appearance: none; -webkit-appearance: none; position: relative; flex-shrink: 0;
  width: var(--tg-w); height: var(--tg-h); margin: 0; vertical-align: middle; cursor: pointer;
  background: var(--color-elevated); border: var(--border-width) solid var(--color-border-strong);
  border-radius: var(--radius-full);
  transition: background-color var(--motion-base) var(--easing-standard), border-color var(--motion-base) var(--easing-standard);
}
.toggle::before {
  content: ""; position: absolute; top: 50%; left: var(--tg-p);
  width: calc(var(--tg-h) - 2 * var(--tg-p)); height: calc(var(--tg-h) - 2 * var(--tg-p));
  background: var(--color-text-secondary); border-radius: var(--radius-full); transform: translateY(-50%);
  transition: transform var(--motion-base) var(--easing-standard), background-color var(--motion-base) var(--easing-standard);
}
.toggle:checked, .toggle-primary:checked { background: var(--color-primary); border-color: var(--color-primary); }
.toggle:checked::before { transform: translate(calc(var(--tg-w) - var(--tg-h)), -50%); background: #fff; }
.toggle:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.toggle-sm { --tg-w: 32px; --tg-h: 18px; --tg-p: 2px; }
.toggle-md { --tg-w: 40px; --tg-h: 24px; }
.toggle-lg { --tg-w: 52px; --tg-h: 30px; }

/* ---- Toggle with an embedded action icon ----
   A .toggle plus a .toggle-action button that sits in the track side OPPOSITE
   the knob and is shown only while ON (e.g. a settings gear on a proxy switch).
   Its position/size derive from the field's --tf-* geometry (the toggle inherits
   the same width), so the icon can never drift from the switch. The action is its
   own tap target; flip the toggle via the knob side. */
.toggle-field {
  --tf-w: 40px; --tf-h: 22px; --tf-p: 2px;   /* 18px knob — tighter control-card scale */
  position: relative; display: inline-flex; align-items: center;
}
.toggle-field > .toggle { --tg-w: var(--tf-w); --tg-h: var(--tf-h); --tg-p: var(--tf-p); }
.toggle-action {
  position: absolute; top: 50%; left: 0; transform: translateY(-50%);
  width: var(--tf-h); height: var(--tf-h); /* the left cap square: icon centers on
                                              the left semicircle's center (tf-h/2) */
  display: inline-flex; align-items: center; justify-content: center;
  border: 0; background: transparent; padding: 0; margin: 0; cursor: pointer;
  color: rgba(255, 255, 255, 0.9); /* reads on the primary ON-track, echoes the knob */
  opacity: 0; pointer-events: none;
  transition: opacity var(--motion-base) var(--easing-standard), transform var(--motion-fast) var(--easing-standard);
}
.toggle-field > .toggle:checked ~ .toggle-action { opacity: 1; pointer-events: auto; }
.toggle-action > svg, .toggle-action > i { width: 12px; height: 12px; }
.toggle-action:hover { transform: translateY(-50%) rotate(35deg); }

/* ---- Modal: native <dialog class="modal"> opened via showModal() (Halo panel
   from opentoken's .share-modal). Box centers via the dialog's default margins. ---- */
.modal { padding: 0; border: none; background: transparent; max-width: 100vw; max-height: 100dvh; color: var(--color-text-primary); overflow: visible; }
.modal::backdrop { background: var(--color-overlay); }
.modal-box {
  width: min(32rem, calc(100vw - 2rem)); max-height: calc(100dvh - 4rem); overflow-y: auto;
  background: var(--color-elevated); border: var(--border-width) solid var(--color-border-strong);
  border-radius: var(--radius-lg); padding: 20px; box-shadow: var(--shadow-lg); outline: none;
}
.modal-box h3 { letter-spacing: -0.015em; }
.modal-box.max-w-sm { width: min(24rem, calc(100vw - 2rem)); }
.modal-box.max-w-md { width: min(28rem, calc(100vw - 2rem)); }
.modal-box.max-w-xl { width: min(36rem, calc(100vw - 2rem)); }
.modal-action { display: flex; align-items: center; justify-content: flex-end; gap: 8px; margin-top: 16px; }
.modal-backdrop { position: fixed; inset: 0; z-index: -1; }
.modal-backdrop button { position: fixed; inset: 0; width: 100%; height: 100%; background: transparent; border: none; cursor: default; }

/* Bottom sheet on phones. Promoted from daisyui-bridge.css: a modal docked to the bottom
   edge is a real mobile pattern (thumb reach, native feel), not a compatibility shim — and
   BOTH consumers need it, so it belongs in the component layer where core builds pick it up.
   Pairs with .sm\:modal-middle (bridge) to re-center at >=640px; on its own, .modal-box keeps
   its default centering above the breakpoint.
   Re-pins the dialog itself, not just the box: a native <dialog> is UA-centered, so moving
   only the box would leave the sheet floating. */
/* modal-bottom = full-width bottom sheet on mobile; the paired sm:modal-middle
   lets it center at >=640px (native <dialog> UA margin:auto centers it there).
   The native <dialog> is UA-centered, so we must re-pin the dialog itself to the
   bottom (not just the box) for the sheet to dock. */
@media (max-width: 639.98px) {
  .modal.modal-bottom { inset: auto 0 0 0; margin: 0; width: 100%; max-width: 100vw; }
  .modal.modal-bottom .modal-box {
    width: 100%; max-width: 100%;
    /* Docked to the screen edge, only the TOP corners are ever visible, and they carry the whole
       'drawn up from the bottom' read — so they take the largest radius in the scale, not the
       default. The bottom and side borders would land exactly ON the display edge as hairlines
       (and fight the phone's own rounded corners), so they come off. */
    border-radius: var(--radius-xl) var(--radius-xl) 0 0;
    border-bottom: 0; border-left: 0; border-right: 0;
    padding-bottom: calc(20px + env(safe-area-inset-bottom));  /* clear the home indicator */
    box-shadow: 0 -8px 30px rgba(0, 0, 0, 0.4);   /* lifts UP over the page, not down onto nothing */
  }
}

/* ---- Table — UTF.link's design (its .table + .halo-table was higher quality than
   opentoken's .atable): uppercase muted headers, hairline dividers, ROW HOVER. ---- */
.table { width: 100%; border-collapse: collapse; font-size: 0.8125rem; }
.table th { text-align: left; color: var(--color-text-muted); font-weight: 600; font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.08em; padding: 10px; border-bottom: var(--border-width) solid var(--color-border); white-space: nowrap; }
.table td { padding: 11px 10px; border-bottom: var(--border-width) solid var(--color-border); vertical-align: middle; color: var(--color-text-secondary); }
.table tbody tr { transition: background-color var(--motion-base) var(--easing-standard); }
.table tbody tr:hover { background: var(--color-elevated); }
.table tbody tr:last-child td { border-bottom: 0; }
.table-sm th { padding: 6px 8px; } .table-sm td { padding: 7px 8px; }

/* ---- Checkbox ---- */
.checkbox { appearance: none; -webkit-appearance: none; position: relative; flex-shrink: 0; width: 20px; height: 20px; cursor: pointer; background: var(--color-elevated); border: var(--border-width) solid var(--color-border-strong); border-radius: var(--radius-sm); transition: background-color var(--motion-base), border-color var(--motion-base); }
.checkbox:checked { background: var(--color-primary); border-color: var(--color-primary); }
.checkbox:checked::after { content: ""; position: absolute; left: 6px; top: 2px; width: 5px; height: 10px; border: solid #fff; border-width: 0 2px 2px 0; transform: rotate(45deg); }
.checkbox:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* ---- Menu + dropdown (from Halo's *-menu popovers) ---- */
.menu { display: flex; flex-direction: column; gap: 2px; padding: 4px; list-style: none; margin: 0; }
.menu li > *, .menu li > a { display: flex; align-items: center; gap: 8px; padding: 8px 12px; border-radius: var(--radius-sm); color: var(--color-text-secondary); text-decoration: none; cursor: pointer; transition: background-color var(--motion-fast); }
.menu li > *:hover, .menu li > a:hover { background: var(--color-elevated); color: var(--color-text-primary); }
.menu li > *:focus-visible, .menu li > a:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.menu li > [aria-current], .menu li > .is-active { color: var(--color-primary-hover); }
.dropdown { position: relative; display: inline-flex; }
.dropdown-content { position: absolute; top: calc(100% + 6px); left: 0; z-index: 30; min-width: 12rem; padding: 4px; background: var(--color-elevated); border: var(--border-width) solid var(--color-border-strong); border-radius: var(--radius-md); box-shadow: var(--shadow-lg); opacity: 0; visibility: hidden; transform: translateY(-4px); transition: opacity var(--motion-fast) var(--easing-standard), transform var(--motion-fast) var(--easing-standard), visibility var(--motion-fast); }
/* Open on focus-within (click the trigger) or an explicit .dropdown-open class;
   closes when focus leaves (click outside) — hidden by default so it can close. */
.dropdown:focus-within > .dropdown-content,
.dropdown.dropdown-open > .dropdown-content { opacity: 1; visibility: visible; transform: none; }
.dropdown-end .dropdown-content { left: auto; right: 0; }

/* ---- Loading spinner (daisyUI .loading .loading-spinner) ---- */
.loading { display: inline-block; width: 1.5rem; height: 1.5rem; vertical-align: middle; border: 2px solid var(--color-border-strong); border-top-color: var(--color-primary); border-radius: 50%; animation: halo-spin .6s linear infinite; }
.loading-sm { width: 1.1rem; height: 1.1rem; } .loading-lg { width: 2.25rem; height: 2.25rem; border-width: 3px; }
@keyframes halo-spin { to { transform: rotate(360deg); } }

/* ---- Alert (from Halo signal tokens) ---- */
.alert { display: flex; align-items: center; gap: 12px; padding: 12px 16px; font-size: .875rem; border-radius: var(--radius-md); border: var(--border-width) solid var(--color-border); background: var(--color-elevated); color: var(--color-text-primary); }
.alert-error { border-color: var(--color-danger); background: var(--color-danger-soft); }
.alert-success { border-color: var(--color-success); background: var(--color-success-soft); }
.alert-warning { border-color: var(--color-warning); background: var(--color-warning-soft); }
.alert-info { border-color: var(--color-info); background: var(--color-info-soft); }

/* ---- Join (connected group) + avatar ---- */
.join { display: inline-flex; }
.join > * { border-radius: 0; }
.join > *:first-child { border-top-left-radius: var(--radius-md); border-bottom-left-radius: var(--radius-md); }
.join > *:last-child { border-top-right-radius: var(--radius-md); border-bottom-right-radius: var(--radius-md); }
.join > * + * { margin-left: -1px; }
.avatar > div { display: inline-flex; align-items: center; justify-content: center; overflow: hidden; border-radius: var(--radius-full); background: var(--color-elevated); }
.avatar img { width: 100%; height: 100%; object-fit: cover; }

/* ---- Link + unified focus coverage (extends the shared focus-ring grammar to
   .link and [role="button"], gaps the per-component rules didn't cover) ---- */
.link { color: var(--color-primary-hover); text-decoration: none; cursor: pointer; transition: color var(--motion-fast) var(--easing-standard); }
.link:hover { color: var(--color-primary); text-decoration: underline; }
.link:focus-visible,
[role="button"]:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* ---- Browser mockup + window controls + status pill (editor/preview chrome) ---- */
.mockup-browser { border-radius: var(--radius-lg); overflow: hidden; background: var(--color-surface); }
.mockup-browser-toolbar { min-height: 40px; padding: 8px 12px; display: flex; align-items: center; gap: 8px; border-bottom: var(--border-width) solid var(--color-border); }

/* macOS traffic-light window dots (also usable as repurposed controls, hence is-active) */
.window-dot { width: 12px; height: 12px; border-radius: var(--radius-full); border: none; padding: 0; cursor: pointer; transition: filter var(--motion-fast) var(--easing-standard), transform var(--motion-fast) var(--easing-standard), box-shadow var(--motion-fast) var(--easing-standard); }
.window-dot:hover { filter: brightness(1.15); }
.window-dot:active { transform: scale(0.86); }
.window-dot.is-active { box-shadow: 0 0 0 2px rgba(127, 127, 127, 0.45); }
.window-dot-red { background: #ff5f57; }
.window-dot-yellow { background: #febc2e; }
.window-dot-green { background: #28c840; }

/* Self-collapsing save-state pill: empty -> 0 width; is-dirty/saving/saved -> tinted.
   Pairs with a .status dot + .animate-ping (ping only while dirty). */
.status-pill {
  display: inline-flex; align-items: center; gap: 0.3rem; flex: none;
  width: 5rem; padding: 0.12rem 0.55rem;
  border: var(--border-width) solid transparent; border-radius: var(--radius-full);
  font-size: 0.66rem; font-weight: 600; line-height: 1.5;
  white-space: nowrap; overflow: hidden; background: transparent; cursor: default;
  transition: width .22s ease, opacity .18s ease, padding .22s ease, margin .22s ease, color .15s, border-color .15s;
}
.status-pill:not(.is-dirty):not(.is-saving):not(.is-saved) { width: 0; opacity: 0; padding-left: 0; padding-right: 0; border-width: 0; margin-right: -0.5rem; pointer-events: none; }
.status-pill.is-dirty { cursor: pointer; color: var(--color-warning); border-color: color-mix(in srgb, var(--color-warning) 45%, transparent); }
.status-pill.is-saving { color: var(--color-info); border-color: color-mix(in srgb, var(--color-info) 45%, transparent); }
.status-pill.is-saved { color: var(--color-success); border-color: color-mix(in srgb, var(--color-success) 45%, transparent); }
.status-pill:not(.is-dirty) .status.animate-ping { display: none; }
.status-pill.is-saving .status { background-color: var(--color-info); }
.status-pill.is-saved .status { background-color: var(--color-success); }

/* ---- Island: grouped content-surface panel (distilled from opentoken) ---- */
.island { display: flex; flex-direction: column; background: var(--color-surface); border: var(--border-width) solid var(--color-border); border-radius: var(--radius-lg); overflow: hidden; }
.island-head { display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 6px; min-height: 38px; padding: 8px 12px; border-bottom: var(--border-width) solid var(--color-border); }
.island-title { display: inline-flex; align-items: center; gap: 8px; color: var(--color-text-secondary); font-family: var(--font-display); font-weight: 600; font-size: 0.9rem; }
.island-count { color: var(--color-text-muted); font-weight: 500; font-variant-numeric: tabular-nums; }
.island-tools { display: inline-flex; align-items: center; gap: 6px; justify-self: end; }
.island-body { display: flex; flex-direction: column; gap: 8px; padding: 10px; }
.island-empty { padding: 24px 8px; text-align: center; font-size: 0.85rem; color: var(--color-text-muted); }

/* ---- FAB + speed dial (daisyUI-compatible API, safe-area placement) ----
   <div class="fab">
     <div tabindex="0" role="button" class="btn btn-lg btn-circle btn-primary">F</div>  ← trigger
     <div class="fab-close"><span class="fab-label">Close</span> <span class="btn btn-lg btn-circle">✕</span></div>
     <div><span class="fab-label">Label A</span> <button class="btn btn-lg btn-circle">A</button></div>
     …
   </div>
   The trigger is a div[tabindex=0][role=button] (Safari never focuses <button>s on
   click — daisyUI's documented workaround). Opening/closing is pure CSS: items show
   on :focus-within with a scale pop + 30ms stagger; while open the trigger is
   click-through, so the same spot hits .fab-close / .fab-main-action (which sit
   absolutely over it; the trigger fades + rotates out when one exists). Clicking
   anywhere else blurs and closes. .fab-label is a Halo extra: a legibility pill for
   the item labels (daisyUI leaves them as plain text). Max 4 dial items. */
.fab {
  position: fixed; z-index: 40;
  inset-inline-end: max(20px, env(safe-area-inset-right));
  bottom: max(20px, env(safe-area-inset-bottom));
  display: flex; flex-direction: column-reverse; align-items: flex-end; gap: 8px;
  font-size: 0.875rem; white-space: nowrap;
  pointer-events: none;   /* gaps between items don't eat page clicks; children re-enable */
}
.fab > * { pointer-events: auto; display: flex; align-items: center; gap: 8px; }
.fab > *:hover, .fab > *:has(:focus-visible) { z-index: 1; }
.fab .btn { box-shadow: var(--shadow-lg); }
.fab > [tabindex]:first-child { position: relative; display: grid; transition: opacity 0.2s var(--easing-standard), visibility 0.2s var(--easing-standard), rotate 0.2s var(--easing-standard); }
.fab .fab-close, .fab .fab-main-action { position: absolute; inset-inline-end: 0; bottom: 0; }
/* dial items: hidden until the fab holds focus; pop in (80% -> 100%) with a stagger */
.fab > :nth-child(n+2) { visibility: hidden; opacity: 0; scale: 80% 80%; transition: opacity 0.2s var(--easing-standard), scale 0.2s var(--easing-standard), visibility 0.2s; }
.fab > .fab-close, .fab > .fab-main-action { scale: 100% 100%; }   /* they replace the trigger — fade only */
.fab > :nth-child(3) { transition-delay: 30ms; }
.fab > :nth-child(4) { transition-delay: 60ms; }
.fab > :nth-child(5) { transition-delay: 90ms; }
.fab > :nth-child(6) { transition-delay: 120ms; }
.fab:focus-within > [tabindex]:first-child { pointer-events: none; }
.fab:focus-within:has(.fab-close) > [tabindex]:first-child,
.fab:focus-within:has(.fab-main-action) > [tabindex]:first-child { opacity: 0; rotate: 90deg; }
.fab:focus-within > :nth-child(n+2) { visibility: visible; opacity: 1; scale: 100% 100%; }
/* label pill (Halo extra — keeps speed-dial labels readable over page content) */
.fab-label { padding: 3px 10px; border-radius: var(--radius-full); background: var(--color-elevated); border: var(--border-width) solid var(--color-border-strong); color: var(--color-text-secondary); font-size: 0.78rem; font-weight: 500; box-shadow: var(--shadow-lg); }
@media (prefers-reduced-motion: reduce) {
  .fab > [tabindex]:first-child { transition: opacity var(--motion-fast) linear; rotate: none; }
  .fab > :nth-child(n+2) { transition: opacity var(--motion-fast) linear; scale: 100% 100%; }
}

/* ---- FAB flower: dial items on a quarter arc (2-4 items; verbatim daisyUI geometry) ---- */
.fab-flower { --position: 0rem; display: grid; }
.fab-flower > * {
  --degree: 180deg; --flip-degree: calc(180deg - var(--degree)); grid-area: 1 / 1;
  transform: translateX(calc(cos(var(--degree)) * var(--position))) translateY(calc(sin(var(--degree)) * -1 * var(--position)));
}
[dir="rtl"] .fab-flower > * { transform: translateX(calc(cos(var(--flip-degree)) * var(--position))) translateY(calc(sin(var(--flip-degree)) * -1 * var(--position))); }
.fab-flower > :nth-child(-n+2) { --position: 0rem; }
.fab-flower > :nth-child(n+7) { display: none; }
.fab-flower:has(> :nth-child(3)) { --position: 140%; }
.fab-flower:has(> :nth-child(3)) > :nth-child(3) { --degree: 135deg; }
.fab-flower:has(> :nth-child(4)) { --position: 140%; }
.fab-flower:has(> :nth-child(4)) > :nth-child(3) { --degree: 165deg; }
.fab-flower:has(> :nth-child(4)) > :nth-child(4) { --degree: 105deg; }
.fab-flower:has(> :nth-child(5)) { --position: 180%; }
.fab-flower:has(> :nth-child(5)) > :nth-child(3) { --degree: 180deg; }
.fab-flower:has(> :nth-child(5)) > :nth-child(4) { --degree: 135deg; }
.fab-flower:has(> :nth-child(5)) > :nth-child(5) { --degree: 90deg; }
.fab-flower:has(> :nth-child(6)) { --position: 220%; }
.fab-flower:has(> :nth-child(6)) > :nth-child(3) { --degree: 180deg; }
.fab-flower:has(> :nth-child(6)) > :nth-child(4) { --degree: 150deg; }
.fab-flower:has(> :nth-child(6)) > :nth-child(5) { --degree: 120deg; }
.fab-flower:has(> :nth-child(6)) > :nth-child(6) { --degree: 90deg; }

/* ---- Tooltip (daisyUI-compatible): pure CSS, text from data-tip ----
   <span class="tooltip" data-tip="Copy">…</span> — top placement by default;
   .tooltip-left / .tooltip-right / .tooltip-bottom reposition. Shows on hover or
   when the wrapped control has :focus-visible. Hairline pill, no arrow (Halo). */
.tooltip { position: relative; display: inline-flex; }
.tooltip::before {
  content: attr(data-tip);
  position: absolute; z-index: 60;
  bottom: calc(100% + 8px); left: 50%; translate: -50% 0;
  padding: 3px 10px; border-radius: var(--radius-sm);
  background: var(--color-elevated); border: var(--border-width) solid var(--color-border-strong);
  color: var(--color-text-primary); font-size: 0.75rem; font-weight: 500;
  font-family: var(--font-body); white-space: nowrap; box-shadow: var(--shadow-lg);
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity var(--motion-fast) var(--easing-standard), visibility var(--motion-fast);
}
.tooltip:hover::before, .tooltip:has(:focus-visible)::before { opacity: 1; visibility: visible; }
.tooltip-left::before { bottom: auto; left: auto; right: calc(100% + 8px); top: 50%; translate: 0 -50%; }
.tooltip-right::before { bottom: auto; left: calc(100% + 8px); top: 50%; translate: 0 -50%; }
.tooltip-bottom::before { bottom: auto; top: calc(100% + 8px); left: 50%; translate: -50% 0; }

/* ---- Menu extras: divider + danger item (for the FAB menu / dropdowns) ---- */
.menu-divider { height: 1px; margin: 4px 6px; background: var(--color-border); }
.menu li > .is-danger { color: var(--color-danger); }
.menu li > .is-danger:hover { background: var(--color-danger-soft); color: var(--color-danger); }

/* =============================================================
   Swipe row -- quick actions revealed by dragging a row sideways
   ============================================================= */
/* The pattern every phone messaging app uses: actions sit UNDER the row, and the
   row itself slides to uncover them. Structure:
     .swipe-row            the clip + the positioning context (does not move)
       .swipe-row-actions  pinned to the trailing edge, revealed, never moved
       .swipe-row-slide    the visible row; this is the only thing that translates
   Two rules make it behave rather than fight the page:
   -- touch-action: pan-y hands VERTICAL scrolling back to the browser and leaves
      only the horizontal axis for script. Without it a list becomes unscrollable
      the moment a finger lands slightly off-vertical.
   -- transform, not the standalone translate property, for SUPPORT breadth alone
      (translate is Chrome 104+ / Safari 14.1+; transform is everywhere). The first
      choice was translate, on the theory that a consumer might already own
      transform -- but it cannot: the consumer's transform goes on the ROW (a
      drag-to-reorder does exactly that here) and this is on the SLIDE inside it,
      so the two were never going to meet, and the theory bought nothing either way.
      NOTE, because it cost hours: translate appeared to "silently do nothing" while
      being measured in a HIDDEN document, where transitions never advance and the
      computed value stays at its start. So does transform. Neither property was at
      fault; document.visibilityState was. Suspect the observer before the CSS.
   The actions must exist somewhere reachable without a gesture too: a swipe is an
   accelerator, and pointer-only affordances are invisible to a keyboard. */
.swipe-row { position: relative; overflow: hidden; }

.swipe-row-actions {
  position: absolute;
  inset: 0 0 0 auto;
  display: flex;
  align-items: stretch;
}

.swipe-row-action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  border: 0;
  padding: 0 18px;
  font: inherit;
  font-size: var(--text-sm);
  color: var(--color-text-inverse);
  background: var(--color-primary);
  cursor: pointer;
}
.swipe-row-action:hover { background: var(--color-primary-hover); }
.swipe-row-action.is-danger { background: var(--color-danger); }
.swipe-row-action.is-danger:hover { background: var(--color-danger); filter: brightness(1.12); }
/* DESCENDANT, not child: a consumer that wraps the glyph to toggle it (x-show, a
   conditional, a tooltip span) would otherwise leave the svg unsized, and an svg
   with a viewBox and no size collapses to nothing. An icon button showing nothing
   still looks like a button, so the failure is silent. */
.swipe-row-action svg { width: 20px; height: 20px; flex: none; }

/* ---- Floating variant: round icon buttons standing in the revealed gap ------
   The flush bar above reads as part of the row; this reads as something the row
   moved aside to expose, which is the iOS Messages / Mail treatment. Icon-only,
   so every button here needs its own accessible name -- there is no label to
   read. Circles sized in one place: the row's height does not set them, because
   a taller row would give a wider circle and the pair would stop matching. */
.swipe-row-actions-float {
  align-items: center;
  gap: 10px;
  padding: 0 12px;
  background: transparent;
}
/* A circle holds a glyph. Some states are worth spelling out -- a destructive
   confirmation above all, where a tick and a cross are exactly the pair a hurried
   user mixes up -- so the same button can become a pill and carry a word. */
.swipe-row-actions-float .swipe-row-action.is-text {
  width: auto;
  min-width: 36px;
  padding: 0 14px;
  border-radius: 999px;
}
.swipe-row-actions-float .swipe-row-action {
  /* Sized to sit INSIDE a compact row with clearance, not to the platform's 44px
     minimum: a circle taller than the row it belongs to has nowhere to be, and
     ends up against the frame. The touch target is the whole circle plus the gap
     around it, which the padding and gap above provide. */
  width: 36px;
  height: 36px;
  padding: 0;
  border-radius: 999px;
}

.swipe-row-slide {
  position: relative;
  background: var(--color-surface);
  touch-action: pan-y;
  transition: transform 200ms cubic-bezier(0.22, 0.61, 0.36, 1);
}
/* While a finger is down the row tracks it exactly -- an animation here would lag
   the gesture and read as a stutter. */
.swipe-row.is-swiping .swipe-row-slide { transition: none; }
/* --swipe-w is set by the consumer from the measured width of its own actions, so
   the open position is always exactly the actions and never a guessed constant. */
.swipe-row.is-open .swipe-row-slide { transform: translateX(calc(-1 * var(--swipe-w, 0px))); }

/* =============================================================
   Accessibility
   ============================================================= */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition-duration: 0.001ms !important;
    animation-duration: 0.001ms !important;
  }
}

/* In-button busy spinner (otBtnBusy). Inherits currentColor so it works on every button variant. */
.ot-spin { display:inline-block; width:14px; height:14px; vertical-align:-2px; border:2px solid currentColor; border-right-color:transparent; border-radius:50%; animation:ot-spin 0.6s linear infinite; }
@keyframes ot-spin { to { transform:rotate(360deg); } }
/* A button mid-save keeps its resting width (otBtnBusy pins min-width) — this just softens the swap. */
button[aria-busy="true"] { cursor:progress; opacity:0.85; }
@media (prefers-reduced-motion: reduce) { .ot-spin { animation-duration:1.8s; } }

/* Transient bottom-center notice. The admin console had no affordance for this at all (139 sites
   assigning textContent into a div); the portal's tip-toast is Alpine-bound and single-purpose. */
.ot-toast { position:fixed; left:50%; bottom:24px; transform:translateX(-50%); z-index:200; max-width:90vw;
  padding:10px 16px; border:1px solid var(--color-border); border-radius:999px; background:var(--color-elevated);
  color:var(--color-text-primary); font-size:0.85rem; box-shadow:0 8px 30px rgba(0,0,0,0.35);
  opacity:0; transition:opacity 0.18s ease; pointer-events:none; }
.ot-toast.ot-toast-in { opacity:1; }
.ot-toast.ot-toast-err { border-color:var(--color-danger, #e5484d); }

  [x-cloak] { display:none !important; }
  [hidden] { display:none !important; }
  /* WenKai TC for all UI text (EN + 中文); the OpenToken wordmark uses Farsan (set on .brand). Both via Google Fonts. */
  :root { --font-display: 'LXGW WenKai TC', system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Inter", sans-serif; --font-body: 'LXGW WenKai TC', system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Inter", sans-serif; }
  /* No unwanted horizontal PAGE scroll on mobile. Inner code blocks / the tab strip keep their own
     overflow-x (clamp is on the root only); the deposit address lives in a clipping input, not clipped here. */
  /* overflow-x:hidden makes html/body a SCROLL CONTAINER, and position:sticky then anchors to that
     container rather than the viewport — which silently defeats the sticky header. overflow-x:clip
     clips identically without creating one. The hidden declaration stays first as the fallback for
     engines that do not know clip; they keep today's behaviour and lose only the stickiness. */
  html, body { overflow-x: hidden; overflow-x: clip; overscroll-behavior-x: none; }
  html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
  * { -webkit-tap-highlight-color: transparent; }
  button, a, input, select, textarea, [role="button"] { touch-action: manipulation; }
  /* App surface: no visible scrollbars anywhere (content still scrolls). */
  * { scrollbar-width: none; }
  *::-webkit-scrollbar { width: 0; height: 0; display: none; }
  /* min-height keeps the wrap at least viewport-tall: .wrap clips overflow-x (horizontal-pan guard
     on iOS) and CSS couples that clip to the y-axis, so a short landing page would otherwise clip
     the downward Recent-keys dropdown at the card's bottom. 100dvh drops the clip edge past it. */
  .wrap { width:100%; max-width:640px; margin:0 auto; padding:0 20px 100px; overflow-x:clip; min-height:100vh; min-height:100dvh; }
    /* Signed out, the entry hub IS the page: the islands are gone (no key means no chatting, so they
       are absent rather than empty) and the hub centres in the viewport with the footer held at the
       bottom. A plain top margin was tried first and was wrong — with the islands hidden there is
       nothing left to push the footer down, so it floated up under the hub.
       Flexing the wrap is safe despite it holding every modal: 25 of its 31 children are
       fixed/absolute, so only the six in-flow rows take part. Measured, not assumed.
       The two viewports genuinely differ. The column is 640px on a desktop, which stretches the
       field to 550px — far too wide for one short instruction — so the hub takes its own narrower
       measure there. On a phone the column IS the viewport and the field already reads correctly at
       full width, so the cap comes off below the existing 639.98px breakpoint. */
    .wrap.is-out { display:flex; flex-direction:column; }
    .wrap.is-out .card { margin:auto; width:100%; max-width:440px; }
    .wrap.is-out .chatisland { display:none; }
    @media (max-width:639.98px) { .wrap.is-out .card { max-width:none; } }
    /* Signed out the field is empty, so its right side is free: the validity indicator moves there and
       the left slot opens up for the scanner. Clear/copy shift left to sit beside it once you type. */
    .wrap.is-out .lead { left:auto; right:14px; }
    .wrap.is-out .search .input { padding-left:44px; padding-right:100px; }
    .sqr { position:absolute; left:10px; top:50%; transform:translateY(-50%); display:inline-flex; align-items:center; justify-content:center; width:26px; height:26px; padding:0; border:0; border-radius:7px; background:transparent; color:var(--color-text-muted); cursor:pointer; transition:color var(--motion-base) var(--easing-standard); }
    .sqr-right { left:auto; right:10px; }
    .q-sub { flex:0 0 auto; max-width:38%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-size:0.68rem; color:var(--color-text-muted); }
    .iacct-add { color:var(--color-primary); font-size:0.78rem; }
    .sqr:hover { color:var(--color-text-secondary); }
    .sqr svg { width:16px; height:16px; }
    .wrap.is-out .scopy { right:38px; }
    .wrap.is-out .sclear { right:66px; }
  /* Horizontal-pan fix (real root cause): wide code blocks inflated the page on iOS because no ancestor
     could shrink below content width. min-width:0 lets flex/block ancestors shrink (the <pre> keeps its
     OWN inner scroll); .wrap width:100% + overflow-x:clip clamps below 640px (root overflow-x:hidden is
     unreliable on iOS Safari, WebKit #153852, which is why headless Chromium never reproduced it). */
  .codewrap, .md, .cblock, .md-tablewrap, pre.code, pre.cb { min-width:0; max-width:100%; }
  .card, #result, .stat-tile, .chatbar, .search, .mdrop { min-width:0; }
  .brand { display:inline-flex; align-items:center; gap:10px; font-family:'Farsan', var(--font-display); font-size:1.5rem; font-weight:600; letter-spacing:-0.015em; }
    .idc { display:block; width:24px; height:24px; border-radius:var(--radius-full); flex:none; box-shadow:inset 0 0 0 1px rgba(255,255,255,0.14); }
    .idcbtn { display:inline-flex; padding:0; border:0; background:transparent; cursor:pointer; border-radius:var(--radius-full); }
    .idc.is-open { box-shadow:inset 0 0 0 1px rgba(255,255,255,0.14), 0 0 0 2px color-mix(in srgb, var(--color-primary) 55%, transparent); }
    /* Nothing else says the disc can be replaced, so it needs a mark that does. */
    .idcwrap { position:relative; display:inline-block; line-height:0; }
    .idcbadge { position:absolute; right:-2px; bottom:-2px; width:15px; height:15px; padding:0; border-radius:var(--radius-full); background:var(--color-elevated); border:1px solid var(--color-border-strong); color:var(--color-text-secondary); display:grid; place-items:center; cursor:pointer; }
    .idcbadge svg { width:9px; height:9px; }
    .idc-lg { width:30px; height:30px; }
    .idc-sm { width:18px; height:18px; }
    .island.iacct { position:relative; }
    .iacct-body { padding:10px 11px; }
    .iacct-id { display:flex; align-items:center; gap:10px; }
    .iacct-who { flex:1 1 auto; min-width:0; display:flex; flex-direction:column; gap:2px; }
    .iacct-r1 { display:flex; align-items:center; gap:6px; }
    .iacct-k { font-size:0.85rem; color:var(--color-text-primary); }
    .iacct-r2 { display:inline-flex; align-items:center; gap:5px; padding:0; border:0; background:transparent; cursor:pointer; }
    .iacct-a { font-size:0.7rem; color:var(--color-text-muted); }
    .iacct-tri { display:inline-block; font-size:0.5rem; color:var(--color-text-secondary); transition:transform var(--motion-base) var(--easing-standard); }
    .iacct-mini { display:inline-flex; align-items:center; justify-content:center; width:20px; height:20px; padding:0; border:0; border-radius:6px; background:transparent; color:var(--color-text-muted); cursor:pointer; }
    .iacct-mini svg { width:13px; height:13px; }
    .iacct-rnd { flex:none; display:inline-flex; align-items:center; justify-content:center; width:30px; height:30px; border-radius:var(--radius-full); background:var(--color-surface); border:1px solid var(--color-border); color:var(--color-text-secondary); cursor:pointer; }
    .iacct-rnd svg { width:14px; height:14px; }
    .iacct-rnd.is-on { color:var(--color-primary); border-color:color-mix(in srgb, var(--color-primary) 45%, transparent); }
    .iacct-id > .iacct-rnd + .iacct-rnd { margin-left:6px; }
    /* Overlays, never reflows — the same contract as .recent-menu. */
    /* The dropdown hangs off the identity ROW. It used to hang off .island, which was the same
       thing when the island WAS the identity row — then balance, the model picker and the
       how-to moved in, the island grew to 550px, and 100% became its bottom edge. The menu
       drifted 496px down the page. */
    .iacct-idwrap { position:relative; }
    .iacct-menu { position:absolute; left:0; right:0; top:calc(100% + 4px); z-index:30; background:var(--color-elevated); border:1px solid var(--color-border-strong); border-radius:var(--radius-md); box-shadow:var(--shadow-lg); padding:4px; }
  /* The ROSTER scrolls, not the menu: the field sits above it and has to stay put, otherwise the
     control you are typing into scrolls out from under the keyboard on a long key list. */
  .iacct-mlist { max-height:200px; overflow-y:auto; overscroll-behavior:contain; }
  .iacct-tri.is-open { transform:rotate(180deg); }
  /* MARGIN, not padding: an absolutely positioned child measures from the padding box, so padding
     here would offset both buttons from the input they are supposed to sit inside. */
  /* Halo's .island clips to its rounded corners, which also clips the model picker's menu — it hangs
     out of the bottom of the account island and was unusable. Lifted only WHILE that menu is open, so
     the corner clipping every other island relies on stays intact the rest of the time. A class, not
     :has(), because this needs to be deterministic rather than dependent on selector support. */
  .island.iacct.drop-open { overflow:visible; }
  .smart-msg { display:flex; flex-direction:column; gap:6px; margin:8px 10px 0; padding:8px 10px; font-size:0.74rem; line-height:1.4; color:var(--color-text-secondary); background:color-mix(in srgb, var(--color-primary) 10%, transparent); border:1px solid color-mix(in srgb, var(--color-primary) 26%, transparent); border-radius:8px; }
  .smart-prow { display:flex; align-items:center; gap:6px; }
  .smart-paste { flex:1 1 auto; min-width:0; padding:7px 9px; font-size:0.76rem; color:var(--color-text); background:var(--color-surface); border:1px solid var(--color-border-strong); border-radius:7px; }
  .smart-paste:focus { outline:none; border-color:var(--color-primary); }
  .isl-addwrap { position:relative; display:inline-flex; }
  .isl-add.is-armed { color:var(--color-primary); }
  /* Overlays, never reflows — the standing rule for every dropdown here. */
  .postcard { margin:0 0 10px; padding:10px 12px; border:1px solid var(--color-border); border-left:2px solid var(--color-primary); border-radius:8px; background:color-mix(in srgb, var(--color-elevated) 60%, transparent); }
  .pc-head { display:flex; align-items:center; gap:8px; margin-bottom:4px; }
  .pc-who { flex:0 1 auto; font-size:0.74rem; color:var(--color-text-secondary); min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .pc-head > .pc-stats::before { content:'·'; margin-right:6px; opacity:0.6; }
  .pc-load { font-size:0.66rem; color:var(--color-text-muted); margin-left:auto; }
  /* The card is PROVENANCE, not the content. An Instagram caption runs to 2,200 characters and
     pre-wrap honours every newline in it, so an unclamped card grows past the viewport and pushes the
     compose field off the bottom — the one control the chat exists for. Clamped to four lines, and
     nothing is lost by that: the full text still reaches the model through _sourceSystem. Tap to
     read the rest. */
  .pc-text { display:-webkit-box; -webkit-line-clamp:3; -webkit-box-orient:vertical; overflow:hidden; max-height:72px; margin:0; font-size:0.82rem; line-height:1.5; white-space:pre-wrap; overflow-wrap:anywhere; }
  /* No separate control. The clipped text and the thumbnail ARE the affordance — a card that is
     visibly cut off is already saying there is more, and one tap anywhere on it opens the sheet. */
  .pc-body { cursor:pointer; }
  /* FLOAT, not flex. Flex pins the text into a fixed column it can never leave, so every line past
     the bottom of a 72px thumbnail still stopped short and left that width unused. A float lets the
     text run alongside the image and then reclaim the full width underneath it. */
  .pc-body { display:flex; align-items:flex-start; gap:10px; margin:0 0 6px; }
  /* min-width:0, or a long unbroken caption blows the column out and takes the page scroll with it. */
  .pc-txt { position:relative; flex:1 1 auto; min-width:0; }
  /* Top padding is not decoration. With none the grip sat flush against the sheet's edge, and its hit
     area starts 14px ABOVE the bar — so it reached onto the backdrop, where a press does nothing.
     16px, measured: less and the area still pokes out by a pixel or two. */
  .src-sheet { position:fixed; left:0; right:0; bottom:0; z-index:61; margin:0 auto; max-width:640px; max-height:88vh; display:flex; flex-direction:column; padding:10px 16px calc(16px + env(safe-area-inset-bottom, 0px)); background:var(--color-surface); border:1px solid var(--color-border-strong); border-bottom:0; border-radius:28px 28px 0 0; box-shadow:var(--shadow-lg); animation:sheetUp var(--motion-base) var(--easing-standard); }
  .src-scroll { min-height:0; overflow-y:auto; overscroll-behavior:contain; }
  /* contain, not cover: this is the one place the whole picture should be visible. */
  .src-carousel { margin:0 0 10px; }
  /* The button anchors to THIS, not to the carousel: the carousel also contains the dots row, so
     bottom:8px of it put the control over the dots instead of over the picture. The track itself
     cannot be the anchor either - it scrolls, and an absolute child would swipe away with frame 1. */
  .src-frame { position:relative; }
  /* Sits ON the photo, because the photo is the thing being attached. */
  .src-att { position:absolute; right:8px; bottom:8px; z-index:2; display:flex; align-items:center; justify-content:center; width:34px; height:34px; padding:0; border:0; border-radius:var(--radius-full); background:rgba(0,0,0,0.55); color:#fff; cursor:pointer; backdrop-filter:blur(4px); transition:background var(--motion-base) var(--easing-standard); }
  .src-att:hover { background:rgba(0,0,0,0.75); }
  .src-att svg { width:17px; height:17px; }
  /* The zoom happens on a COPY pinned to the viewport. The track is a horizontal scroller, so it
     clips: scaling the frame in place would grow it into a hidden box, and taking the frame out of
     flow would collapse the carousel's layout and lose its scroll position. */
  .src-zoom { position:fixed; z-index:70; object-fit:contain; pointer-events:none; will-change:transform; border-radius:8px; background:var(--color-elevated); }
  /* One frame per image, snapped. overscroll-behavior-x:contain stops a swipe past the last frame
     becoming a browser back-gesture, which on iOS would close the sheet mid-look. */
  /* The track takes the PHOTOS' shape, not a fixed slab. A flat max-height meant a 4:5 portrait -
     what Instagram and xiaohongshu both default to - was fitted into a box too short to fill the
     width, so it sat between two grey bars while a landscape shot left an empty band below it.
     Ratio comes from the first frame; max-height is only the backstop for something very tall.
     70vh, and the number is derived rather than picked: 3:4 and 4:5 are what the platforms serve,
     and filling the width with those on the SHORTEST common phone - 341px of content in a 667px
     viewport - needs 455px, which is 68vh. At 56vh the same photo letterboxed by 61px there while
     looking perfect on a 812px screen. The sheet scrolls, so height costs less than grey bars. */
  .src-track { display:flex; overflow-x:auto; overflow-y:hidden; scroll-snap-type:x mandatory; scroll-behavior:smooth; overscroll-behavior-x:contain; -webkit-overflow-scrolling:touch; scrollbar-width:none; width:100%; aspect-ratio:var(--src-ar, 0.8); max-height:70vh; min-height:64px; }
  .src-track::-webkit-scrollbar { display:none; }
  /* contain, not cover: the sheet is the one place the whole picture should be visible. */
  .src-img { flex:0 0 100%; scroll-snap-align:center; display:block; width:100%; height:100%; object-fit:contain; border-radius:8px; background:var(--color-elevated); }
  .src-dots { display:flex; justify-content:center; align-items:center; gap:7px; margin:8px 0 0; }
  /* A 7px dot is not a tap target; the hit area is, and it stays inside the row. */
  .src-dot { position:relative; width:7px; height:7px; padding:0; border:0; border-radius:50%; background:var(--color-border-strong); cursor:pointer; transition:background var(--motion-base) var(--easing-standard); }
  .src-dot.is-on { background:var(--color-primary); }
  .src-dot::before { content:''; position:absolute; top:50%; left:50%; transform:translate(-50%, -50%); width:28px; height:28px; }
  /* The count of what is MISSING sits with the dots, not hidden in the system message: the dots
     otherwise assert the gallery is complete. */
  .src-rest { margin-left:4px; font-size:0.66rem; color:var(--color-text-muted); font-variant-numeric:tabular-nums; }
  .src-who { margin:0 0 8px; font-size:0.72rem; color:var(--color-text-muted); }
  .src-full { margin:0 0 10px; font-size:0.86rem; line-height:1.55; white-space:pre-wrap; overflow-wrap:anywhere; }
  .src-link { display:block; font-size:0.68rem; color:var(--color-text-muted); overflow-wrap:anywhere; }
  .pc-media { position:relative; flex:none; }
  .pc-thumb { display:block; width:72px; height:72px; object-fit:cover; border-radius:6px; border:1px solid var(--color-border); background:var(--color-surface); }
  .pc-count { position:absolute; right:3px; bottom:3px; padding:1px 5px; font-size:0.6rem; color:#fff; background:rgba(0,0,0,0.62); border-radius:999px; }
  /* On the header line, not a line of its own. It absorbs the leftover width and truncates first —
     the author's name matters more than the date, so that is the one that keeps its room. */
  .pc-stats { flex:1 1 auto; min-width:0; font-size:0.68rem; color:var(--color-text-muted); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .pc-note { margin:0 0 4px; font-size:0.68rem; color:var(--color-text-muted); font-style:italic; }
  /* The chips and the post button are Halo's btn/btn-xs/btn-outline/btn-primary. A local pill would
     shadow .chip AND re-derive a button that already exists — the drift the ratchet test stops.
     Only the LAYOUT is local, because Halo has no opinion about where these sit. */
  .pc-acts { display:flex; flex-wrap:wrap; align-items:center; gap:6px; margin-top:8px; }
  .pc-out { margin-left:auto; }
  .pc-over { font-size:0.66rem; opacity:0.8; }
  .pc-link { display:block; font-size:0.66rem; color:var(--color-text-muted); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .iacct-addrow { position:relative; margin:2px 0 6px; }
  .iacct-addbtn { position:absolute; top:50%; transform:translateY(-50%); display:inline-flex; align-items:center; justify-content:center; width:26px; height:26px; padding:0; border:0; border-radius:7px; background:transparent; color:var(--color-text-muted); cursor:pointer; transition:color var(--motion-base) var(--easing-standard); }
  .iacct-addbtn svg { width:15px; height:15px; }
  .iacct-addbtn:hover { color:var(--color-text); }
  .iacct-addpaste { left:7px; }
  .iacct-addpaste.is-bad { color:var(--color-danger); }
  .iacct-addclr { right:7px; }
  .iacct-addin { width:100%; padding:8px 38px; font-size:0.76rem; color:var(--color-text); background:var(--color-surface); border:1px solid var(--color-border-strong); border-radius:8px; transition:border-color var(--motion-base) var(--easing-standard); }
  .iacct-addin::placeholder { color:var(--color-text-muted); }
  .iacct-addin:focus { outline:none; border-color:var(--color-primary); }
  .iacct-addin:disabled { opacity:0.6; }
  .iacct-adderr { margin:0; padding:0 10px 6px; font-size:0.7rem; color:var(--color-danger); }
    .iacct-rot { margin-top:10px; padding:10px; border:1px solid var(--color-border); border-radius:var(--radius-md); background:var(--color-background); }
    .iacct-rothint { margin:0 0 8px; font-size:0.72rem; line-height:1.4; color:var(--color-text-secondary); }
    .iacct-rotrow { display:flex; align-items:center; gap:8px; }
    .iacct-rotrow .input { flex:1 1 auto; min-width:0; }
    .iacct-fresh { flex:1 1 auto; min-width:0; font-size:0.72rem; word-break:break-all; color:var(--color-text-primary); }
    .iacct-roterr { margin:8px 0 0; font-size:0.72rem; color:var(--color-danger); }
    .iacct-rotclose { margin-top:8px; padding:0; border:0; background:transparent; color:var(--color-text-muted); font-size:0.72rem; cursor:pointer; }
    .ebrow { display:flex; align-items:center; justify-content:space-between; gap:8px; margin:14px 0 6px; }
    .ebrow .lbl { display:flex; align-items:center; gap:7px; font-size:0.72rem; text-transform:uppercase; letter-spacing:1.2px; color:var(--color-text-primary); }
    .ebrow .lbl i { width:6px; height:6px; border-radius:var(--radius-full); background:var(--color-primary); display:block; }
    /* Inside the island these are sub-sections of one card, not cards in their own right, so they
       take the island's scale rather than the page's. The balance tile's own 20px padding was what
       read as a gap under the identity row — the two are flush; the space was internal to it. */
    .iacct-body .stat-tile { padding:11px 13px; margin-top:14px; }
    /* The head row's height is set by its icon buttons, which push the eyebrow down by half the
       difference. Shrinking them tightens the card without touching the type. */
    .iacct-body .stat-tile .iconbtn { width:24px; height:24px; }
    .iacct-body .stat-tile .stat-head { gap:8px; }
    .iacct-body .howto-toggle { margin-top:16px !important; font-size:0.72rem; letter-spacing:1px; }
    .iacct-body .mdrop { margin-top:7px; }
      .iacct-mi { display:flex; align-items:center; gap:9px; width:100%; padding:7px 9px; border:0; border-radius:8px; background:transparent; cursor:pointer; text-align:left; }
    .iacct-mtext { display:flex; flex-direction:column; gap:1px; min-width:0; }
    .iacct-mtext > span:first-child { font-size:0.78rem; color:var(--color-text-primary); }
  .brand svg { width:24px; height:24px; color:var(--color-primary); stroke-width:2; }
  /* Brand + language switch share one row, so the switch lives inside .wrap and inherits its
     safe-area top padding — in installed/standalone mode it no longer hides under the status bar. */
  /* The header sticks. z-index 45 puts it above every in-page dropdown (30) and the fab (40) so a
     switcher opening below can never paint over it, and below modals (60) and toasts (200), which
     should still cover it. Its own search dropdown is a child, so it rides along inside this
     stacking context.
     The background is a bleeding pseudo-element rather than a background on the bar itself: .wrap
     carries side padding, so a plain background would leave strips at both edges for content to
     scroll through. .wrap already sets overflow-x:clip, so the bleed cannot make the page scroll
     sideways. Vertical spacing is unchanged — the old 16px margin becomes 10px padding + 6px. */
  /* The sticky spacer: transparent, and it owns the room above the controls so their position does
     not shift when it sticks. */
  .topbar { position:sticky; top:0; z-index:45; display:flex; align-items:center; justify-content:space-between; gap:10px; flex-wrap:nowrap; margin-bottom:16px; padding-top:calc(20px + env(safe-area-inset-top, 0px)); }
  /* The material goes on each CONTROL, never on a bar wrapping them. One capsule around everything
     is still a plate — just with rounded ends — and it reinstates the edge the plate was removed
     for. Liquid glass floats separate objects. The identicon carries none: it is a coloured disc,
     and glass over it would only mute the hue that identifies the account.
     Signed OUT there is nothing to see through — the hub is centred on an empty page and nothing
     scrolls behind — so the material is scoped to the signed-in shell rather than applied and then
     wasted.
     CSS cannot refract, so depth is three cues that read as glass together and as nothing apart: a
     saturating blur, a bright inset hairline for the specular rim, and a shadow lifting it clear. */
  .wrap:not(.is-out) .glassy { border:1px solid color-mix(in srgb, #fff 9%, transparent); background:color-mix(in srgb, var(--color-surface) 62%, transparent); box-shadow:inset 0 1px 0 color-mix(in srgb, #fff 14%, transparent), 0 4px 14px rgba(0,0,0,0.28); }
  @supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .wrap:not(.is-out) .glassy { background:color-mix(in srgb, var(--color-surface) 38%, transparent); -webkit-backdrop-filter:blur(18px) saturate(180%); backdrop-filter:blur(18px) saturate(180%); }
  }
  @media (prefers-reduced-transparency: reduce) {
    .wrap:not(.is-out) .glassy { background:var(--color-surface); -webkit-backdrop-filter:none; backdrop-filter:none; }
  }
  /* The add-a-key sheet. Same card, drawn up from the bottom: signed in there is no sensible place
     for it in the flow — it landed between the account island and Working, reading as an orphan
     island with an input in it. Sits above the modal layer (60) so it behaves like every other
     dialog here, and stops at 640px so it does not stretch across a desktop pane. */
  /* touch-action:none, because a swipe that starts on the backdrop has no business reaching the
     page. Paired with html.sheet-lock below - a modal that lets the layer beneath it scroll is not
     modal. .src-scroll already carries overscroll-behavior:contain, but that only bites once the
     element ACTUALLY overflows, and a short post does not: the swipe fell straight through to the
     document scroller and took the islands with it. */
  .sheet-back { position:fixed; inset:0; z-index:60; background:rgba(0,0,0,0.5); touch-action:none; }
  html.sheet-lock, html.sheet-lock body { overflow-y:hidden; }
  .card.as-sheet { position:fixed; left:0; right:0; bottom:0; z-index:61; width:100%; max-width:640px; margin:0 auto; border-radius:var(--radius-lg) var(--radius-lg) 0 0; padding-bottom:calc(var(--space-6) + env(safe-area-inset-bottom, 0px)); max-height:86vh; overflow-y:auto; box-shadow:0 -12px 40px rgba(0,0,0,0.45); animation:sheetUp var(--motion-slow) var(--easing-standard); }
  /* The sheet follows the finger while dragging, so nothing is animated then; the transition is
     only for the spring back. */
  .src-sheet.is-dragging { animation:none; transition:none; }
  .src-sheet { transition:transform var(--motion-base) var(--easing-standard); }
  .sheet-grip { position:relative; width:52px; height:6px; border-radius:var(--radius-full); background:var(--color-border-strong); margin:0 auto 10px; cursor:grab; touch-action:none; transition:background var(--motion-base) var(--easing-standard), box-shadow var(--motion-base) var(--easing-standard), transform var(--motion-fast) var(--easing-standard); }
  .sheet-grip:active { cursor:grabbing; }
  /* A 6px bar is not a 6px target. 44px tall is Apple's minimum, and it is anchored to the bar's
     BOTTOM rather than centred on it, which is what lets the visible band be thin: only 8px reaches
     down, and the rest hangs UPWARD past the sheet's own top edge over the backdrop. Measured: that
     overhang is still hit-testable, so a press just above the sheet catches the handle - and even
     when it misses, the backdrop it covers dismisses on tap exactly as the grip does.
     Downward is the constrained direction, because the carousel comes later in the DOM and wins the
     hit test wherever it overlaps. At a 12px gap with a centred area, a press 15px under the bar
     landed on the photo and quietly ate a third of the handle. */
  .sheet-grip::before { content:''; position:absolute; bottom:-8px; left:50%; transform:translateX(-50%); width:140px; height:44px; }
  /* Held. The bar is the only thing under the finger during a drag, so it is the only thing that can
     confirm the sheet is listening — it lights up and thickens slightly rather than just sitting
     there. :active covers the press before the first move; .is-dragging covers the rest, and both
     grips use it (the account sheet sets the same class on its own container). */
  .is-dragging .sheet-grip, .sheet-grip:active { background:var(--color-primary); box-shadow:0 0 0 5px var(--color-primary-soft), 0 0 14px color-mix(in srgb, var(--color-primary) 55%, transparent); transform:scaleY(1.35); }
  @media (prefers-reduced-motion: reduce) { .sheet-grip { transition:none; } .is-dragging .sheet-grip, .sheet-grip:active { transform:none; } }
  .card.as-sheet.is-dragging { animation:none; transition:none; }
  @keyframes sheetUp { from { transform:translateY(12%); opacity:0; } to { transform:translateY(0); opacity:1; } }
  @media (prefers-reduced-motion: reduce) { .card.as-sheet { animation:none; } }
  .topsearch { position:relative; flex:1 1 auto; min-width:0; }
  .topsearch .input { width:100%; height:34px; padding-left:14px; padding-right:38px; border-radius:var(--radius-full); }
  .topsearch .sqr-right { right:8px; }
  .langseg { flex-shrink:0; display:inline-flex; gap:2px; background:var(--color-surface); border:1px solid var(--color-border); border-radius:var(--radius-full); padding:3px; }
  .langopt { border:0; background:transparent; color:var(--color-text-secondary); font:inherit; font-size:0.78rem; line-height:1; padding:5px 11px; border-radius:var(--radius-full); cursor:pointer; transition:background var(--motion-base) var(--easing-standard), color var(--motion-base) var(--easing-standard); }
  .langopt:hover { color:var(--color-text-primary); }
  .langopt.is-active { background:var(--color-elevated); color:var(--color-text-primary); }
  .mono { font-family:var(--font-mono); }
  .muted { color:var(--color-text-secondary); }
  .hint { color:var(--color-text-muted); font-size:0.8125rem; margin:10px 2px 0; }
  .err { color:var(--color-danger); font-size:0.8125rem; margin-top:8px; }
  .btn-block { width:100%; }
  .row { display:flex; gap:10px; align-items:center; }
  .row .input { flex:1; min-width:180px; }
  .search { position:relative; }
  .search .input { padding-left:40px; padding-right:74px; }
  .search .lead { position:absolute; left:13px; top:50%; transform:translateY(-50%); width:16px; height:16px; color:var(--color-text-muted); pointer-events:none; transition:color var(--motion-base) var(--easing-standard); }
  .search .lead svg { width:16px; height:16px; stroke-width:2; }
  .search .lead.is-ok { color:var(--color-text-primary); }   /* valid key/voucher: the icon brightens (replaces the green check) */
  .scopy { position:absolute; right:12px; top:50%; transform:translateY(-50%); display:inline-flex; align-items:center; justify-content:center; width:26px; height:26px; padding:0; border:0; border-radius:7px; background:transparent; color:var(--color-text-secondary); cursor:pointer; }
  .scopy:hover { background:var(--color-elevated); color:var(--color-text-primary); }
  .scopy svg { width:16px; height:16px; }
  .sclear { position:absolute; right:40px; top:50%; transform:translateY(-50%); display:inline-flex; align-items:center; justify-content:center; width:26px; height:26px; padding:0; border:0; border-radius:7px; background:transparent; color:var(--color-text-muted); cursor:pointer; }
  .sclear:hover { background:var(--color-elevated); color:var(--color-text-primary); }
  .sclear svg { width:17px; height:17px; }
  .card { gap:12px; }
  #result { margin-top:0; }
  #vnew { margin-top:12px; }
  .orline { display:flex; align-items:center; gap:12px; margin:16px 0 12px; color:var(--color-text-muted); font-size:0.8125rem; }
  .orline:before, .orline:after { content:""; flex:1; height:1px; background:var(--color-border); }
  .balcard { margin-top:0; }
  .balcard .stat-head { align-items:center; }
  .balcard .tip { border-top:1px solid var(--color-border); padding-top:14px; }
  .balcard .tip .row .input { min-width:0; }
  .balrow { display:flex; align-items:center; justify-content:space-between; gap:12px; }
  .iconbtn { display:inline-flex; align-items:center; justify-content:center; width:30px; height:30px; padding:0; border:0; border-radius:7px; background:transparent; color:var(--color-text-muted); cursor:pointer; flex-shrink:0; }
  .iconbtn:hover, .iconbtn[aria-expanded="true"] { background:var(--color-elevated); color:var(--color-text-primary); }
  .iconbtn svg { width:16px; height:16px; stroke-width:2; }
  /* ★ affordance sitting right after the BALANCE label (tooltip explains it). */
  .starbtn { border:0; background:transparent; cursor:pointer; padding:1px 4px; font-size:1rem; line-height:1; border-radius:5px; }
  .starbtn:hover:not(:disabled) { background:var(--color-elevated); }
  .starbtn[aria-expanded="true"] { background:var(--color-elevated); }
  .starbtn:disabled { opacity:0.45; cursor:default; }
  .histcols { display:flex; gap:18px; }
  .histcol { flex:1; min-width:0; }
  .histcol-h { font-size:0.7rem; margin-bottom:8px; }
  .histcol-body { display:flex; flex-direction:column; gap:8px; }
  .histrow { display:flex; align-items:baseline; justify-content:space-between; gap:10px; font-size:0.8125rem; }
  .histrow .hr-amt, .histrow .hr-model { font-family:var(--font-mono); color:var(--color-text-primary); }
  .histrow .hr-amt { color:var(--color-success); }
  .histrow .hr-model { flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .histrow .hr-date { color:var(--color-text-muted); white-space:nowrap; flex-shrink:0; }
  .histrow-u { display:flex; flex-direction:column; gap:1px; padding:3px 0; }
  .histrow-u .hr-top { display:flex; align-items:baseline; justify-content:space-between; gap:8px; font-size:0.8125rem; }
  .histrow-u .hr-when { font-family:var(--font-mono); color:var(--color-text-muted); flex-shrink:0; }
  .histrow-u .hr-model { font-family:var(--font-mono); color:var(--color-text-primary); flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .histrow-u .hr-cost { font-family:var(--font-mono); color:var(--color-success); flex-shrink:0; font-size:0.8125rem; }
  .histrow-u .hr-tok { display:flex; align-items:baseline; justify-content:space-between; gap:8px; font-family:var(--font-mono); font-size:0.72rem; color:var(--color-text-muted); }
  .histrow-u .hr-tok > span:first-child { min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .pager { display:flex; align-items:center; justify-content:center; gap:12px; margin-top:8px; }
  .pgbtn { width:24px; height:24px; padding:0; border:1px solid var(--color-border); border-radius:6px; background:transparent; color:var(--color-text-secondary); cursor:pointer; font-size:1rem; line-height:1; display:inline-flex; align-items:center; justify-content:center; }
  .pgbtn:hover:not(:disabled) { background:var(--color-elevated); color:var(--color-text-primary); }
  .pgbtn:disabled { opacity:0.3; cursor:default; }
  .histfilter { display:flex; gap:6px; margin-bottom:10px; }
  .hf { font-size:0.72rem; padding:3px 11px; border:1px solid var(--color-border); border-radius:999px; background:transparent; color:var(--color-text-secondary); cursor:pointer; }
  .hf:hover { color:var(--color-text-primary); }
  .hf.on { background:var(--color-elevated); color:var(--color-text-primary); border-color:var(--color-text-muted); }
  .histrow-u .hr-amt2 { font-family:var(--font-mono); flex-shrink:0; font-size:0.8125rem; }
  .histrow-u .hr-amt2.earn { color:var(--color-success); }
  .histrow-u .hr-amt2.spend { color:var(--color-text-muted); }
  .histrow-u .hr-amt2.failed { color:var(--color-warning); font-family:var(--font-sans); }
  .locked-pane { position:relative; min-height:160px; display:flex; align-items:center; justify-content:center; padding:18px 14px; }
  .locked-blur { position:absolute; inset:14px; display:flex; flex-direction:column; gap:12px; pointer-events:none; }
  .lb-line { height:11px; border-radius:6px; background:var(--color-border); filter:blur(2px); opacity:0.55; }
  .x402-btn { position:relative; display:inline-flex; align-items:center; gap:8px; padding:10px 22px; border-radius:12px; border:1px solid var(--color-border); background:var(--color-elevated); color:var(--color-text-primary); font-weight:500; font-size:0.95rem; cursor:pointer; }
  .x402-btn:hover { border-color:var(--color-primary); color:var(--color-primary); }
  .x402-btn svg { width:16px; height:16px; }
  .buy-desc { color:var(--color-text-secondary); font-size:0.9rem; line-height:1.6; margin:0 0 12px; }
  .buy-meta { display:flex; align-items:center; gap:7px; font-size:0.82rem; color:var(--color-text-muted); margin-bottom:8px; }
  .buy-meta svg { width:15px; height:15px; flex-shrink:0; }
  .buy-sealed { color:var(--color-success); }
  .buy-offer { display:inline-block; font-size:0.78rem; color:var(--color-primary); background:var(--color-elevated); border-radius:6px; padding:2px 9px; margin-bottom:8px; }
  .buy-price { display:flex; align-items:baseline; gap:10px; margin:6px 0 12px; }
  .buy-old { font-family:var(--font-mono); color:var(--color-text-muted); text-decoration:line-through; font-size:0.9rem; }
  .buy-net { font-family:var(--font-mono); font-size:1.5rem; font-weight:500; color:var(--color-text-primary); }
  .buy-bal { font-size:0.82rem; color:var(--color-text-muted); margin:0 0 12px; }
  .sell-box { margin-top:16px; padding-top:14px; border-top:1px solid var(--color-border); }
  .sell-row { display:flex; gap:8px; margin:8px 0; }
  .sell-row .input { flex:1; }
  .sell-listed { display:flex; align-items:center; justify-content:space-between; gap:10px; margin:8px 0; }
  .sell-amt { font-family:var(--font-mono); color:var(--color-success); }
  /* sell-artifact publish modal (stage 4c) */
  .sell-field { display:flex; flex-direction:column; gap:4px; margin:10px 0; }
  .sell-field .input { width:100%; }
  .sell-label { font-size:0.75rem; color:var(--color-text-muted); }
  .sell-row .sell-field { flex:1; margin:0; }
  .sell-row .sell-price { flex:2; }
  .sell-quote-btn { display:inline-flex; align-items:center; justify-content:center; gap:7px; margin:2px 0 8px; }
  .sell-quote-btn svg { width:16px; height:16px; }
  .sell-quote { background:var(--color-elevated); border:1px solid var(--color-border); border-radius:var(--radius-md); padding:9px 11px; margin:0 0 10px; }
  .sell-quote-notes { font-size:0.82rem; color:var(--color-text-secondary); margin:0; }
  .sell-quote-notes.is-warn { color:var(--color-warning); }
  .sell-quote-rationale { font-size:0.74rem; color:var(--color-text-muted); margin:5px 0 0; }
  .sell-tos { display:flex; align-items:flex-start; gap:8px; font-size:0.8rem; color:var(--color-text-secondary); margin:6px 0 12px; cursor:pointer; }
  .sell-tos input { margin-top:2px; flex-shrink:0; }
  /* relocate (Copy/Move to island) picker (islands v2) */
  .relocate-list { display:flex; flex-direction:column; gap:8px; margin:10px 0; }
  .relocate-target { display:flex; align-items:center; gap:9px; justify-content:flex-start; text-align:left; }
  .relocate-target svg { width:16px; height:16px; flex:none; color:var(--color-text-muted); }
  .relocate-kind { margin-left:auto; font-size:0.7rem; color:var(--color-text-muted); text-transform:uppercase; letter-spacing:0.04em; }
  .relocate-new { display:flex; gap:8px; margin-top:12px; }
  .relocate-new .input { flex:1; }
  .relocate-new .btn { flex:none; white-space:nowrap; }
  /* Shared-chat Continue affordance (islands v2): replaces the compose input on a received remote chat */
  /* Shared-chat Tip gate (islands v2): replaces the compose input on a received remote chat until a tip is picked */
  .tip-bar { flex:1; display:flex; align-items:center; gap:6px; flex-wrap:wrap; padding:6px 8px; border:1px solid var(--color-border); border-radius:var(--radius-md); background:var(--color-elevated); }
  .tip-label { font-size:0.8rem; color:var(--color-text-muted); margin-right:2px; }
  .tip-opt { padding:4px 10px; border:1px solid var(--color-border); border-radius:999px; background:var(--color-surface); color:var(--color-text-secondary); cursor:pointer; font-size:0.8rem; font-weight:500; line-height:1.4; transition:background var(--motion-base) var(--easing-standard), border-color var(--motion-base) var(--easing-standard), color var(--motion-base) var(--easing-standard); }
  .tip-opt:hover { border-color:var(--color-primary); color:var(--color-primary); }
  .tip-opt.tip-no { color:var(--color-text-muted); }
  .tip-toast { position:fixed; left:50%; bottom:24px; transform:translateX(-50%); z-index:80; max-width:90vw; padding:10px 16px; border:1px solid var(--color-border); border-radius:999px; background:var(--color-elevated); color:var(--color-text-primary); font-size:0.85rem; box-shadow:0 8px 30px rgba(0,0,0,0.35); }
  .tip-more-wrap { position:relative; display:inline-flex; }
  .tip-more-btn { display:inline-flex; align-items:center; justify-content:center; padding:4px 6px; }
  .tip-more-btn svg { width:14px; height:14px; }
  .tip-more-pop { position:absolute; bottom:calc(100% + 6px); right:0; z-index:20; display:flex; flex-direction:column; gap:2px; padding:5px; background:var(--color-background); border:1px solid var(--color-border); border-radius:var(--radius-md); box-shadow:0 8px 26px rgba(0,0,0,0.28); min-width:84px; }
  .tip-more-item { padding:6px 12px; border:0; border-radius:var(--radius-sm); background:transparent; color:var(--color-text-secondary); cursor:pointer; font-size:0.82rem; text-align:left; }
  .tip-more-item:hover { background:var(--color-elevated); color:var(--color-primary); }
  .pgnum { font-family:var(--font-mono); font-size:0.72rem; color:var(--color-text-muted); min-width:14px; text-align:center; }
  @media (max-width:520px) { .histcols { flex-direction:column; gap:14px; } }
  .codewrap { border:1px solid var(--color-border); border-radius:var(--radius-md); overflow:hidden; margin-top:14px; }
  .codebar { display:flex; align-items:center; justify-content:space-between; gap:10px; padding:7px 8px; background:var(--color-surface); border-bottom:1px solid var(--color-border); }
  .codebar .tabs { margin-top:0; background:transparent; border:0; padding:0; gap:3px; flex-wrap:wrap; }
  .codebar .tab { height:28px; padding-inline:11px; }
  /* Mobile: tighter top spacing + the How-to-use tab row becomes a single horizontal-scroll strip
     (5 tabs otherwise wrap to two lines on narrow screens). Placed AFTER the codebar base rules so
     these overrides win on source order (same specificity). */
  @media (max-width:560px) {
    /* env() insets are 0 in a normal tab; in the installed standalone app (black-translucent
       status bar + viewport-fit=cover) they clear the notch/clock and the home indicator. */
    .wrap { padding:0 calc(12px + env(safe-area-inset-right)) calc(24px + env(safe-area-inset-bottom)) calc(12px + env(safe-area-inset-left)); }
    .codebar { gap:6px; }
    /* 5 tabs share the row equally — NO horizontal-scroll strip (that read as a "page pan" on touch
       in the key view). flex:1 + min-width:0 + ellipsis guarantees they fit at any width, no scroll. */
    .codebar .tabs { flex:1 1 auto; min-width:0; flex-wrap:nowrap; overflow:hidden; gap:2px; }
    .codebar .tab { flex:1 1 0; min-width:0; padding-inline:4px; font-size:0.72rem; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; text-align:center; justify-content:center; }
    .row { flex-wrap:wrap; }
    .row .input { min-width:0; }
    input, textarea, select { font-size:16px; }
  }
  .codecopy { display:inline-flex; align-items:center; justify-content:center; width:30px; height:30px; padding:0; border:0; border-radius:7px; background:transparent; color:var(--color-text-secondary); cursor:pointer; flex-shrink:0; }
  .codecopy:hover { background:var(--color-elevated); color:var(--color-text-primary); }
  .codecopy svg { width:16px; height:16px; }
  .mdrop { position:relative; margin-top:10px; }
  .mdrop-trigger { display:flex; align-items:center; justify-content:space-between; gap:10px; width:100%; height:42px; background:var(--color-surface); color:var(--color-text-primary); border:1px solid var(--color-border); border-radius:var(--radius-md); padding:0 14px; font-family:var(--font-mono); font-size:0.875rem; cursor:pointer; text-align:left; transition:border-color var(--motion-base) var(--easing-standard), box-shadow var(--motion-base) var(--easing-standard); }
  .mdrop-trigger:hover { border-color:var(--color-border-strong); }
  .mdrop-trigger:focus-visible, .mdrop.open .mdrop-trigger { outline:none; border-color:var(--color-primary); box-shadow:var(--focus-ring); }
  .mdrop-trigger .chev { width:16px; height:16px; color:var(--color-text-secondary); flex-shrink:0; transition:transform var(--motion-base) var(--easing-standard); }
  .mdrop.open .mdrop-trigger .chev { transform:rotate(180deg); }
  .mdrop-menu { position:absolute; left:0; right:0; top:calc(100% + 6px); background:var(--color-elevated); border:1px solid var(--color-border-strong); border-radius:var(--radius-md); box-shadow:var(--shadow-lg); padding:4px; z-index:30; max-height:280px; overflow-y:auto; overscroll-behavior:contain; }
  .mdrop-sect { position:relative; display:flex; align-items:baseline; gap:7px; padding:7px 9px 4px; font-size:0.64rem; font-weight:700; text-transform:uppercase; letter-spacing:0.06em; color:var(--color-text-muted); }
  .mdrop-sect-sub { font-weight:500; letter-spacing:0; text-transform:none; font-size:0.66rem; color:var(--color-text-muted); opacity:0.8; }
  /* The allowance lives here rather than in the header, so the header can state the deal in four
     words. Sized to the sub-label it sits beside, not to a control. */
  .sect-i { display:inline-flex; align-items:center; color:var(--color-text-muted); opacity:0.75; cursor:help; margin-left:5px; }
  .sect-i svg { width:12px; height:12px; }
  .sect-i:hover, .sect-i:focus-visible { opacity:1; color:var(--color-primary); }
  /* Deliberately NOT position:relative — the panel's containing block is the SECTION, so it spans the
     section's width and cannot overflow a menu that clips (overflow-y:auto). Shown on focus as well as
     hover, because tabindex+focus is the only way a touch device can ever open it. */
  .sect-i::after { content:attr(data-tip); position:absolute; left:9px; right:9px; top:calc(100% - 2px); z-index:5;
    padding:7px 9px; border-radius:var(--radius-sm); background:var(--color-text-primary); color:var(--color-surface);
    font-size:0.7rem; font-weight:500; line-height:1.45; letter-spacing:0; text-transform:none; text-align:left;
    white-space:normal; box-shadow:var(--shadow-lg);
    opacity:0; visibility:hidden; transition:opacity var(--motion-base) var(--easing-standard); }
  .sect-i:hover::after, .sect-i:focus::after { opacity:1; visibility:visible; }
  .mitem-top .chip { flex:none; }
  .mdrop-item { display:flex; flex-direction:row; align-items:center; gap:12px; width:100%; background:transparent; border:0; border-radius:8px; padding:9px 11px; color:var(--color-text-primary); font-family:var(--font-mono); font-size:0.8125rem; cursor:pointer; text-align:left; }
  .mitem-top { display:flex; align-items:center; justify-content:space-between; gap:12px; }
  .mitem-name { display:inline-flex; align-items:center; gap:8px; min-width:0; }
  .mitem-name .mitem-lbl { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .mitem-chips { display:flex; align-items:center; gap:6px; flex-wrap:wrap; margin-top:6px; }
  /* Text on the left, price on the right, and the ring CENTRED against both price lines — which is
     what lets it be 26px instead of 18px, and the 9px label inside it actually readable. It sat on the
     chips row before, sized to a chip and squinting. */
  .mitem-main { flex:1 1 auto; min-width:0; display:flex; flex-direction:column; align-items:stretch; }
  .mitem-px { display:flex; align-items:center; gap:10px; flex-shrink:0; }
  /* The ring is LAST and the prices are right-aligned against it, so every ring in the list lands on
     the same x. With the ring leading, a wide price pushed it out and the column read ragged. */
  .mitem-px .cwrap { order:2; }
  .mitem-pxcol { order:1; }
  .mitem-pxcol { display:flex; flex-direction:column; align-items:flex-end; gap:2px; }
  .mitem-pxcol .mdrop-band { margin-left:0; }
  .chdot { width:9px; height:9px; border-radius:var(--radius-full); flex-shrink:0; }
  .mdrop .chip { height:20px; padding-inline:8px; font-size:0.6875rem; }
  .mdrop-item:hover { background:var(--color-surface); }
  /* Recent keys/vouchers dropdown under the entry field (reuses the elevated-menu look) */
  .recent-menu { position:absolute; left:0; right:0; top:calc(100% + 6px); background:var(--color-elevated); border:1px solid var(--color-border-strong); border-radius:var(--radius-md); box-shadow:var(--shadow-lg); padding:4px; z-index:30; max-height:260px; overflow-y:auto; overscroll-behavior:contain; }
  .recent-h { font-size:0.66rem; text-transform:uppercase; letter-spacing:0.5px; color:var(--color-text-muted); padding:6px 9px 4px; }
  .recent-item { display:flex; align-items:center; gap:9px; padding:8px 9px; border-radius:8px; cursor:pointer; }
  .recent-item:hover { background:var(--color-surface); }
  .recent-ic { display:inline-flex; align-items:center; width:15px; height:15px; color:var(--color-text-secondary); flex-shrink:0; }
  .recent-ic svg { width:15px; height:15px; }
  .recent-v { flex:1 1 auto; min-width:0; font-size:0.8rem; color:var(--color-text-primary); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .recent-x { flex-shrink:0; width:22px; height:22px; border:0; background:transparent; color:var(--color-text-muted); border-radius:6px; cursor:pointer; font-size:16px; line-height:1; }
  .recent-x:hover { background:var(--color-border); color:var(--color-text-primary); }
  .mdrop-item[aria-selected="true"] { color:var(--color-primary-hover); }
  .mdrop-item .mdrop-meta { color:var(--color-text-muted); font-size:0.72rem; white-space:nowrap; }
  /* The band rides the END of the chips row — a line the item already draws — so a banded model is
     exactly as tall as a flat one. Stacking it inside the price block added height to every such row
     for a second fact that had somewhere free to sit. */
  /* Beside the NAME, where the capability belongs — and it leaves the chips row free for brand,
     context and the band, which is what was wrapping on a phone. */
  .mitem-nm { display:inline-flex; align-items:center; gap:7px; min-width:0; overflow:hidden; }
  .chip-mod { gap:5px; flex-shrink:0; }
  .modi { width:13px; height:13px; display:block; flex-shrink:0; }
  .modw { font-size:0.72rem; }
  .mdrop-band { margin-left:auto; color:var(--color-text-muted); font-size:0.72rem; white-space:nowrap; }
  /* The context ring. 18px is the smallest size at which a two-colour split still reads as two
     things rather than one dirty colour; the label inside sits at 7px, which is legible because it
     is 2-4 tabular characters and never wraps. */
  /* 36px. The row already carries ~44px of content (name line + chips line), so the ring grows into
     height the row was spending anyway. ONE size: the collapsed trigger dropped its ring (the context
     chip beside it already said 1M, in the tightest bar on screen), so a size modifier would name a
     distinction that no longer exists. */
  .cwrap { position:relative; display:inline-flex; align-items:center; justify-content:center; width:36px; height:36px; flex-shrink:0; }
  .cring { position:absolute; inset:0; width:100%; height:100%; transform:rotate(-90deg); }
  /* The picker's size: two price lines tall, so the ring costs no row height and the label grows with it. */
  /* ONE width, one hue — the SEGMENTATION carries the band (see ctxRing: a gap at both junctions).
     A second colour would spend the strongest channel available on a two-way distinction, and hue is
     doing real work elsewhere in this list (brand dots, tone chips). A second WIDTH was tried and read
     as a lopsided blob rather than a heavier stroke: at this diameter the thicker arc distorts the
     circle instead of weighting part of it. The price text still goes bold for the upper band, so the
     two encodings agree without either shouting. */
  .cring circle { fill:none; stroke-linecap:butt; stroke-width:2; }
  .cr-a, .cr-b { stroke:color-mix(in srgb, var(--color-primary) 38%, transparent); }
  .cr-u { stroke:var(--color-primary); }
  /* The cached share of the fill. Drawn over it, in the colour the separate bar used to be, because it
     answers the same question in the place that already had the tokens for it: this much of what you
     have used is coming from cache, and is therefore nearly free. */
  .cr-c { stroke:var(--color-success); }
  /* Past the threshold. A SEMANTIC colour, which is a different job from the two bands of the track:
     those are categories and share one hue, this is a state — the tokens beyond this point cost more. */
  .cr-o { stroke:var(--color-warning); }
  /* 12px, normal tracking: the fraction glyphs are wide, and the -0.02em that suits digits pulled the
     M onto the bar of the 1/2. */
  .clab { position:relative; font-size:12px; line-height:1; font-variant-numeric:tabular-nums; color:var(--color-text-muted); letter-spacing:0; }
  .mdrop-item[aria-selected="true"] .mdrop-band { color:var(--color-primary-hover); font-weight:700; }
  .mdrop-note { padding:8px 11px; margin-bottom:2px; font-size:0.72rem; line-height:1.35; color:var(--color-text-muted); background:var(--color-surface); border-radius:8px; }
  .mdrop-item[aria-selected="true"] .mdrop-meta { color:var(--color-primary-hover); }
  pre.code { background:var(--color-background); border:0; border-radius:0; padding:14px; overflow-x:auto; margin:0; }
  pre.code code { font-family:var(--font-mono); font-size:0.78rem; white-space:pre; color:#cfe3f5; line-height:1.55; }
  /* rendered "How to use" markdown */
  .md { padding:16px 16px 4px; background:var(--color-surface); }
  .md > :first-child { margin-top:0; }
  .md p { font-size:0.82rem; color:var(--color-text-secondary); line-height:1.6; margin:0 0 12px; }
  .md p strong { color:var(--color-text-primary); font-weight:600; }
  .md ol, .md ul { margin:0 0 12px; padding-left:20px; }
  .md li { font-size:0.82rem; color:var(--color-text-secondary); line-height:1.6; margin:3px 0; }
  .md-h { font-weight:600; font-size:0.9rem; color:var(--color-text-primary); margin:0 0 8px; }
  .md code.ic { font-family:var(--font-mono); font-size:0.76rem; background:var(--color-elevated); border:1px solid var(--color-border); border-radius:5px; padding:1px 5px; color:var(--color-text-primary); }
  .cblock { position:relative; margin:0 0 14px; }
  .cblock pre.cb { background:var(--color-background); border:1px solid var(--color-border); border-radius:var(--radius-md); padding:13px 46px 13px 14px; overflow-x:auto; margin:0; }
  .cblock pre.cb code { font-family:var(--font-mono); font-size:0.78rem; white-space:pre; color:#cfe3f5; line-height:1.55; }
  .cbcopy { position:absolute; top:8px; right:8px; display:inline-flex; align-items:center; justify-content:center; width:28px; height:28px; padding:0; border:0; border-radius:7px; background:rgba(255,255,255,0.05); color:var(--color-text-secondary); cursor:pointer; }
  .cbcopy:hover { background:rgba(255,255,255,0.12); color:var(--color-text-primary); }
  .cbcopy.ok { color:var(--color-success); }
  .cbcopy svg { width:15px; height:15px; }
  .md-tablewrap { overflow-x:auto; margin:0 0 12px; }
  .md-table { border-collapse:collapse; width:100%; font-size:0.8rem; }
  .md-table th, .md-table td { border:1px solid var(--color-border); padding:6px 10px; text-align:left; vertical-align:top; line-height:1.5; }
  .md-table th { background:var(--color-elevated); color:var(--color-text-primary); font-weight:600; white-space:nowrap; }
  .md-table td { color:var(--color-text-secondary); }
  .md-table tbody tr:nth-child(even) td { background:var(--color-background); }

  /* ---- Chat tab (Halo: user = elevated tier, model = surface tier, hairline borders) */
  .chatpane { padding:14px 16px; }
  .chatlog { max-height:340px; overflow:auto; overscroll-behavior:contain; -webkit-overflow-scrolling:touch; display:flex; flex-direction:column; gap:12px; margin-bottom:12px; scroll-behavior:smooth; }
  .chat-empty { color:var(--color-text-muted); font-size:var(--text-body-sm-size); text-align:center; padding:26px 8px; }
  .cmsg-row { display:flex; flex-direction:column; gap:12px; }
  .cmsg-day { align-self:center; font-family:var(--font-mono); font-size:0.66rem; color:var(--color-text-muted); background:var(--color-surface); border:1px solid var(--color-border); border-radius:var(--radius-full); padding:2px 12px; }
  .cmsg { display:flex; flex-direction:column; gap:4px; max-width:86%; }
  .cmsg.user { align-self:flex-end; align-items:flex-end; }
  .cmsg.bot { align-self:flex-start; align-items:flex-start; max-width:100%; }

  .cmsg-actions { display:flex; align-items:center; gap:8px; padding:0 2px; }
  .cmsg-time { font-family:var(--font-mono); font-size:0.6875rem; color:var(--color-text-muted); }
  /* per-message header (chat boxes): model dot + name (assistant) + timestamp, above the bubble */
  .cmsg-head { display:flex; align-items:center; gap:7px; padding:0 2px 3px; min-width:0; max-width:100%; }
  .cmsg-model { display:inline-flex; align-items:center; gap:5px; font-family:var(--font-mono); font-size:0.7rem; color:var(--color-text-secondary); min-width:0; }
  .cmsg-model .chdot { width:8px; height:8px; flex-shrink:0; }
  .cmsg-model > span:last-child { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; min-width:0; }
  .cmsg-act { display:inline-flex; align-items:center; justify-content:center; width:22px; height:22px; padding:0; border:0; background:transparent; color:var(--color-text-muted); border-radius:var(--radius-sm); cursor:pointer; transition:background var(--motion-base) var(--easing-standard), color var(--motion-base) var(--easing-standard); }
  .cmsg-act:hover { background:var(--color-elevated); color:var(--color-text-primary); }
  .cmsg-act svg { width:14px; height:14px; }
  .cmsg-bubble { padding:9px 13px; border-radius:var(--radius-lg); font-size:var(--text-body-sm-size); line-height:1.55; word-break:break-word; overflow-wrap:anywhere; min-width:0; max-width:100%; color:var(--color-text-primary); }
  .cmsg-plain { white-space:pre-wrap; }
  .cmsg.user .cmsg-bubble { background:var(--color-elevated); border:1px solid var(--color-border-strong); border-bottom-right-radius:var(--radius-sm); }
  .cmsg.bot .cmsg-bubble { background:transparent; border:0; padding:0; }
  .cmsg-meta { font-family:var(--font-mono); font-size:0.6875rem; color:var(--color-text-muted); }
  .cmsg-think { color:var(--color-text-muted); font-style:italic; font-size:0.74rem; margin-bottom:5px; white-space:pre-wrap; }
  .cmsg-think-wrap { margin-bottom:7px; }
  .cmsg-think-body { position:relative; margin-top:5px; padding:8px 32px 8px 10px; background:var(--color-surface); border:1px solid var(--color-border); border-radius:var(--radius-md); }
  /* reasoning must always be selectable/copyable (users lift it into a Panel-mode message by hand) */
  .cmsg-think-body .cmsg-think { -webkit-user-select:text; user-select:text; -webkit-touch-callout:default; cursor:text; }
  .cmsg-think-body .cmsg-think { margin-bottom:0; }
  .cmsg-think-sig { display:inline-flex; align-items:center; gap:3px; padding:1px 6px; border-radius:var(--radius-full); background:var(--color-success-soft); color:var(--color-success); font-size:0.66rem; font-style:normal; flex-shrink:0; }
  .cmsg-think-sig svg { width:11px; height:11px; }
  .cmsg-think-copy { position:absolute; top:5px; right:5px; }
  .cmsg-tool { margin-bottom:7px; }
  .cmsg-tool-h { display:inline-flex; align-items:center; gap:6px; max-width:100%; padding:4px 9px; background:var(--color-surface); border:1px solid var(--color-border); border-radius:var(--radius-full); color:var(--color-text-secondary); font-size:0.72rem; cursor:pointer; transition:border-color var(--motion-base) var(--easing-standard), color var(--motion-base) var(--easing-standard); }
  .cmsg-tool-h:hover { border-color:var(--color-border-strong); color:var(--color-text-primary); }
  .cmsg-tool-ico { width:13px; height:13px; flex-shrink:0; }
  .cmsg-tool-lbl { flex-shrink:0; }
  .cmsg-tool-name { font-family:var(--font-mono, ui-monospace, monospace); color:var(--color-text-primary); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .cmsg-tool-chev { width:13px; height:13px; flex-shrink:0; transition:transform var(--motion-base) var(--easing-standard); }
  .cmsg-tool-chev.is-open { transform:rotate(180deg); }
  .cmsg-fetch { display:flex; align-items:center; gap:6px; margin:4px 0 6px; font-size:12px; color:var(--color-text-muted); }
  .cmsg-fetch-ico { width:14px; height:14px; flex:none; animation:isl-spin 1.6s linear infinite; }
  .cmsg-tool-args { margin:6px 0 0; padding:8px 10px; background:var(--color-surface); border:1px solid var(--color-border); border-radius:var(--radius-md); font-family:var(--font-mono, ui-monospace, monospace); font-size:0.7rem; line-height:1.5; white-space:pre-wrap; word-break:break-word; overflow-x:auto; color:var(--color-text-secondary); }
  .cmsg-md { padding:0; background:transparent; }
  .cmsg-md > :last-child { margin-bottom:0; }
  .cmsg-md p, .cmsg-md li { color:var(--color-text-primary); font-size:var(--text-body-sm-size); margin-bottom:8px; }
  .cmsg-md ol, .cmsg-md ul { margin:4px 0 8px; }
  .cmsg-md .cblock { margin:6px 0; }
  .cmsg-md .md-tablewrap { margin:6px 0; }
  .cmsg-md .md-table td { color:var(--color-text-primary); }
  /* reply source citations */
  .cmsg-cites { display:flex; flex-direction:column; gap:3px; margin-top:8px; padding-top:7px; border-top:1px solid var(--color-border); }
  .cmsg-cites-h { font-size:0.68rem; text-transform:uppercase; letter-spacing:0.04em; color:var(--color-text-muted); }
  .cmsg-cite { font-size:0.74rem; color:var(--color-text-secondary); text-decoration:none; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-width:100%; }
  .cmsg-cite:hover { color:var(--color-text-primary); text-decoration:underline; }
  .md a, .cmsg-md a { color:var(--color-primary); text-decoration:underline; text-underline-offset:2px; overflow-wrap:anywhere; }
  .md a:hover, .cmsg-md a:hover { color:var(--color-primary-hover); }
  .chat-err { display:flex; align-items:baseline; gap:8px; margin-bottom:10px; padding:8px 12px; border:1px solid var(--color-danger); border-radius:var(--radius-md); background:var(--color-danger-soft); font-size:var(--text-body-sm-size); color:var(--color-text-primary); }
  .chat-err b { color:var(--color-danger); font-weight:600; text-transform:uppercase; font-size:var(--text-label-sm-size); letter-spacing:var(--text-label-sm-tracking); }
  .chat-empty .chip { cursor:pointer; }
  .chatbar { position:relative; }
  /* multiline auto-growing input: 1 line up to ~9 lines, then scrolls; controls sit at the bottom corners */
  .chatbar .chatinput { width:100%; box-sizing:border-box; display:block; resize:none; border-radius:18px; padding:9px 44px 9px 44px; line-height:1.5; min-height:42px; max-height:calc(1.5em * 9 + 18px); overflow-y:auto; }
  /* user-select/touch-callout:none so the send button's long-press/swipe never starts a text selection
     or iOS callout; touch-action:none so a vertical swipe reaches the gesture handler instead of scrolling. */
  .cbtn { position:absolute; bottom:5px; display:inline-flex; align-items:center; justify-content:center; width:32px; height:32px; padding:0; border:0; background:transparent; cursor:pointer; -webkit-user-select:none; user-select:none; -webkit-touch-callout:none; touch-action:none; transition:color var(--motion-base) var(--easing-standard); }
  .cbtn svg { width:19px; height:19px; }
  .cbtn-send { right:8px; color:var(--color-primary); }
  .cbtn-send:hover:not(:disabled) { color:var(--color-primary-hover); }
  .cbtn-send:disabled { opacity:.35; cursor:default; }
  /* style-disabled (empty draft) but NOT attribute-disabled, so the long-press still fires */
  .cbtn-send.is-off { opacity:.35; }
  .cbtn-stop { right:8px; color:var(--color-text-secondary); }
  /* compose hub: a floating popup MENU (like the model-dot menu) that opens ABOVE the input on
     long-press / swipe of the send triangle. Vertical rows — icon (left) + label (right) — with
     separators dividing the action groups (add file · export/import · clear). Overlay = no layout shift. */
  .compose-hub { position:absolute; right:0; bottom:calc(100% + 8px); min-width:186px; display:flex; flex-direction:column; gap:1px; background:var(--color-elevated); border:1px solid var(--color-border-strong); border-radius:var(--radius-md); box-shadow:var(--shadow-lg); padding:5px; z-index:30; }
  /* The compose bar's dashboard. A readout, not a control: no hover state, no pointer. It leads the menu
   because "what will this cost" is the question you opened it with. */
.hub-stat { width:100%; padding:8px 9px 9px; margin-bottom:3px; border-bottom:1px solid var(--color-border); display:flex; flex-direction:column; gap:5px; }
.hs-top { display:flex; align-items:center; gap:10px; }
.hs-main { display:flex; flex-direction:column; gap:1px; min-width:0; flex:1; }
.hs-row { display:flex; align-items:center; gap:8px; font-size:0.73rem; line-height:1.3; }
.hs-k { color:var(--color-text-muted); flex-shrink:0; }
.hs-v { color:var(--color-text-secondary); font-variant-numeric:tabular-nums; margin-left:auto; white-space:nowrap; }
.hs-money { color:var(--color-primary-hover); font-weight:600; }
/* A floor is not an exact figure and should not read as one. Same size as its neighbours - the three
   rows are peers - but stepped back a shade so >= carries visually as well as literally. */
.hs-money[data-partial="1"] { color:var(--color-text-secondary); font-weight:500; }
.hs-muted .hs-v, .hs-muted .hs-k { color:var(--color-text-muted); }
/* The band as a STATE rather than a sentence: it takes the warning colour when the higher rate applies,
   the same colour the ring's overage arc uses, so picture and text agree without a legend. */
.hs-band { font-size:0.68rem; line-height:1.3; color:var(--color-text-muted); }
.hs-band[data-over="1"] { color:var(--color-warning); font-weight:600; }
/* THE CONTEXT BAR. Segments stack the way the tokens do — cached, then fresh, then what is left — and
   the band threshold is a TICK at a position you can read against the fill, which is the thing an arc
   could only imply. The fill takes the warning colour once it is past that tick, so the bar and the
   rate below it say the same thing. */
.cbar { position:relative; display:flex; height:7px; border-radius:4px; overflow:hidden;
  background:color-mix(in srgb, var(--color-text-muted) 22%, transparent); }
.cbar i { display:block; height:100%; }
.cb-c { background:var(--color-success); }
.cb-f { background:var(--color-primary); }
.cb-o { background:var(--color-warning); }
.cb-tick { position:absolute; top:-2px; bottom:-2px; width:2px; border-radius:1px;
  background:color-mix(in srgb, var(--color-text-primary) 55%, transparent); }
/* The legend only names what is actually drawn: no cache reads yet, no cache swatch. */
.cb-leg { display:flex; gap:11px; flex-wrap:wrap; font-size:0.63rem; color:var(--color-text-muted); margin-top:-1px; }
.cb-leg span { display:inline-flex; align-items:center; gap:4px; }
.cb-leg i { width:7px; height:7px; border-radius:2px; flex-shrink:0; }
.cb-tick-k { background:color-mix(in srgb, var(--color-text-primary) 55%, transparent); width:2px !important; height:9px !important; border-radius:1px; }
.hs-rate { font-variant-numeric:tabular-nums; font-weight:600; }
.hs-rate[data-over="1"] { color:var(--color-warning); }
.hs-rate[data-free="1"] { color:var(--color-success); }
.hub-item { display:flex; align-items:center; gap:10px; width:100%; padding:7px 9px; border:0; border-radius:var(--radius-sm); background:transparent; color:var(--color-text-secondary); font-size:0.8rem; line-height:1.1; text-align:left; cursor:pointer; transition:background var(--motion-base) var(--easing-standard), color var(--motion-base) var(--easing-standard); }
  @media (hover: hover) { .hub-item:hover { background:var(--color-surface); color:var(--color-text-primary); } }
  .hub-item svg { width:16px; height:16px; flex:none; }
  .hub-item span { flex:1; }
  .hub-item .bx-sw { flex:none; }   /* the toggle switch must keep its own width, not stretch to fill the row */
  .hub-sep { height:1px; margin:4px 7px; background:var(--color-border); }   /* still used by the island kebab menu */
  .hub-danger:hover { color:var(--color-danger); }
  /* two side-by-side manage groups — [move · copy] and [clear · delete]. No group box or pill:
     the grouping is purely the horizontal row (paired instead of stacked full-width), and each
     button keeps its OWN per-button hover bg (the default .hub-item:hover), like the rows above. */
  .hub-row { display:flex; gap:1px; margin-top:4px; }
  .hub-row .hub-item { flex:1; width:auto; }
  /* attachment chips, persistent above the input while files are pending */
  /* attachment chips = square thumbnail tiles: image preview, or a file-type tile (e.g. "pdf");
     filename on hover (title), a corner × to remove (hover on desktop, always shown on touch). */
  .att-row { display:flex; flex-wrap:wrap; gap:8px; padding:8px 2px 2px; }
  .att-chip { position:relative; width:58px; height:58px; flex:none; border-radius:10px; overflow:hidden; background:var(--color-surface); border:1px solid var(--color-border); }
  .att-thumb { width:100%; height:100%; object-fit:cover; display:block; }
  /* generated images in an assistant reply (image models) — a wrapping row so multiple providers' results
     sit side by side to compare; each captioned with its model. */
  .cmsg-gen { display:flex; flex-wrap:wrap; align-items:flex-start; gap:10px; margin:2px 0 6px; }
  .cmsg-genfig { margin:0; display:flex; flex-direction:column; gap:4px; max-width:100%; min-width:0; }
  .cmsg-gen-img { max-width:100%; width:auto; max-height:380px; border-radius:var(--radius-md); border:1px solid var(--color-border); display:block; }
  .cmsg-gencap { font-size:0.72rem; color:var(--color-text-muted); text-align:center; }
  /* reference image(s) the model generated FROM (image-to-image) — shown above the result so the user can see
     what was actually used; the label turns red when a regen dropped an available reference (genRefLost). */
  .cmsg-ref { display:flex; flex-wrap:wrap; align-items:center; gap:6px; margin:0 0 6px; }
  .cmsg-ref-h { flex:none; font-size:0.72rem; color:var(--color-text-muted); }
  .cmsg-ref-h.cmsg-ref-lost { color:var(--color-danger); }
  .cmsg-ref-img { width:44px; height:44px; object-fit:cover; border-radius:var(--radius-sm); border:1px solid var(--color-border); display:block; }
  .cmsg-generr { display:flex; flex-direction:column; gap:2px; padding:8px 10px; border-radius:var(--radius-md); background:var(--color-danger-soft); color:var(--color-danger); font-size:0.78rem; max-width:100%; }
  .cmsg-generr-m { font-weight:600; }
  .cmsg-genretry { margin-top:6px; align-self:flex-start; }
  .cmsg-genload { width:180px; height:140px; max-width:100%; border-radius:var(--radius-md); border:1px solid var(--color-border); background:var(--color-surface); display:flex; flex-direction:column; align-items:center; justify-content:center; gap:12px; padding:0 16px; }
  .cmsg-genbar-label { font-size:0.72rem; color:var(--color-text-muted); }
  .cmsg-genbar { width:100%; height:6px; border-radius:var(--radius-full); background:var(--color-border); overflow:hidden; }
  .cmsg-genbar-fill { height:100%; min-width:5%; border-radius:var(--radius-full); background:linear-gradient(90deg, var(--color-primary), rgba(255,255,255,.45), var(--color-primary)); background-size:200% 100%; transition:width .9s linear; animation:cmsgGenShimmer 1.3s linear infinite; }
  @keyframes cmsgGenShimmer { from { background-position:200% 0; } to { background-position:0 0; } }
  .att-file { display:flex; width:100%; height:100%; align-items:center; justify-content:center; background:var(--color-elevated); color:var(--color-text-secondary); font-size:0.66rem; font-weight:600; text-transform:uppercase; letter-spacing:.05em; }
  .att-x { position:absolute; top:3px; right:3px; width:18px; height:18px; padding:0; border:0; border-radius:50%; background:rgba(10,11,15,.6); color:#fff; cursor:pointer; font-size:13px; line-height:1; display:flex; align-items:center; justify-content:center; opacity:0; transition:opacity var(--motion-base) var(--easing-standard); }
  .att-chip:hover .att-x, .att-x:focus-visible { opacity:1; }
  @media (hover: none) { .att-x { opacity:1; } }
  .msg-att { display:flex; flex-wrap:wrap; gap:8px; margin-bottom:8px; }
  .cbtn-stop:hover { color:var(--color-danger); }
  /* ---- Chat island: stacked independent model-chat boxes opened from the launcher ---- */
  .chatisland { display:flex; flex-direction:column; gap:14px; margin-top:16px; }
  /* chat island grouping (stage 4a): type-islands (Working/Selling/Shared/Bought) + tree-islands. Monochrome
     — a header strip + spacing separate the groups; no per-item color frames (they'd cost width + add noise). */
  /* The base .island panel now comes from @utf/halo (it was distilled FROM this portal — computed-identical:
     halo uses border:var(--border-width), which tokens.css pins to 1px and no theme overrides).
     We keep only the portal's deltas: a 3-column head (grip + title + tools) at chat-list density, and
     border-bottom:0 because the divider here is OWNED by .island-body's border-top (a folded island shows
     no stray line), overriding the halo island-head's built-in border-bottom. */
  .island-head { display:grid; grid-template-columns:auto 1fr auto; align-items:center; gap:6px; min-height:30px; padding:6px 10px; border-bottom:0; }
  /* Reorder feedback is a live "make space" push: the dragged item follows the finger (lifted, inline transform) and
     its peers slide to open a gap. Items animate their transform; the dragged one + the just-committed frame don't. */
  .island { transition:transform 0.18s var(--easing-standard); }
  .chatisland.reordering .island { overflow:visible; }   /* don't clip the lifted box + its shadow while dragging */
  .chatisland.committing .island, .chatisland.committing .chatbox { transition:none; }
  .isl-lead { display:inline-flex; align-items:center; gap:2px; }
  .isl-grip { display:inline-flex; align-items:center; justify-content:center; width:18px; height:26px; color:var(--color-text-muted); opacity:0.55; cursor:grab; }
  .isl-grip:active { cursor:grabbing; }
  .isl-grip svg { width:15px; height:15px; }
  .island-head:hover .isl-grip { opacity:0.9; }
  .isl-add { display:inline-flex; align-items:center; justify-content:center; width:26px; height:26px; padding:0; border:0; border-radius:var(--radius-sm); background:transparent; color:var(--color-text-muted); cursor:pointer; transition:background var(--motion-base) var(--easing-standard), color var(--motion-base) var(--easing-standard); }
  @media (hover: hover) { .isl-add:hover { background:var(--color-elevated); color:var(--color-primary); } }
  .isl-add svg { width:17px; height:17px; }
  .isl-add.is-syncing { color:var(--color-primary); cursor:default; }
  .isl-add.is-syncing svg { animation:isl-spin 0.8s linear infinite; }
  @keyframes isl-spin { to { transform:rotate(360deg); } }
  .isl-name { justify-self:center; display:inline-flex; align-items:center; gap:6px; min-width:0; color:var(--color-text-secondary); font-family:var(--font-display); font-weight:600; font-size:0.85rem; }
  .isl-title { white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-width:14rem; }
  /* custom-folder name is inline-editable (click to rename); styled to look like the title text until focused */
  .isl-title-input { field-sizing:content; min-width:3rem; max-width:14rem; text-align:center; border:0; background:transparent; color:var(--color-text-secondary); font-family:var(--font-display); font-weight:600; font-size:0.85rem; padding:2px 5px; border-radius:var(--radius-sm); cursor:text; -webkit-user-select:text; user-select:text; }
  .isl-title-input:hover { background:var(--color-elevated); }
  .isl-title-input:focus { outline:none; background:var(--color-elevated); color:var(--color-text-primary); }
  .isl-count { color:var(--color-text-muted); font-weight:500; font-variant-numeric:tabular-nums; }
  .isl-tree { display:inline-flex; color:var(--color-text-muted); }
  .isl-tree svg { width:14px; height:14px; }
  .isl-sale { display:inline-flex; align-items:center; gap:3px; color:var(--color-success); font-weight:600; font-size:0.78rem; white-space:nowrap; }
  .isl-tools { display:inline-flex; align-items:center; gap:2px; justify-self:end; }
  .isl-fold { display:inline-flex; align-items:center; justify-content:center; width:24px; height:24px; padding:0; border:0; background:transparent; color:var(--color-text-muted); cursor:pointer; transition:color var(--motion-base) var(--easing-standard); }
  .isl-fold:hover { color:var(--color-text-primary); }
  .isl-fold svg { width:16px; height:16px; }
  .isl-menu { position:relative; display:inline-flex; }
  .isl-kebab { display:inline-flex; align-items:center; justify-content:center; width:24px; height:24px; padding:0; border:0; background:transparent; color:var(--color-text-muted); cursor:pointer; border-radius:var(--radius-sm); transition:background var(--motion-base) var(--easing-standard), color var(--motion-base) var(--easing-standard); }
  .isl-kebab:hover { background:var(--color-elevated); color:var(--color-text-primary); }
  .isl-kebab svg { width:16px; height:16px; }
  .isl-menu-pop { position:absolute; right:0; top:calc(100% + 4px); min-width:160px; display:flex; flex-direction:column; background:var(--color-elevated); border:1px solid var(--color-border-strong); border-radius:var(--radius-md); box-shadow:var(--shadow-lg); padding:4px; z-index:30; }
  .island-body { display:flex; flex-direction:column; gap:10px; padding:10px; border-top:1px solid var(--color-border); }
  .isl-empty { padding:14px 6px; text-align:center; font-size:0.78rem; color:var(--color-text-muted); }
  /* Cap notice: a ghost of the chat box that WOULD have appeared — dashed placeholder at the island top. */
  .isl-capnote { padding:16px 12px; text-align:center; font-size:0.8rem; color:var(--color-text-secondary); border:1px dashed var(--color-border-strong); border-radius:var(--radius-md); background:var(--color-primary-soft); cursor:pointer; }
  /* Share-import progress: a ghost box where the incoming chat will appear — bar + phase label below. */
  .isl-prog { padding:14px 12px; border:1px dashed var(--color-border-strong); border-radius:var(--radius-md); background:var(--color-primary-soft); }
  .isl-progbar { height:6px; border-radius:3px; background:var(--color-elevated); overflow:hidden; }
  .isl-progfill { height:100%; border-radius:3px; background:var(--color-primary); transition:width 0.2s var(--easing-standard); }
  .isl-progfill.is-indet { animation:isl-indet 1.2s ease-in-out infinite; }
  @keyframes isl-indet { 0%, 100% { opacity:1; } 50% { opacity:0.45; } }
  .isl-proglabel { margin-top:8px; text-align:center; font-size:0.78rem; color:var(--color-text-secondary); }
  /* In-place pinch zoom: the actively-pinched image floats above its neighbours while scaled. */
  .cmsg-pinching { position:relative; z-index:60; will-change:transform; }
  /* ---- Reseller hidden side (phase 0) ---- */
  /* You-are-here cue: the LOGO MARK (the bolt) turns gold while inside — the ★ that opens the mode is
     the same gold, so the color already means "reseller". The "OpenToken" TEXT keeps its normal color.
     Tapping the brand exits back to normal use. */
  .brand.is-rsl svg { color:var(--color-warning); }
  .rslwrap { display:flex; flex-direction:column; gap:14px; }
  /* Account status lives as PILLS in the Overview island-head (operator: a whole card for
     id/Active/2FA wasted space) — the id pill ellipsizes so the row survives 375px. */
  .rsl-sp { display:inline-flex; align-items:center; padding:1px 8px; border-radius:999px; font-size:0.66rem; font-weight:600; line-height:1.4; }   /* own line-height: pills must survive line-height:0 hosts */
  .rsl-sp.is-ok { background:var(--color-success-soft); color:var(--color-success); }
  .rsl-sp.is-bad { background:var(--color-danger-soft); color:var(--color-danger); }
  .rsl-sp.is-info { background:var(--color-info-soft); color:var(--color-info); }
  .rsl-headpills { display:flex; align-items:center; gap:4px; min-width:0; flex-wrap:wrap; justify-self:start; }
  .rsl-sp.is-id { background:var(--color-surface); border:1px solid var(--color-border); color:var(--color-text-secondary); max-width:38vw; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; display:inline-block; }
  .rsl-sp.is-mut { background:var(--color-surface); color:var(--color-text-muted); }
  /* Wallet-link affordance on the supply card: LIT (gold) once a deposit wallet is linked, DIM when
     none — tap opens the deposit-wallet modal. */
  /* Supply-card controls: the gold wallet GLYPH is the button into the deposit-wallet modal; the
     compact money line reads "balance | remintable"; key icon top right, voucher toggle bottom right. */
  .rsl-ticobtn { cursor:pointer; border:none; padding:0; }
  @media (hover: hover) { .rsl-ticobtn:hover { filter:brightness(1.12); } }
  .rsl-wmoney { display:flex; align-items:baseline; gap:7px; font-variant-numeric:tabular-nums; white-space:nowrap; }
  .rsl-wm-b { font-size:1.05rem; font-weight:700; color:var(--color-text-primary); }
  .rsl-wm-sep { color:var(--color-border-strong); }
  .rsl-wm-r { font-size:1.05rem; font-weight:700; color:var(--color-success); }
  /* Two-row grid: [glyph spans 2] [label / money] [key / voucher] — each icon shares its row's
     vertical center with the text beside it. */
  .rsl-wtop.rsl-wgrid { display:grid; grid-template-columns:auto 1fr auto; align-items:center; column-gap:10px; row-gap:2px; }
  .rsl-wgrid > .rsl-tico { grid-row:1 / span 2; }   /* the card glyph anchors BOTH rows (wallet button or plain span) */
  .rsl-wgrid .rsl-keysbtn, .rsl-wgrid .rsl-vchbtn, .rsl-wgrid .rsl-custbtn, .rsl-wgrid .rsl-usebtn { justify-self:end; }
  /* Pricing modal: threshold block + per-model margin rows (effective recomputes live) */
  .rsl-thresh { position:relative; margin-bottom:12px; }
  .rsl-thloc-name { position:relative; display:inline-flex; align-items:center; gap:4px; min-width:0; }
  .rsl-tipop.at-left { left:0; transform:none; }
  .rsl-tipop { white-space:pre-line; }
  .rsl-thresh-in { flex:none; display:inline-flex; align-items:center; gap:2px; border:1px solid var(--color-border-strong); border-radius:var(--radius-sm); padding:3px 7px; }
  .rsl-thresh-dollar { color:var(--color-text-muted); font-size:0.82rem; }
  /* Uniform prefix/suffix slots so the threshold box ($ … pad) and a margin box (+ … %) are the
     same width and their inputs line up as a column. */
  .rsl-affix { flex:none; text-align:center; }
  .rsl-thresh-dollar.rsl-affix, .rsl-price-plus.rsl-affix { width:11px; }
  .rsl-price-pct.rsl-affix { width:12px; }
  .rsl-thresh-input { background:none; border:none; outline:none; width:46px; text-align:right; font-size:0.85rem; color:var(--color-text-primary); }   /* match the margin % input width */
  .rsl-linkbtn { align-self:flex-start; background:none; border:none; padding:0; color:var(--color-primary); font-size:0.72rem; cursor:pointer; text-decoration:underline; }
  .rsl-price-list { display:flex; flex-direction:column; gap:6px; max-height:46vh; overflow-y:auto; }
  .rsl-price-row { display:flex; align-items:center; justify-content:space-between; gap:10px; padding:8px 10px; background:var(--color-surface); border:1px solid var(--color-border); border-radius:var(--radius-sm); }
  .rsl-price-main { min-width:0; display:flex; flex-direction:column; gap:2px; }
  .rsl-price-name { font-size:0.82rem; font-weight:600; color:var(--color-text-primary); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .rsl-price-nums { font-size:0.7rem; color:var(--color-text-muted); display:inline-flex; align-items:baseline; gap:5px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  /* Two-margin model row: [name  …  in/out/cache prices] on ONE line, then the two % inputs. */
  .rsl-price-2 { flex-direction:column; align-items:stretch; gap:8px; }
  .rsl-price-top { display:flex; align-items:baseline; justify-content:space-between; gap:10px; min-width:0; }
  .rsl-price-top .rsl-price-name { min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .rsl-price-top .rsl-price-nums { flex:none; }
  .rsl-price-inputs { display:flex; align-items:center; gap:10px; justify-content:space-between; }
  .rsl-price-mlabel { font-size:0.72rem; color:var(--color-text-secondary); white-space:nowrap; }
  .rsl-price-margs { display:inline-flex; align-items:center; gap:6px; }
  .rsl-price-dot { color:var(--color-text-muted); }
  .rsl-price-marg { flex:none; display:inline-flex; align-items:center; gap:2px; border:1px solid var(--color-border-strong); border-radius:var(--radius-sm); padding:3px 7px; }
  .rsl-price-plus { color:var(--color-text-muted); font-size:0.85rem; }
  .rsl-price-input { background:none; border:none; outline:none; width:46px; text-align:right; font-size:0.85rem; color:var(--color-text-primary); }
  .rsl-price-pct { color:var(--color-text-muted); font-size:0.78rem; }
  .rsl-price-save { width:100%; margin-top:14px; }
  .rsl-fpills { display:flex; gap:6px; margin:2px 0 10px; }
  .rsl-fpill { border:1px solid var(--color-border-strong); background:var(--color-surface); border-radius:999px; padding:3px 12px; font-size:0.72rem; font-weight:600; color:var(--color-text-secondary); cursor:pointer; }
  .rsl-fpill.is-on { color:var(--color-primary); border-color:var(--color-primary); background:var(--color-primary-soft); }
  /* Calendar heatmap (ported from the admin provider card's daily-load grid) */
  .rsl-calwrap { display:flex; flex-direction:column; gap:8px; margin-top:12px; }
  .rsl-caltop { display:flex; align-items:center; justify-content:space-between; gap:10px; }
  .rsl-callegend { display:inline-flex; align-items:center; gap:4px; font-size:0.66rem; color:var(--color-text-muted); }
  .rsl-callegend .hc { width:11px; height:11px; }
  .rsl-cal { display:grid; grid-template-columns:repeat(12,1fr); grid-template-rows:repeat(7,auto); grid-auto-flow:column; gap:2px; }
  .hc { width:100%; aspect-ratio:1; border-radius:3px; background:color-mix(in srgb, var(--color-text-primary) 5%, transparent); }
  .hc.l1 { background:color-mix(in srgb, var(--color-primary) 30%, transparent); }
  .hc.l2 { background:color-mix(in srgb, var(--color-primary) 52%, transparent); }
  .hc.l3 { background:color-mix(in srgb, var(--color-primary) 75%, transparent); }
  .hc.l4 { background:color-mix(in srgb, var(--color-primary) 90%, white); }
  .rsl-cal .hc { cursor:pointer; }
  .rsl-cal .hc.on { outline:2px solid var(--color-primary); outline-offset:1px; }
  .rsl-calsel { display:flex; align-items:center; justify-content:space-between; padding:6px 9px; background:var(--color-surface); border:1px solid var(--color-border); border-radius:var(--radius-sm); font-size:0.78rem; }
  .rsl-useday { color:var(--color-text-secondary); }
  .rsl-useval { font-variant-numeric:tabular-nums; font-weight:600; }
  .rsl-vchx { display:flex; flex-direction:column; gap:6px; }
  .rsl-mintrow { display:flex; align-items:center; justify-content:center; gap:6px; padding:8px; border:1px dashed var(--color-border-strong); border-radius:var(--radius-sm); background:none; color:var(--color-text-secondary); font-size:0.78rem; font-weight:600; cursor:pointer; }
  .rsl-mintrow svg { width:14px; height:14px; }
  .rsl-walstat { display:inline-flex; align-items:center; }
  .rsl-walstat svg { width:16px; height:16px; }
  .rsl-walstat.is-on { color:var(--color-warning); }
  .rsl-walstat.is-off { color:var(--color-text-muted); opacity:0.6; }
  /* Voucher stock: foldable island — chevron rotates open; batch rows reuse the entry-card grammar. */
  .rsl-vch-eye { flex:none; align-self:center; }
  .rsl-code-row { display:flex; align-items:center; gap:8px; padding:7px 9px; background:var(--color-surface); border:1px solid var(--color-border); border-radius:var(--radius-sm); }
  .rsl-code-c { flex:1; min-width:0; font-size:0.78rem; overflow-wrap:anywhere; }
  .rsl-code-d { flex:none; font-size:0.72rem; color:var(--color-text-muted); font-variant-numeric:tabular-nums; }
  .rsl-code-acts { flex:none; display:flex; align-items:center; gap:0; }
  .rsl-code-acts .bx-tool { padding:5px; }
  .rsl-code-acts svg { width:16px; height:16px; }
  .rsl-codes-h { display:inline-flex; align-items:center; gap:6px; min-width:0; }
  .rsl-csvbtn { flex:none; }
  .rsl-csvbtn svg { width:16px; height:16px; }
  .rsl-codes-list { display:flex; flex-direction:column; gap:6px; margin-top:10px; }
  .rsl-mintform { display:flex; flex-direction:column; gap:8px; margin-top:8px; }
  .rsl-mintform label { font-size:0.72rem; font-weight:600; color:var(--color-text-secondary); }
  .rsl-mintrow { display:flex; gap:8px; }
  .rsl-mintrow > * { flex:1; min-width:0; }
  /* WORKFLOW cards (Overview v2): supply loop (wallet+inventory) and demand loop (customers+business).
     Same surface-card family as the entries; internal hairline splits the two related halves. */
  .rsl-wcard, .rsl-ccard { display:flex; flex-direction:column; gap:9px; padding:11px 12px; background:var(--color-surface); border:1px solid var(--color-border); border-radius:var(--radius-md); }
  .rsl-wtop, .rsl-ctop { display:flex; align-items:center; gap:10px; }
  .rsl-wmain { flex:1; min-width:0; display:flex; flex-direction:column; gap:1px; }
  .rsl-wside { flex:none; display:flex; flex-direction:column; align-items:flex-end; gap:1px; }
  .rsl-clabel { font-size:0.66rem; font-weight:600; letter-spacing:0.04em; text-transform:uppercase; color:var(--color-text-muted); }
  .rsl-whero { font-size:1.35rem; font-weight:700; color:var(--color-text-primary); font-variant-numeric:tabular-nums; line-height:1.15; }
  .rsl-wsub { font-size:0.95rem; font-weight:600; color:var(--color-success); font-variant-numeric:tabular-nums; }
  .rsl-cmeta { font-size:0.7rem; font-weight:500; color:var(--color-text-muted); letter-spacing:0; text-transform:none; }
  .rsl-cdiv { height:1px; background:var(--color-border); opacity:0.7; }
  .rsl-wstock { display:flex; align-items:center; gap:8px; }
  .rsl-wstockline { flex:1; min-width:0; display:flex; flex-direction:column; gap:0; }
  .rsl-wstockv { font-size:0.85rem; font-weight:600; color:var(--color-text-secondary); font-variant-numeric:tabular-nums; }
  .rsl-cspark { flex:none; display:flex; flex-direction:column; align-items:flex-end; gap:2px; }
  .rsl-cspark canvas { color:var(--color-info); }
  /* tinted glyph family (shared by cards + today cells) */
  .rsl-tico { flex:none; width:32px; height:32px; display:inline-flex; align-items:center; justify-content:center; border-radius:50%; }
  .rsl-tico svg { width:16px; height:16px; }
  .rsl-tico.sm { width:26px; height:26px; }
  .rsl-tico.sm svg { width:14px; height:14px; }
  .rsl-tico.is-gold { background:var(--color-warning-soft); color:var(--color-warning); }
  .rsl-tico.is-warn { background:var(--color-warning-soft); color:var(--color-warning); }
  .rsl-tico.is-ok { background:var(--color-success-soft); color:var(--color-success); }
  .rsl-tico.is-zap { background:var(--color-info-soft); color:var(--color-info); }
  .rsl-tico.is-info { background:var(--color-info-soft); color:var(--color-info); }
  /* today cells now live INSIDE the demand card — borderless halves */
  .rsl-today { display:grid; grid-template-columns:1fr 1fr; gap:10px; }
  .rsl-today-cell { display:flex; align-items:center; gap:8px; min-width:0; }
  .rsl-today-main { min-width:0; display:flex; flex-direction:column; gap:0; }
  .rsl-today-l { font-size:0.66rem; color:var(--color-text-muted); }
  .rsl-today-v { font-size:0.9rem; font-weight:600; color:var(--color-text-primary); font-variant-numeric:tabular-nums; }
  /* ledger pager: thumb-sized prev/next, indicator between */
  .rsl-pager { display:flex; align-items:center; justify-content:center; gap:14px; padding-top:4px; }
  .rsl-pgbtn { display:inline-flex; align-items:center; justify-content:center; width:40px; height:34px; border:1px solid var(--color-border); border-radius:var(--radius-sm); background:var(--color-surface); color:var(--color-text-secondary); cursor:pointer; }
  .rsl-pgbtn:disabled { opacity:0.4; cursor:default; }
  .rsl-pgbtn svg { width:16px; height:16px; }
  .rsl-pgind { font-size:0.78rem; color:var(--color-text-muted); font-variant-numeric:tabular-nums; min-width:52px; text-align:center; }
  /* Ledger ENTRY CARDS (the UTF.link tables->cards anatomy): [tinted glyph] [main col] [right rail].
     Each entry is its own surface card (no divider-row table styling); the kind lives in the glyph
     tint, freeing the horizontal space a chip used to eat. Hover-elevate on pointer devices only. */
  .rsl-act { display:flex; align-items:center; gap:10px; padding:9px 10px; background:var(--color-surface); border:1px solid var(--color-border); border-radius:var(--radius-md); font-size:0.8rem; }
  @media (hover: hover) { .rsl-act:hover { background:var(--color-elevated); border-color:var(--color-border-strong); } }
  .rsl-act-ico { flex:none; width:32px; height:32px; display:inline-flex; align-items:center; justify-content:center; border-radius:50%; background:var(--color-elevated); color:var(--color-text-muted); }
  .rsl-act-ico svg { width:16px; height:16px; }
  .rsl-act.is-mint .rsl-act-ico { background:var(--color-primary-soft); color:var(--color-primary); }
  .rsl-act.is-topup .rsl-act-ico { background:var(--color-success-soft); color:var(--color-success); }
  .rsl-act.is-void .rsl-act-ico { background:var(--color-danger-soft); color:var(--color-danger); }
  .rsl-act-main { flex:1; min-width:0; display:flex; flex-direction:column; gap:1px; }
  .rsl-act-kind { font-weight:600; font-size:0.8rem; color:var(--color-text-primary); }
  .rsl-act-detail { min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:var(--color-text-muted); font-size:0.72rem; }
  .rsl-act-side { flex:none; display:flex; flex-direction:column; align-items:flex-end; gap:1px; }
  .rsl-act-amt { font-variant-numeric:tabular-nums; font-weight:600; color:var(--color-text-secondary); }
  .rsl-act-amt.is-plus { color:var(--color-success); }
  .rsl-act-amt.is-minus { color:var(--color-danger); }
  .rsl-act-when { font-size:0.68rem; color:var(--color-text-muted); }
  .rsl-err { color:var(--color-danger); font-size:0.8rem; }
  .rsl-coming { color:var(--color-text-muted); font-size:0.75rem; text-align:center; padding:6px 0 2px; }
  /* Wallet island: deposit-address card (address + QR gated behind a link) + linked-wallet rows + add form. */
  .rsl-wal { display:flex; flex-direction:column; gap:11px; padding:11px 12px; background:var(--color-surface); border:1px solid var(--color-border); border-radius:var(--radius-md); }
  .rsl-wal-addr { font-size:0.8rem; color:var(--color-text-secondary); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .rsl-wal-qrwrap { position:relative; align-self:center; display:inline-flex; align-items:center; justify-content:center; }
  /* The QR box keeps its 170px square footprint in BOTH states (154 svg + 8px padding): the gated
     (empty) state is a designed dashed placeholder the reveal hint centers over — an empty inline-flex
     box otherwise collapses to its padding and the absolute overlay wraps one word per line. */
  .rsl-wal-qr { display:inline-flex; align-items:center; justify-content:center; width:170px; height:170px; box-sizing:border-box; line-height:0; background:#fff; padding:8px; border-radius:var(--radius-sm); transition:filter var(--motion-base) var(--easing-standard); }
  .rsl-wal-qr:empty { background:var(--color-surface); border:1px dashed var(--color-border-strong); }
  .rsl-wal-qr svg { width:154px; height:154px; display:block; }
  .rsl-wal-qr.is-blur { filter:blur(7px); }
  .rsl-wal-qr.is-blur:empty { filter:none; }   /* pre-load PLACEHOLDER hides nothing — blur only ever veils real QR content */
  .rsl-wal-info { font-size:0.72rem; color:var(--color-text-muted); line-height:1.55; }
  /* Ported from the original /reseller console wallet card (operator-refined link flow):
     [chain trigger] [mode-swapped heading] [Unlinked chip | change-wallet toggle] over the
     blurred-QR gate with a centered SCAN overlay, then the edit-in-place address + inline code. */
  .rsl-walgrid { display:grid; grid-template-columns:1fr auto 1fr; align-items:center; gap:6px; min-height:28px; }
  .rsl-chainwrap { position:relative; justify-self:start; line-height:0; }
  .rsl-chainbtn { display:inline-flex; align-items:center; gap:3px; background:none; border:none; padding:0; cursor:pointer; line-height:0; color:var(--color-text-muted); }
  /* line-height reset is LOAD-BEARING: the menu lives inside .rsl-chainwrap (line-height:0 for icon
     alignment) — without it the Active/Soon pill's text box collapses and the pill squishes to a
     2px sliver that reads as a stray horizontal line above the label. */
  .rsl-chainmenu { position:absolute; top:calc(100% + 8px); left:0; background:var(--color-elevated); border:1px solid var(--color-border-strong); border-radius:12px; padding:5px; min-width:200px; box-shadow:0 12px 32px rgba(0,0,0,0.35); z-index:30; text-align:left; line-height:1.4; }
  .rsl-chainrow { display:flex; align-items:center; justify-content:space-between; gap:14px; padding:7px 9px; border-radius:8px; }
  .rsl-chainrow.is-soon { opacity:0.55; }
  .rsl-chainname { line-height:1.25; font-size:0.82rem; color:var(--color-text-primary); }
  .rsl-chainassets { display:block; font-size:0.66rem; color:var(--color-text-muted); }
  .rsl-walright { justify-self:end; display:inline-flex; align-items:center; gap:5px; }
  .rsl-walhead { position:relative; display:inline-flex; align-items:center; gap:4px; justify-self:center; line-height:1.3; }
  .rsl-walinfo { display:inline-flex; align-items:center; color:var(--color-text-muted); cursor:pointer; background:none; border:none; padding:0; }
  .rsl-walinfo svg { width:13px; height:13px; }
  .rsl-walinfo.is-on { color:var(--color-text-primary); }
  .rsl-tipop { position:absolute; top:calc(100% + 8px); left:50%; transform:translateX(-50%); width:max-content; max-width:min(280px, 78vw); background:var(--color-elevated); border:1px solid var(--color-border-strong); border-radius:10px; padding:8px 11px; font-size:0.72rem; line-height:1.55; color:var(--color-text-secondary); text-align:left; box-shadow:0 12px 32px rgba(0,0,0,0.35); z-index:30; }
  .rsl-sp.is-warn { background:var(--color-warning-soft); color:var(--color-warning); }
  .rsl-wal-scanbtn { position:absolute; left:50%; top:50%; transform:translate(-50%,-50%); width:46px; height:46px; border-radius:999px; padding:0; box-shadow:0 4px 14px rgba(0,0,0,0.35); }
  .rsl-wal-scanbtn svg { width:20px; height:20px; }
  .rsl-wal-addrline { display:flex; align-items:center; justify-content:center; gap:5px; }
  .rsl-wal-list { display:flex; flex-direction:column; gap:6px; text-align:left; }
  .rsl-act.is-dep .rsl-act-ico { animation: rslDepPulse 1.3s ease-in-out infinite; }
  @keyframes rslDepPulse { 0%, 100% { opacity:1; } 50% { opacity:0.35; } }
  @media (prefers-reduced-motion: reduce) { .rsl-act.is-dep .rsl-act-ico { animation:none; } }
  .rsl-wal-plus svg { transition:transform 0.15s var(--easing-standard); }
  .rsl-wal-plus.is-x svg { transform:rotate(45deg); }   /* + becomes ✕ while a form is open — same button is the way back */
  .rsl-wal-recv { font-size:0.7rem; overflow-wrap:anywhere; }
  .rsl-wal-inwrap { display:flex; align-items:center; justify-content:center; gap:5px; }
  .rsl-wal-in2 { background:none; border:none; outline:none; text-align:center; font-size:0.78rem; color:var(--color-text-primary); max-width:calc(100% - 24px); padding:2px 0; }
  .rsl-wal-chk { display:inline-flex; align-items:center; line-height:0; flex:none; cursor:pointer; }
  .rsl-wal-chk svg { width:14px; height:14px; }
  .rsl-wal-chk[data-st="pen"] { color:var(--color-text-muted); }
  .rsl-wal-chk[data-st="ok"] { color:var(--color-success); }
  .rsl-wal-chk[data-st="bad"] { color:var(--color-danger); }
  .rsl-wal-otp { margin-top:6px; }
  .rsl-scanvid { width:100%; border-radius:10px; background:#000; aspect-ratio:1/1; object-fit:cover; }
  .rsl-wal-form { display:flex; flex-direction:column; gap:8px; }
  .rsl-wal-inrow { display:flex; gap:8px; align-items:center; }
  .rsl-wal-in { flex:1; min-width:0; font-size:0.8rem; }
  .rsl-wal-help { font-size:0.72rem; color:var(--color-text-muted); line-height:1.55; }
  .rsl-key-warn { color:var(--color-warning); }
  .rsl-key-nudge { color:var(--color-danger); font-weight:600; }
  .rsl-keyact { flex:none; color:var(--color-primary); }
  .rsl-keyact svg { width:18px; height:18px; }
  .rsl-wal-unlink { flex:none; align-self:center; background:none; border:1px solid var(--color-border-strong); border-radius:var(--radius-sm); padding:5px 11px; font-size:0.72rem; font-weight:600; color:var(--color-text-secondary); cursor:pointer; }
  @media (hover: hover) { .rsl-wal-unlink:hover { color:var(--color-danger); border-color:var(--color-danger); } }
  /* Segmented OTP [][][]-[][][]: the real input is invisible but stretched over the whole row (taps focus
     it; iOS autofill/paste stay native); segments render its value, the active one gets the primary ring. */
  .otp-wrap { position:relative; display:flex; align-items:center; justify-content:center; gap:7px; margin:2px 0 10px; }
  .otp-wrap.is-busy { opacity:0.55; }
  .otp-real { position:absolute; inset:0; width:100%; height:100%; opacity:0; border:0; padding:0; margin:0; font-size:16px; color:transparent; caret-color:transparent; background:transparent; z-index:1; }
  .otp-seg { width:36px; height:46px; display:inline-flex; align-items:center; justify-content:center; border:1px solid var(--color-border-strong); border-radius:var(--radius-sm); background:var(--color-surface); font-family:var(--font-mono, monospace); font-size:1.25rem; color:var(--color-text-primary); }
  .otp-seg.is-active { border-color:var(--color-primary); box-shadow:0 0 0 2px var(--color-primary-soft); }
  .otp-dash { color:var(--color-text-muted); font-weight:600; }
  .isl-empty-line { display:inline-flex; align-items:center; justify-content:center; gap:5px; flex-wrap:wrap; }
  .isl-empty-ico { width:15px; height:15px; flex-shrink:0; color:var(--color-text-secondary); }
  .howto-toggle { display:flex; align-items:center; width:100%; background:none; border:none; padding:0; cursor:pointer; text-align:left; font:inherit; color:inherit; }
  .howto-chev { width:15px; height:15px; flex-shrink:0; margin-left:auto; color:var(--color-text-muted); transition:transform var(--motion-base) var(--easing-standard); }
  .howto-chev.is-folded { transform:rotate(-90deg); }
  /* chat launcher: an icon button INSIDE the model-picker trigger, just left of the chevron */
  .mdrop-chat { display:inline-flex; align-items:center; justify-content:center; flex-shrink:0; width:28px; height:28px; border-radius:var(--radius-sm); color:var(--color-primary); cursor:pointer; transition:background var(--motion-base) var(--easing-standard), color var(--motion-base) var(--easing-standard); }
  .mdrop-chat:hover { background:var(--color-elevated); color:var(--color-primary-hover); }
  .mdrop-chat svg { width:18px; height:18px; }
  /* per-box data menu: export (Markdown / JSON) or import a JSON chat into the box */
  .bx-dl { position:relative; display:inline-flex; }
  .bx-dlmenu { position:absolute; right:0; top:calc(100% + 6px); min-width:150px; background:var(--color-elevated); border:1px solid var(--color-border-strong); border-radius:var(--radius-md); box-shadow:var(--shadow-lg); padding:4px; z-index:30; }
  .chatbox { border:1px solid var(--color-border); border-radius:var(--radius-lg); background:var(--color-surface); overflow:hidden; }
  /* A dropdown hangs BELOW the header it opens from, so the box's own clip cuts it off — invisibly
     while the box is expanded and tall enough to contain it, and completely once the box is folded to
     header height. Folded is where the menu is most useful and where it vanished entirely.
     Same remedy the island rows already use (.island.iacct.drop-open), same class name: the state is
     the same state, and a second name for it would be a second thing to remember.
     TWO clips to lift now, not one: the swipe wrapper clips so the action circles stay hidden behind
     the row, and the box clips its own rounded corners. A menu has to escape both. */
  .swipe-row.drop-open, .swipe-row.drop-open .chatbox { overflow:visible; }
  /* The chat box brings its own surface and border, so the sliding layer must not paint one over the
     circles it is supposed to be uncovering. (Halo's default suits a row that IS the slide.) */
  .chatbox .swipe-row-slide, .swipe-row > .swipe-row-slide { background:transparent; }
  .chatbox-head { display:flex; align-items:center; gap:8px; padding:7px 8px 7px 8px; border-bottom:1px solid var(--color-border); background:var(--color-elevated); }
  /* per-box drag handle: drop one chatbox onto a sibling in the same island to reorder it */
  .bx-grip { display:inline-flex; align-items:center; justify-content:center; width:16px; height:24px; flex:none; padding:0; color:var(--color-text-muted); opacity:0.5; cursor:grab; }
  .bx-grip:active { cursor:grabbing; }
  .bx-grip svg { width:14px; height:14px; }
  .chatbox-head:hover .bx-grip { opacity:0.85; }
  /* The grip is a drag handle: touch-action:none lets a drag that starts on it reorder instead of scrolling,
     and user-select/touch-callout:none stop a touch press from selecting text or popping the iOS callout. */
  .bx-grip, .isl-grip { touch-action:none; -webkit-user-select:none; user-select:none; -webkit-touch-callout:none; }
  /* While a reorder is in flight, suppress text-selection + callout across the whole island list so sliding the
     finger over box titles / messages can't start a selection (Pointer Events keep firing regardless). */
  .chatisland.reordering, .chatisland.reordering * { -webkit-user-select:none !important; user-select:none !important; -webkit-touch-callout:none !important; }
  /* Selection policy inside the chat islands: ONLY message content + the editable title/compose fields select on
     tap/long-press. Everything else (headers, buttons, labels, counts, grips, tip bar) selects nothing and pops no
     iOS callout. Titles/compose are <input>/<textarea> so they are inherently edit-mode-only. (.reordering above
     additionally kills selection mid-drag.) */
  .chatisland { -webkit-user-select:none; user-select:none; -webkit-touch-callout:none; }
  .chatisland .chatlog, .chatisland input, .chatisland textarea { -webkit-user-select:text; user-select:text; -webkit-touch-callout:default; }
  .chatbox { transition:transform 0.18s var(--easing-standard); }   /* siblings slide to open the gap during a reorder (the dragged box overrides transition:none inline) */
  .chatbox-tools { display:flex; align-items:center; gap:2px; margin-left:auto; flex:none; }
  .bx-tool { display:inline-flex; align-items:center; justify-content:center; width:28px; height:28px; flex:none; padding:0; border:0; background:transparent; color:var(--color-text-muted); border-radius:var(--radius-sm); cursor:pointer; transition:background var(--motion-base) var(--easing-standard), color var(--motion-base) var(--easing-standard); }
  @media (hover: hover) { .bx-tool:hover { background:var(--color-elevated); color:var(--color-text-primary); } }
  .bx-tool svg { width:16px; height:16px; }
  /* web-search state shows as a corner dot (green=on, grey=off) — the globe icon stays monochrome */
  .bx-search { position:relative; }
  .bx-dot { position:absolute; top:3px; right:3px; width:9px; height:9px; box-sizing:border-box; border-radius:50%; background:var(--color-text-muted); border:2px solid var(--color-elevated); transition:background var(--motion-base) var(--easing-standard); }
  .bx-dot.on { background:var(--color-success); }
  /* per-box Tools menu (web search + image gen, extensible) — opened from the globe; the dot still indicates search */
  .bx-toolwrap { position:relative; display:inline-flex; }
  .bx-toolmenu { position:absolute; left:0; top:calc(100% + 6px); min-width:248px; display:flex; flex-direction:column; gap:2px; background:var(--color-elevated); border:1px solid var(--color-border-strong); border-radius:var(--radius-md); box-shadow:var(--shadow-lg); padding:6px; z-index:30; }
  .bx-toolmenu-h { font-size:0.7rem; font-weight:600; text-transform:uppercase; letter-spacing:.06em; color:var(--color-text-muted); padding:2px 6px 4px; }
  .bx-toolrow { display:flex; align-items:center; gap:10px; width:100%; padding:7px 8px; border:0; background:transparent; border-radius:var(--radius-sm); cursor:pointer; text-align:left; transition:background var(--motion-base) var(--easing-standard); }
  @media (hover: hover) { .bx-toolrow:hover:not(.is-off) { background:var(--color-surface); } }
  .bx-toolrow.is-off { opacity:0.5; cursor:not-allowed; }
  .bx-toolrow-i { display:inline-flex; flex:none; color:var(--color-text-secondary); }
  .bx-toolrow-i svg { width:17px; height:17px; }
  .bx-toolrow-t { display:flex; flex-direction:column; gap:1px; min-width:0; flex:1 1 auto; }
  .bx-toolrow-n { font-size:0.82rem; font-weight:600; color:var(--color-text-primary); }
  .bx-toolrow-s { font-size:0.7rem; color:var(--color-text-muted); white-space:normal; line-height:1.3; }
  .bx-sw { flex:none; position:relative; width:30px; height:18px; border-radius:9px; background:var(--color-border-strong); transition:background var(--motion-base) var(--easing-standard); }
  .bx-sw::after { content:""; position:absolute; top:2px; left:2px; width:14px; height:14px; border-radius:50%; background:#fff; transition:transform var(--motion-base) var(--easing-standard); }
  .bx-sw.on { background:var(--color-success); }
  .bx-sw.on::after { transform:translateX(12px); }
  /* Island menu: a group header (icon + noun) over a row of icon-only verbs. The verbs repeat in both
     groups, so naming them twice in words doubled the menu's height to say nothing new. */
  .hub-head { display:flex; align-items:center; gap:8px; padding:8px 10px 4px; font-size:0.7rem; font-weight:600; letter-spacing:0.04em; text-transform:uppercase; color:var(--color-text-muted); }
  .hub-head svg { width:15px; height:15px; flex:none; }
  .hub-icons { display:flex; gap:4px; padding:0 6px 6px; }
  .hub-icon { flex:1 1 0; display:inline-flex; align-items:center; justify-content:center; height:34px; padding:0; border:0; border-radius:var(--radius-sm); background:transparent; color:var(--color-text-secondary); cursor:pointer; transition:background var(--motion-base) var(--easing-standard), color var(--motion-base) var(--easing-standard); }
  .hub-icon svg { width:17px; height:17px; }
  @media (hover: hover) { .hub-icon:hover:not(:disabled) { background:var(--color-surface); color:var(--color-text-primary); } }
  .hub-icon:disabled { opacity:0.35; cursor:not-allowed; }

  /* Knowledge settings: label-left / control-right rows, so the sheet reads as a short list of
     settings instead of a stack of paragraphs. */
  .kcfg-row { display:flex; align-items:center; gap:12px; width:100%; padding:9px 0; border:0; background:transparent; text-align:left; }
  /* FIXED basis, not auto. With auto, a longer label pushes its own control further right and the
     column goes ragged — measured 108px vs 82px for two rows in the same sheet. 112px clears the
     longest label in both locales, so every control starts on the same line. */
  .kcfg-lab { flex:0 0 112px; font-size:0.82rem; font-weight:600; color:var(--color-text-primary); }
  /* A budget is 1-4 characters. A full-width box for it reads as a text field and wastes the row. */
  .kcfg-num { flex:0 0 84px; width:84px; }
  .kcfg-side { flex:1 1 auto; text-align:right; font-size:0.72rem; color:var(--color-text-muted); }
  .kcfg-ctl { flex:1 1 auto; min-width:0; width:auto; }
  .kcfg-val { text-align:right; font-size:0.82rem; color:var(--color-text-muted); }
  .kcfg-link { cursor:pointer; }
  .kcfg-note { margin:2px 0 8px; font-size:0.72rem; line-height:1.35; color:var(--color-text-muted); }
    .kcfg-warn { color:var(--color-warning); }   /* modifier, not a new component — same note, raised voice */

  /* ---- Knowledge settings: two cards ------------------------------------------------------
     Every token below is Halo. Nothing here re-implements a Halo primitive: the card, chip, toggle
     and dropdown are all Halo classes; what is added is the LOG and the EXPLORER, which Halo has no
     equivalent for. Both are built from tokens only so they can be lifted UP into Halo later, the
     way .island was. */
  .kstack { display:flex; flex-direction:column; gap:var(--space-4); }
  /* The redesign leaned on .tcard-id as if it were an existing primitive. It was not -- it came from
     the review artifact, whose frames carried their own stylesheet. Without it the icon rendered at
     its intrinsic ~80px and the title stacked underneath it. */
  .tcard-id { display:flex; align-items:center; gap:9px; min-width:0; }
  .tcard-id svg { width:17px; height:17px; flex:none; color:var(--color-text-secondary); }
  .tcard-id .card-title { font-size:0.9rem; }

  /* Title row. NO wrap: the folder name is the only variable-length part, so it is the part that
     shrinks. Letting the row break instead would drop the model/language cluster onto line two,
     where it stops reading as a property of the folder named above it. */
  .ktitle { display:flex; align-items:center; justify-content:space-between; gap:8px; flex-wrap:nowrap; }
  .ktitle-l { display:flex; align-items:center; gap:8px; min-width:0; flex:1 1 auto; }
  .ktitle-l .tcard-id { flex:0 1 auto; min-width:0; overflow:hidden; }
  .ktitle-l .card-title { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .ktitle-r { display:flex; align-items:center; gap:8px; flex:none; }
  .klang-note { margin:6px 0 0; }

  /* One cluster: which model writes the knowledge, and in which language. Both answer "how", and
     both are set once per folder rather than per run — so they sit with the folder, not the action. */
  .how { display:inline-flex; align-items:center; gap:6px; flex:none; }
  .how-sep { width:1px; height:11px; background:var(--color-border-strong); flex:none; }
  /* The chat model trigger without its frame: it rides a title row, where a bordered control would
     out-weigh the title itself. */
  .mpick-wrap { position:relative; display:inline-flex; }
  .mpick { display:inline-flex; align-items:center; gap:6px; border:0; background:transparent; padding:0; color:var(--color-text-secondary); font-family:var(--font-mono); font-size:0.76rem; cursor:pointer; white-space:nowrap; }
  .mpick:hover { color:var(--color-text-primary); }
  .mpick-menu { right:0; left:auto; min-width:210px; }
  .mdot { width:7px; height:7px; border-radius:var(--radius-full); flex:none; }
  .mpick.lang { color:var(--color-text-primary); }

  .run-grp { display:inline-flex; align-items:center; gap:6px; flex:none; margin-left:auto; }
  .run-lbl { font-size:0.76rem; font-weight:600; color:var(--color-text-secondary); }
  /* Halo hides .toggle-action while its switch is OFF -- correct for a gear (configure a thing that
     is already running), wrong for RUN NOW, which is exactly what you reach for when auto is off. */
  .run-field > .toggle ~ .toggle-action { opacity:1; pointer-events:auto; }
  .run-field .toggle-action:hover { transform:translateY(-50%) scale(1.15); }
  .run-field .toggle-action:disabled { opacity:0.4; cursor:not-allowed; }
  .run-field .toggle-action svg { width:11px; height:11px; }
  .run-field .ot-spin { width:10px; height:10px; border-width:2px; }

  /* LOG VIEWER. A distillation is neither a conversation (nothing to rewind or fork) nor a terminal
     (nobody typed a command) -- it is a timestamped, read-only record that ACCUMULATES across runs. */
  .log { border:1px solid var(--color-border); border-radius:var(--radius-md); background:var(--color-background); overflow:hidden; margin-top:10px; }
  .log-head { display:flex; align-items:center; gap:8px; padding:7px 10px; background:var(--color-surface); border-bottom:1px solid var(--color-border); }
  .log-title { font-size:0.68rem; font-weight:600; letter-spacing:0.06em; text-transform:uppercase; color:var(--color-text-secondary); }
  .log-body { max-height:190px; overflow-y:auto; overscroll-behavior:contain; padding:6px 0; }
  .log-run + .log-run { border-top:1px solid var(--color-border); margin-top:6px; padding-top:6px; }
  .log-past { opacity:0.55; }
  .log-line { display:flex; gap:10px; padding:2px 12px; font-family:var(--font-mono); font-size:0.68rem; line-height:1.65; }
  .log-t { flex:0 0 52px; color:var(--color-text-muted); font-variant-numeric:tabular-nums; }
  .log-m { color:var(--color-text-secondary); min-width:0; overflow-wrap:anywhere; }
  .log-ok { color:var(--color-success); }
  .log-done { color:var(--color-text-primary); }
  .log-bad { color:var(--color-danger); }
  .log-live { color:var(--color-text-muted); }
  .log-empty { padding:10px 12px; font-size:0.72rem; color:var(--color-text-muted); }
  /* An unattended pass spent money nobody asked for; it must not look identical to one you ran. */
  .log-auto { margin-right:6px; padding:0 4px; border-radius:var(--radius-sm); background:var(--color-surface); color:var(--color-text-muted); font-size:0.6rem; letter-spacing:0.04em; text-transform:uppercase; }

  /* Budget as the log FOOTER: it is the running cost of the thing above it. The meter is what makes
     "about to stop" read at a glance -- hitting the cap halts distillation silently. */
  .log-foot { display:flex; align-items:center; gap:8px; padding:7px 10px; border-top:1px solid var(--color-border); }
  .bud-lbl { font-size:0.68rem; color:var(--color-text-muted); flex:none; }
  .bud-meter { flex:1 1 auto; height:3px; border-radius:var(--radius-full); background:var(--color-border); overflow:hidden; min-width:24px; }
  .bud-fill { display:block; height:100%; border-radius:var(--radius-full); background:var(--color-primary); transition:width var(--motion-base) var(--easing-standard); }
  .bud-fill.is-full { background:var(--color-danger); }
  .bud { font-family:var(--font-mono); font-size:0.74rem; color:var(--color-text-muted); white-space:nowrap; flex:none; }
  .bud-spent { color:var(--color-text-secondary); }
  .bud-of { margin:0 3px; }
  /* Edited in place, no frame -- a bordered input here would read as the row’s main event. */
  .bud-cap { width:3.2em; border:0; border-bottom:1px dashed var(--color-border-strong); background:transparent; color:var(--color-text-primary); font:inherit; padding:0 2px; outline:none; }
  .bud-cap:focus { border-bottom-color:var(--color-primary); }

  /* EXPLORER. A concept id IS its path inside an OKF bundle, so the browser for it is a file tree
     over a document view. Filenames are DATA, so they are mono; the prose in the doc is not. */
  .exp { border:1px solid var(--color-border); border-radius:var(--radius-md); overflow:hidden; background:var(--color-background); margin-top:10px; }
  .exp-head { display:flex; align-items:center; flex-wrap:wrap; gap:3px 0; padding:6px 10px; background:var(--color-surface); border-bottom:1px solid var(--color-border); }
  .exp-path { font-family:var(--font-mono); font-size:0.68rem; color:var(--color-text-secondary); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .exp-sep { color:var(--color-text-muted); margin:0 4px; }
  .exp-n { margin-left:auto; font-family:var(--font-mono); font-size:0.66rem; color:var(--color-text-muted); font-variant-numeric:tabular-nums; }
  .exp-act { display:inline-flex; align-items:center; justify-content:center; width:26px; height:26px; margin-left:6px; padding:0; border:0; border-radius:var(--radius-sm); background:transparent; color:var(--color-text-muted); cursor:pointer; flex:none; }
  .exp-act svg { width:15px; height:15px; }
  .exp-act:hover { background:var(--color-elevated); color:var(--color-text-primary); }
  /* The SUBJECT axis. It sits above the tree because it cuts ACROSS the type directories rather
     than living inside one — filtering by a tag leaves whichever types hold it and drops the rest. */
  .tagbar { display:flex; flex-wrap:wrap; gap:4px; padding:6px 8px; border-bottom:1px solid var(--color-border); background:var(--color-surface); }
  .tagchip { display:inline-flex; align-items:center; gap:4px; padding:2px 8px; border:1px solid var(--color-border); border-radius:var(--radius-full); background:transparent; color:var(--color-text-secondary); font:inherit; font-size:0.66rem; cursor:pointer; }
  .tagchip:hover { border-color:var(--color-border-strong); color:var(--color-text-primary); }
  .tagchip.is-on { border-color:var(--color-primary); background:var(--color-primary-soft); color:var(--color-text-primary); }
  .tagchip-n { font-family:var(--font-mono); font-size:0.6rem; color:var(--color-text-muted); }
  .tagchip-sm { padding:1px 3px 1px 7px; }
  .tagchip-b { border:0; background:transparent; color:inherit; font:inherit; padding:0; cursor:pointer; }
  .tagchip-x { border:0; background:transparent; color:var(--color-text-muted); font:inherit; padding:0 3px; cursor:pointer; }
  .tagchip-x:hover { color:var(--color-danger); }
  .doctags { display:flex; flex-wrap:wrap; align-items:center; gap:4px; margin:0 0 8px; }
  .tagadd { height:22px; width:88px; font-size:0.66rem; padding:0 7px; }
  .exp-tree { padding:6px 0; max-height:208px; overflow-y:auto; overscroll-behavior:contain; border-bottom:1px solid var(--color-border); }
  .exp-dirrow { display:flex; align-items:center; }
  /* A type with nothing in it yet is not an error -- it is the vocabulary showing what the model may
     sort into. Dimmed, not hidden: hiding it would make "add a folder" look like it did nothing. */
  .exp-dirrow.is-empty .exp-dir { color:var(--color-text-muted); }
  .exp-dir { display:flex; align-items:center; gap:5px; flex:1 1 auto; min-width:0; padding:3px 10px; border:0; background:transparent; font-family:var(--font-mono); font-size:0.68rem; color:var(--color-text-secondary); text-align:left; cursor:pointer; }
  .exp-del { display:inline-flex; align-items:center; justify-content:center; width:22px; height:22px; margin-right:6px; padding:0; border:0; border-radius:var(--radius-sm); background:transparent; color:var(--color-text-muted); cursor:pointer; flex:none; }
  .exp-del svg { width:11px; height:11px; }
  .exp-del:hover { background:var(--color-elevated); color:var(--color-danger); }
  .exp-orph { font-size:0.6rem; letter-spacing:0.04em; text-transform:uppercase; color:var(--color-warning); }
  .exp-new { display:flex; flex-wrap:wrap; align-items:center; gap:6px; padding:6px 10px; border-top:1px solid var(--color-border); background:var(--color-surface); }
  .exp-hint { padding:2px 10px 6px 26px; }
  .exp-hint .input { height:28px; font-size:0.7rem; }
  .tplsect { font-size:0.62rem; font-weight:700; letter-spacing:0.06em; text-transform:uppercase; color:var(--color-text-muted); padding:10px 0 4px; }
  .tplsave { display:flex; gap:6px; padding:4px 0 6px; }
  /* A template row carries its own actions, so the row is the container and the label is the button. */
  .tplrow { display:flex; align-items:center; }
  .tplrow-main { flex:1 1 auto; min-width:0; display:block; padding:8px 0; border:0; background:transparent; text-align:left; cursor:pointer; color:var(--color-text-primary); font:inherit; }
  .tplrow-prov { display:block; margin-top:2px; font-size:0.62rem; color:var(--color-text-muted); }
  .tplrow-act { display:inline-flex; align-items:center; justify-content:center; width:24px; height:24px; margin-right:4px; padding:0; border:0; border-radius:var(--radius-sm); background:transparent; color:var(--color-text-muted); cursor:pointer; flex:none; }
  .tplrow-act svg { width:13px; height:13px; }
  .tplrow-act:hover { background:var(--color-elevated); color:var(--color-text-primary); }
  .tplimp { color:var(--color-primary); }
  .tplnote { margin:2px 0 6px; font-size:0.68rem; line-height:1.45; color:var(--color-text-muted); }
  .oprow, .tplsug, .tplempty { display:block; padding:9px 0; }
  .tplsug { color:var(--color-primary); }
  .sheet-new { border:0; padding:4px 0 8px; background:transparent; }
  /* The path row wraps once there are more tags than fit — a filter you cannot see is not a filter. */
  .exp-tags-row { display:flex; flex-wrap:wrap; gap:4px; flex:1 1 auto; min-width:0; margin-left:6px; }
  .tplempty { color:var(--color-text-secondary); }
  .tplempty .tplrow-prov { font-family:var(--font-mono); }
  .tplsug .tplrow-prov { color:var(--color-text-muted); }
  .vocabp { border-top:1px solid var(--color-border); border-bottom:1px solid var(--color-border); margin:4px 0; }
  .vocabp-row { padding:7px 0; }
  .vocabp-mv { border-top:1px solid var(--color-border); margin-top:6px; }
  .vocabp-mvrow { display:flex; align-items:baseline; justify-content:space-between; gap:10px; padding:3px 0; }
  .vocabp-mvt { font-size:0.72rem; color:var(--color-text-secondary); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .vocabp-mvp { font-family:var(--font-mono); font-size:0.64rem; color:var(--color-text-muted); flex:none; }
  .vocabp-mvto { color:var(--color-primary); }
  .refile { position:relative; display:inline-flex; }
  .refile-trig { border:0; cursor:pointer; font:inherit; }
  .refile-menu { left:0; right:auto; min-width:160px; }
  .vocabp-n { display:flex; align-items:center; gap:6px; font-size:0.76rem; font-weight:600; color:var(--color-text-primary); }
  .vocabp-h { font-size:0.68rem; line-height:1.4; color:var(--color-text-secondary); }
  .vocabp-e { font-size:0.64rem; line-height:1.4; color:var(--color-text-muted); font-style:italic; }
  .tplsave .input { height:30px; font-size:0.72rem; min-width:0; }
  /* Starter vocabulary, at the moment a folder is named. Chips rather than a select: four options
     that are compared against each other, not chosen from a list. */
  .tplpick { margin-top:10px; }
  .tplpick-h { font-size:0.68rem; font-weight:600; letter-spacing:0.06em; text-transform:uppercase; color:var(--color-text-muted); margin-bottom:6px; }
  .tplpick-row { display:flex; flex-wrap:wrap; gap:6px; }
  .tplchip { display:inline-flex; align-items:center; gap:6px; padding:5px 10px; border:1px solid var(--color-border); border-radius:var(--radius-full); background:transparent; color:var(--color-text-secondary); font:inherit; font-size:0.76rem; cursor:pointer; }
  .tplchip:hover { border-color:var(--color-border-strong); color:var(--color-text-primary); }
  .tplchip.is-on { border-color:var(--color-primary); background:var(--color-primary-soft); color:var(--color-text-primary); }
  .tplchip-n { font-family:var(--font-mono); font-size:0.66rem; color:var(--color-text-muted); }
  .tplpick-s { margin:6px 0 0; font-family:var(--font-mono); font-size:0.68rem; line-height:1.5; color:var(--color-text-muted); }
  .exp-new-n { flex:0 0 108px; }
  .exp-new-h { flex:1 1 140px; min-width:0; }
  .exp-new .input { height:30px; font-size:0.72rem; }
  .exp-caret svg { width:12px; height:12px; display:block; transition:transform var(--motion-fast) var(--easing-standard); }
  .exp-shut svg { transform:rotate(-90deg); }
  .exp-c { margin-left:auto; color:var(--color-text-muted); font-size:0.64rem; }
  .exp-file { display:flex; align-items:center; gap:6px; width:100%; padding:3px 10px 3px 26px; border:0; background:transparent; color:var(--color-text-muted); font-family:var(--font-mono); font-size:0.68rem; text-align:left; cursor:pointer; }
  .exp-file svg { width:11px; height:11px; flex:none; opacity:0.6; }
  .exp-file:hover { background:var(--color-surface); color:var(--color-text-secondary); }
  .exp-file.is-open { background:var(--color-primary-soft); color:var(--color-primary-hover); }
  .exp-doc { padding:10px 12px; max-height:260px; overflow-y:auto; overscroll-behavior:contain; }
  .exp-doc h4 { margin:0 0 6px; font-size:0.86rem; color:var(--color-text-primary); }
  .exp-doc p { margin:0 0 6px; font-size:0.74rem; line-height:1.55; color:var(--color-text-secondary); }
  .exp-doc .md { font-size:0.74rem; line-height:1.55; color:var(--color-text-secondary); background:transparent; padding:0; }
  .exp-id { font-family:var(--font-mono); font-size:0.64rem; color:var(--color-text-muted); overflow-wrap:anywhere; }
  .exp-tags { display:flex; flex-wrap:wrap; gap:4px; margin:6px 0 8px; }

  /* Provenance. OKF records the SIGNALS, not a verdict -- so the actors and their dates are stated
     as facts and nothing is scored. The one derived thing, the trust TIER, is a level the spec
     itself defines, which is why it alone is allowed to be a toned chip. */
  /* A refused revision is not a footnote: it is the reviewer's queue, so it sits above provenance
     and carries its own actions rather than hiding behind a disclosure. */
  .prop { margin-top:10px; padding-top:8px; border-top:1px solid var(--color-warning); }
  .prop-why { margin:0 0 8px; font-size:0.68rem; line-height:1.45; color:var(--color-text-muted); }
  .prop-item { padding:8px; margin-bottom:6px; border:1px solid var(--color-border); border-radius:var(--radius-sm); background:var(--color-surface); }
  .prop-meta { display:flex; justify-content:space-between; gap:8px; font-family:var(--font-mono); font-size:0.62rem; color:var(--color-text-muted); margin-bottom:5px; }
  .prop-body { font-size:0.72rem; line-height:1.5; color:var(--color-text-secondary); white-space:pre-wrap; overflow-wrap:anywhere; max-height:120px; overflow-y:auto; }
  .prop-acts { display:flex; gap:6px; margin-top:8px; }
  .prov { margin-top:10px; padding-top:8px; border-top:1px solid var(--color-border); }
  .prov-h { font-size:0.6rem; font-weight:600; letter-spacing:0.1em; text-transform:uppercase; color:var(--color-text-muted); margin-bottom:5px; }
  .prov-row { display:flex; align-items:center; gap:6px; padding:2px 0; font-size:0.66rem; color:var(--color-text-muted); }
  .prov-i svg { width:11px; height:11px; display:block; opacity:0.7; }
  .prov-who { font-family:var(--font-mono); color:var(--color-text-secondary); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .prov-what { min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .prov-src .prov-who { color:var(--color-text-muted); }
  .bx-toolrow-info { display:inline-flex; flex:none; color:var(--color-text-muted); pointer-events:auto; }
  .bx-toolrow-info svg { width:16px; height:16px; }
  .tcfg-body { display:flex; flex-direction:column; gap:8px; }
  .tcfg-field { display:flex; align-items:center; justify-content:space-between; gap:12px; }
  .tcfg-label { font-size:0.84rem; font-weight:600; color:var(--color-text-primary); }
  .tcfg-num { width:64px; text-align:center; }
  .tcfg-select { width:auto; min-width:120px; }
  .tcfg-hint { font-size:0.72rem; color:var(--color-text-muted); margin:-2px 0 2px; }
  .tcfg-row { display:flex; align-items:center; justify-content:space-between; gap:12px; font-size:0.82rem; }
  .tcfg-row .bx-sw { cursor:pointer; }
  .tcfg-mrow { display:flex; align-items:center; gap:8px; font-size:0.8rem; padding:3px 0; cursor:pointer; }
  .tcfg-mlbl { color:var(--color-text-primary); }
  .bx-close:hover { background:var(--color-danger-soft); color:var(--color-danger); }
  .bx-clear:hover { color:var(--color-danger); }   /* clear sits right after the chat name (title is content-sized) */
  /* Tier 2 import seal badge — provenance of an imported session log (sealed / modified / unsigned). */
  /* title clear (backspace) — a clear-the-title affordance inside the name field */
  .title-wrap { display:inline-flex; align-items:center; gap:1px; flex:0 1 auto; min-width:0; }   /* min-width:0 lets a long title shrink instead of pushing the badges/tools off the row */
  .title-clear { display:inline-flex; align-items:center; justify-content:center; width:20px; height:20px; padding:0; border:0; background:transparent; color:var(--color-text-muted); cursor:pointer; border-radius:var(--radius-sm); transition:background var(--motion-base) var(--easing-standard), color var(--motion-base) var(--easing-standard); }
  .title-clear:hover { background:var(--color-surface); color:var(--color-text-primary); }
  .title-clear svg { width:13px; height:13px; }
  .seal-badge { display:inline-flex; align-items:center; flex:none; cursor:help; }
  .seal-badge svg { width:15px; height:15px; }
  .seal-sealed { color:var(--color-success); }
  .seal-modified { color:var(--color-danger); }
  .seal-unsigned, .seal-checking { color:var(--color-text-muted); }
  .seal-checking { animation:sealpulse 1.1s ease-in-out infinite; }
  @keyframes sealpulse { 0%,100% { opacity:1; } 50% { opacity:0.35; } }
  .bx-tool:disabled { opacity:0.4; cursor:default; }
  .bx-tool:disabled:hover { background:transparent; color:var(--color-text-muted); }
  /* The chat's own menu. Share used to be a lit/dim icon here; folding it into the menu would have
     lost that at-a-glance "this conversation is PUBLIC" state, so the state moved onto the button as
     the same dot the tools button already uses. */
  .bx-menuwrap { position:relative; display:inline-flex; }
  .bx-menu { position:relative; }
  .bx-hmenu { position:absolute; right:0; top:calc(100% + 5px); z-index:40; min-width:186px;
    background:var(--color-elevated); border:1px solid var(--color-border-strong); border-radius:var(--radius-md);
    box-shadow:var(--shadow-lg); padding:4px; display:flex; flex-direction:column; gap:2px; }
  .bx-hmenu .hub-item { font-size:0.8rem; }
  /* Halo owns the sheet shell (.modal + .modal-box + .modal-bottom). Only what is INSIDE it is
     portal-local, and only the parts Halo has no primitive for. */
  .set-sheet { border-radius:var(--radius-xl,24px) var(--radius-xl,24px) 0 0; border-bottom:0; border-left:0; border-right:0;
    padding-bottom:calc(20px + env(safe-area-inset-bottom, 0px)); }
  .set-head { display:flex; align-items:center; justify-content:space-between; gap:12px; margin-bottom:6px; }
  .set-sect { padding:14px 0; border-top:1px solid var(--color-border); }
  .set-label { font-size:0.78rem; font-weight:600; color:var(--color-text-secondary); margin-bottom:8px; }
  .set-note { font-size:0.76rem; line-height:1.5; color:var(--color-text-muted); margin:6px 0 0; }
  .set-optlabel { font-size:0.82rem; color:var(--color-text-secondary); }
  .set-opts { display:flex; flex-direction:column; gap:8px; }
  .set-opt { display:flex; flex-direction:column; gap:2px; text-align:left; width:100%; cursor:pointer;
    padding:10px 12px; border-radius:var(--radius-md); background:var(--color-surface);
    border:1px solid var(--color-border); color:var(--color-text-primary); }
  .set-opt.is-sel { border-color:var(--color-primary); background:var(--color-primary-soft); }
  .set-optname { font-size:0.86rem; font-weight:600; }
  .set-optsub { font-size:0.74rem; color:var(--color-text-muted); }
  .share-modal-backdrop { position:fixed; inset:0; z-index:60; display:flex; align-items:center; justify-content:center; padding:16px; background:rgba(0,0,0,0.5); }
  .share-modal { width:min(420px,100%); max-height:90vh; overflow:auto; background:var(--color-background); border:1px solid var(--color-border); border-radius:14px; padding:18px; box-shadow:0 12px 40px rgba(0,0,0,0.3); }
  .share-modal-head { display:flex; align-items:center; justify-content:space-between; font-weight:600; font-size:1rem; margin-bottom:14px; }
  /* Bottom sheet on phones. The portal is an installed PWA, so a phone is the primary case, not the
     edge case — a centred dialog puts its controls out of thumb reach. Breakpoint matches Halo's
     .modal-bottom (639.98px) deliberately: same behaviour whichever primitive a surface ends up on.
     overscroll-behavior stops a scroll inside the sheet from chaining to the chat behind it, and the
     safe-area padding clears the home indicator. */
  @media (max-width: 639.98px) {
    .share-modal-backdrop { align-items:flex-end; padding:0; }
    .share-modal {
      width:100%; max-width:100%; max-height:88vh;
      /* Only the TOP corners are ever visible once docked, and they carry the whole 'drawn up from
         the bottom' read — so they take the largest radius in the scale (matches Halo's
         .modal-bottom). The bottom and side borders would land ON the display edge as hairlines and
         fight the phone's own rounded corners, so they come off; the shadow lifts UP over the page
         rather than down onto nothing. */
      border-radius:var(--radius-xl,24px) var(--radius-xl,24px) 0 0;
      border-bottom:0; border-left:0; border-right:0;
      box-shadow:0 -8px 30px rgba(0,0,0,0.4);
      padding-bottom:calc(18px + env(safe-area-inset-bottom));
      overscroll-behavior:contain;
    }
  }
  .share-size { margin:0 0 12px; font-size:0.8rem; text-align:center; font-variant-numeric:tabular-nums; }
  .share-link-row { display:flex; gap:8px; margin-bottom:12px; }
  .share-link-row .input { flex:1; min-width:0; }
  .share-qr { display:flex; justify-content:center; padding:12px; background:#fff; border-radius:10px; width:max-content; max-width:100%; margin:0 auto 12px; }
  .share-note { color:var(--color-text-muted); font-size:0.78rem; line-height:1.5; margin:8px 0 0; }
  /* fork lineage badge — read from box.fork (the structured marker), never the title. short id = sibling link. */
  .fork-badge { display:inline-flex; align-items:center; gap:4px; flex:none; padding:2px 7px; border:1px solid var(--color-border); border-radius:999px; background:transparent; color:var(--color-text-secondary); }
  .fork-badge svg { width:13px; height:13px; }
  .fork-glyph { font-size:0.95rem; line-height:1; letter-spacing:0; }
  .fork-jump { display:inline-flex; align-items:center; justify-content:center; margin-left:1px; padding:0; border:0; background:transparent; color:var(--color-text-muted); cursor:pointer; border-radius:var(--radius-sm); transition:color var(--motion-base) var(--easing-standard); }
  .fork-jump:hover { color:var(--color-text-primary); }
  .chatbox-body { padding:12px; }
  .chatbox-body .chatlog { min-height:160px; max-height:320px; margin-bottom:10px; }
  /* editable chat title (top-left of each box; stays visible when folded so you know what it is) */
  .chatbox-title { flex:0 1 auto; min-width:0; max-width:14rem; field-sizing:content; overflow:hidden; white-space:nowrap; text-overflow:ellipsis; border:0; background:transparent; color:var(--color-text-primary); font-family:var(--font-display); font-size:0.9rem; font-weight:600; padding:4px 6px; border-radius:var(--radius-sm); }
  .chatbox-title::placeholder { color:var(--color-text-muted); font-weight:500; }
  .chatbox-title:focus { outline:none; background:var(--color-elevated); }
  /* model status dot at the input's left end -> opens an upward model menu (switch model mid-chat) */
  .bdot-wrap { position:absolute; left:7px; bottom:6px; -webkit-user-select:none; user-select:none; -webkit-touch-callout:none; touch-action:manipulation; }
  .bdot { position:relative; display:inline-flex; align-items:center; justify-content:center; width:30px; height:30px; padding:0; border:0; border-radius:50%; background:transparent; cursor:pointer; transition:background var(--motion-base) var(--easing-standard); }
  /* The textarea fills the bar and both controls sit ON TOP of it, so a tap a few pixels wide of a
     30px target lands in the input and throws up the keyboard instead. The input already reserves
     44px of padding at each end for exactly these — the TAP AREA just never matched the space. It
     does now: 44px, the usual minimum, entirely inside padding where no text can be. */
  .cbtn::before, .bdot::before { content:''; position:absolute; top:50%; left:50%; transform:translate(-50%, -50%); width:44px; height:44px; }
  .bdot:hover { background:var(--color-elevated); }
  /* The context ring, drawn on the 30px button's edge so the 14px pip keeps the middle. Thinner stroke
   than the picker's: at this diameter the picker's weight would close the gap to the pip. */
/* Sits ON the send button, so pointer-events:none is load-bearing: the button owns a tap, a
   long-press and a swipe, and a decorative overlay must not intercept any of them. */
.bring { position:absolute; inset:0; pointer-events:none; }
.cbtn-send .bring { inset:1px; }
.bring .cring { position:absolute; inset:0; width:100%; height:100%; transform:rotate(-90deg); }
.bring .cring circle { fill:none; stroke-width:1.3; }
.bring .cr-u, .bring .cr-o { stroke-width:1.6; }
.bdot-pip { width:14px; height:14px; border-radius:50%; transition:box-shadow var(--motion-base) var(--easing-standard); }
  .bdot-pulse { animation:bdotpulse 1.7s ease-in-out infinite; }
  @keyframes bdotpulse { 0%,100% { filter:brightness(1); } 50% { filter:brightness(1.35); } }
  /* Breathing, not brightening: bdotpulse already means "effort level 3", and a second meaning on
     the same signal would make neither readable. Scale and opacity also survive any provider colour,
     which brightness does not. A tool-calling turn can run silently for a long time and this is the
     only thing on screen saying it is still alive. */
  @keyframes bdotbreathe { 0%,100% { transform:scale(1); opacity:1; } 50% { transform:scale(1.24); opacity:0.5; } }
  .bdot-pip.is-working { animation:bdotbreathe 1.3s ease-in-out infinite; }
  /* Both at once when a high-effort model is working — one property, so it has to be said together. */
  .bdot-pip.bdot-pulse.is-working { animation:bdotbreathe 1.3s ease-in-out infinite, bdotpulse 1.7s ease-in-out infinite; }
  @media (prefers-reduced-motion: reduce) { .bdot-pip.is-working, .bdot-pip.bdot-pulse.is-working { animation:none; opacity:0.72; } }
  /* ============================================================
     EFFORT SLIDER — 3 states, native <input type=range> + real-div visuals.
       non-max  : recessed channel + --ev progress fill; discrete step dots (always
                  visible, own layer) mark the 4 thumb stops, rightmost = accent.
       max(.is-max): single-accent dot-matrix (random per-dot opacity = twinkle) scrolling
                  right→left, with a fixed left→right brightness gradient; accent label.
     --ev=effortOf/3 drives fill+thumb math; --ethumb=thumb width; --trk=track/thumb height.
     Thumb fills the full track height (no gaps). Theme-aware. Honors reduced-motion.
     ============================================================ */
  .effort-pop {
    --ev: 0;
    --ethumb: 24px;
    --trk: 22px;
    --ch: var(--color-surface);
    --fill: color-mix(in srgb, var(--color-text-primary) 12%, var(--color-surface));
    --dot: rgba(255,255,255,.5);
    --accent: var(--color-primary);
    --eff-grid: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='22' viewBox='0 0 240 22'%3E%3Ccircle cx='0' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.93'/%3E%3Ccircle cx='6' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.2'/%3E%3Ccircle cx='12' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.56'/%3E%3Ccircle cx='18' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.94'/%3E%3Ccircle cx='24' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.33'/%3E%3Ccircle cx='30' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.25'/%3E%3Ccircle cx='36' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.64'/%3E%3Ccircle cx='42' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.59'/%3E%3Ccircle cx='48' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='1'/%3E%3Ccircle cx='54' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.44'/%3E%3Ccircle cx='60' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.2'/%3E%3Ccircle cx='66' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.68'/%3E%3Ccircle cx='72' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.45'/%3E%3Ccircle cx='78' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.39'/%3E%3Ccircle cx='84' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.92'/%3E%3Ccircle cx='90' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.76'/%3E%3Ccircle cx='96' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.91'/%3E%3Ccircle cx='102' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.97'/%3E%3Ccircle cx='108' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.94'/%3E%3Ccircle cx='114' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.92'/%3E%3Ccircle cx='120' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.62'/%3E%3Ccircle cx='126' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.79'/%3E%3Ccircle cx='132' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.83'/%3E%3Ccircle cx='138' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.69'/%3E%3Ccircle cx='144' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.97'/%3E%3Ccircle cx='150' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.94'/%3E%3Ccircle cx='156' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.53'/%3E%3Ccircle cx='162' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.48'/%3E%3Ccircle cx='168' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.93'/%3E%3Ccircle cx='174' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.24'/%3E%3Ccircle cx='180' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.2'/%3E%3Ccircle cx='186' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.94'/%3E%3Ccircle cx='192' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.44'/%3E%3Ccircle cx='198' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.22'/%3E%3Ccircle cx='204' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.82'/%3E%3Ccircle cx='210' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.72'/%3E%3Ccircle cx='216' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.45'/%3E%3Ccircle cx='222' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.69'/%3E%3Ccircle cx='228' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.76'/%3E%3Ccircle cx='234' cy='3.8' r='1.55' fill='%237E8BFF' fill-opacity='0.95'/%3E%3Ccircle cx='3' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.72'/%3E%3Ccircle cx='9' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.7'/%3E%3Ccircle cx='15' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.47'/%3E%3Ccircle cx='21' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.53'/%3E%3Ccircle cx='27' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.24'/%3E%3Ccircle cx='33' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.2'/%3E%3Ccircle cx='39' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.39'/%3E%3Ccircle cx='45' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.52'/%3E%3Ccircle cx='51' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.78'/%3E%3Ccircle cx='57' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.23'/%3E%3Ccircle cx='63' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.68'/%3E%3Ccircle cx='69' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.69'/%3E%3Ccircle cx='75' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.84'/%3E%3Ccircle cx='81' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.22'/%3E%3Ccircle cx='87' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.5'/%3E%3Ccircle cx='93' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.31'/%3E%3Ccircle cx='99' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.74'/%3E%3Ccircle cx='105' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.85'/%3E%3Ccircle cx='111' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.98'/%3E%3Ccircle cx='117' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.19'/%3E%3Ccircle cx='123' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.65'/%3E%3Ccircle cx='129' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.63'/%3E%3Ccircle cx='135' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.44'/%3E%3Ccircle cx='141' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.31'/%3E%3Ccircle cx='147' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.83'/%3E%3Ccircle cx='153' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.36'/%3E%3Ccircle cx='159' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.69'/%3E%3Ccircle cx='165' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.21'/%3E%3Ccircle cx='171' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.4'/%3E%3Ccircle cx='177' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.6'/%3E%3Ccircle cx='183' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.7'/%3E%3Ccircle cx='189' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.71'/%3E%3Ccircle cx='195' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.87'/%3E%3Ccircle cx='201' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.91'/%3E%3Ccircle cx='207' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.25'/%3E%3Ccircle cx='213' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.21'/%3E%3Ccircle cx='219' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.74'/%3E%3Ccircle cx='225' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.89'/%3E%3Ccircle cx='231' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.26'/%3E%3Ccircle cx='237' cy='8.6' r='1.55' fill='%237E8BFF' fill-opacity='0.72'/%3E%3Ccircle cx='0' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.66'/%3E%3Ccircle cx='6' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.19'/%3E%3Ccircle cx='12' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.2'/%3E%3Ccircle cx='18' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.2'/%3E%3Ccircle cx='24' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.53'/%3E%3Ccircle cx='30' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.65'/%3E%3Ccircle cx='36' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.25'/%3E%3Ccircle cx='42' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.92'/%3E%3Ccircle cx='48' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.25'/%3E%3Ccircle cx='54' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.32'/%3E%3Ccircle cx='60' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.28'/%3E%3Ccircle cx='66' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.77'/%3E%3Ccircle cx='72' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.3'/%3E%3Ccircle cx='78' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.23'/%3E%3Ccircle cx='84' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.26'/%3E%3Ccircle cx='90' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.46'/%3E%3Ccircle cx='96' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.47'/%3E%3Ccircle cx='102' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.39'/%3E%3Ccircle cx='108' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.41'/%3E%3Ccircle cx='114' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.92'/%3E%3Ccircle cx='120' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.82'/%3E%3Ccircle cx='126' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.25'/%3E%3Ccircle cx='132' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.82'/%3E%3Ccircle cx='138' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.79'/%3E%3Ccircle cx='144' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.61'/%3E%3Ccircle cx='150' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.74'/%3E%3Ccircle cx='156' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.83'/%3E%3Ccircle cx='162' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.34'/%3E%3Ccircle cx='168' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.3'/%3E%3Ccircle cx='174' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.31'/%3E%3Ccircle cx='180' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.98'/%3E%3Ccircle cx='186' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.83'/%3E%3Ccircle cx='192' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.34'/%3E%3Ccircle cx='198' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.58'/%3E%3Ccircle cx='204' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.85'/%3E%3Ccircle cx='210' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='1'/%3E%3Ccircle cx='216' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.51'/%3E%3Ccircle cx='222' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.19'/%3E%3Ccircle cx='228' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.41'/%3E%3Ccircle cx='234' cy='13.4' r='1.55' fill='%237E8BFF' fill-opacity='0.78'/%3E%3Ccircle cx='3' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.22'/%3E%3Ccircle cx='9' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.33'/%3E%3Ccircle cx='15' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.64'/%3E%3Ccircle cx='21' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.87'/%3E%3Ccircle cx='27' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.18'/%3E%3Ccircle cx='33' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.55'/%3E%3Ccircle cx='39' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.43'/%3E%3Ccircle cx='45' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.39'/%3E%3Ccircle cx='51' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.95'/%3E%3Ccircle cx='57' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.78'/%3E%3Ccircle cx='63' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.69'/%3E%3Ccircle cx='69' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.77'/%3E%3Ccircle cx='75' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.34'/%3E%3Ccircle cx='81' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.78'/%3E%3Ccircle cx='87' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.39'/%3E%3Ccircle cx='93' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.87'/%3E%3Ccircle cx='99' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.2'/%3E%3Ccircle cx='105' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.35'/%3E%3Ccircle cx='111' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.34'/%3E%3Ccircle cx='117' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.19'/%3E%3Ccircle cx='123' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.77'/%3E%3Ccircle cx='129' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.23'/%3E%3Ccircle cx='135' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.81'/%3E%3Ccircle cx='141' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.54'/%3E%3Ccircle cx='147' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.8'/%3E%3Ccircle cx='153' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.49'/%3E%3Ccircle cx='159' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.42'/%3E%3Ccircle cx='165' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.99'/%3E%3Ccircle cx='171' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.37'/%3E%3Ccircle cx='177' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.19'/%3E%3Ccircle cx='183' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.55'/%3E%3Ccircle cx='189' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.65'/%3E%3Ccircle cx='195' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.45'/%3E%3Ccircle cx='201' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.45'/%3E%3Ccircle cx='207' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.88'/%3E%3Ccircle cx='213' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.52'/%3E%3Ccircle cx='219' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.54'/%3E%3Ccircle cx='225' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.51'/%3E%3Ccircle cx='231' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.52'/%3E%3Ccircle cx='237' cy='18.2' r='1.55' fill='%237E8BFF' fill-opacity='0.2'/%3E%3C/svg%3E");
    position:absolute;
    bottom:calc(100% + 8px); left:0;
    background:var(--color-elevated);
    border:1px solid var(--color-border-strong);
    border-radius:var(--radius-md);
    box-shadow:var(--shadow-lg);
    padding:11px 13px 9px;
    width:198px;
    max-width:calc(100vw - 32px);
    z-index:30;
  }
  :root[data-theme="light"] .effort-pop {
    --ch:#F4F6FB;
    --fill: color-mix(in srgb, var(--color-text-primary) 9%, #F4F6FB);
    --dot: rgba(20,22,29,.42);
    --eff-grid: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='22' viewBox='0 0 240 22'%3E%3Ccircle cx='0' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.93'/%3E%3Ccircle cx='6' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.2'/%3E%3Ccircle cx='12' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.56'/%3E%3Ccircle cx='18' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.94'/%3E%3Ccircle cx='24' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.33'/%3E%3Ccircle cx='30' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.25'/%3E%3Ccircle cx='36' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.64'/%3E%3Ccircle cx='42' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.59'/%3E%3Ccircle cx='48' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='1'/%3E%3Ccircle cx='54' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.44'/%3E%3Ccircle cx='60' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.2'/%3E%3Ccircle cx='66' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.68'/%3E%3Ccircle cx='72' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.45'/%3E%3Ccircle cx='78' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.39'/%3E%3Ccircle cx='84' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.92'/%3E%3Ccircle cx='90' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.76'/%3E%3Ccircle cx='96' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.91'/%3E%3Ccircle cx='102' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.97'/%3E%3Ccircle cx='108' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.94'/%3E%3Ccircle cx='114' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.92'/%3E%3Ccircle cx='120' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.62'/%3E%3Ccircle cx='126' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.79'/%3E%3Ccircle cx='132' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.83'/%3E%3Ccircle cx='138' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.69'/%3E%3Ccircle cx='144' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.97'/%3E%3Ccircle cx='150' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.94'/%3E%3Ccircle cx='156' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.53'/%3E%3Ccircle cx='162' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.48'/%3E%3Ccircle cx='168' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.93'/%3E%3Ccircle cx='174' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.24'/%3E%3Ccircle cx='180' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.2'/%3E%3Ccircle cx='186' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.94'/%3E%3Ccircle cx='192' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.44'/%3E%3Ccircle cx='198' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.22'/%3E%3Ccircle cx='204' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.82'/%3E%3Ccircle cx='210' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.72'/%3E%3Ccircle cx='216' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.45'/%3E%3Ccircle cx='222' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.69'/%3E%3Ccircle cx='228' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.76'/%3E%3Ccircle cx='234' cy='3.8' r='1.55' fill='%235B6BFF' fill-opacity='0.95'/%3E%3Ccircle cx='3' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.72'/%3E%3Ccircle cx='9' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.7'/%3E%3Ccircle cx='15' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.47'/%3E%3Ccircle cx='21' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.53'/%3E%3Ccircle cx='27' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.24'/%3E%3Ccircle cx='33' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.2'/%3E%3Ccircle cx='39' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.39'/%3E%3Ccircle cx='45' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.52'/%3E%3Ccircle cx='51' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.78'/%3E%3Ccircle cx='57' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.23'/%3E%3Ccircle cx='63' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.68'/%3E%3Ccircle cx='69' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.69'/%3E%3Ccircle cx='75' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.84'/%3E%3Ccircle cx='81' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.22'/%3E%3Ccircle cx='87' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.5'/%3E%3Ccircle cx='93' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.31'/%3E%3Ccircle cx='99' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.74'/%3E%3Ccircle cx='105' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.85'/%3E%3Ccircle cx='111' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.98'/%3E%3Ccircle cx='117' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.19'/%3E%3Ccircle cx='123' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.65'/%3E%3Ccircle cx='129' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.63'/%3E%3Ccircle cx='135' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.44'/%3E%3Ccircle cx='141' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.31'/%3E%3Ccircle cx='147' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.83'/%3E%3Ccircle cx='153' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.36'/%3E%3Ccircle cx='159' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.69'/%3E%3Ccircle cx='165' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.21'/%3E%3Ccircle cx='171' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.4'/%3E%3Ccircle cx='177' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.6'/%3E%3Ccircle cx='183' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.7'/%3E%3Ccircle cx='189' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.71'/%3E%3Ccircle cx='195' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.87'/%3E%3Ccircle cx='201' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.91'/%3E%3Ccircle cx='207' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.25'/%3E%3Ccircle cx='213' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.21'/%3E%3Ccircle cx='219' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.74'/%3E%3Ccircle cx='225' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.89'/%3E%3Ccircle cx='231' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.26'/%3E%3Ccircle cx='237' cy='8.6' r='1.55' fill='%235B6BFF' fill-opacity='0.72'/%3E%3Ccircle cx='0' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.66'/%3E%3Ccircle cx='6' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.19'/%3E%3Ccircle cx='12' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.2'/%3E%3Ccircle cx='18' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.2'/%3E%3Ccircle cx='24' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.53'/%3E%3Ccircle cx='30' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.65'/%3E%3Ccircle cx='36' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.25'/%3E%3Ccircle cx='42' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.92'/%3E%3Ccircle cx='48' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.25'/%3E%3Ccircle cx='54' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.32'/%3E%3Ccircle cx='60' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.28'/%3E%3Ccircle cx='66' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.77'/%3E%3Ccircle cx='72' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.3'/%3E%3Ccircle cx='78' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.23'/%3E%3Ccircle cx='84' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.26'/%3E%3Ccircle cx='90' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.46'/%3E%3Ccircle cx='96' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.47'/%3E%3Ccircle cx='102' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.39'/%3E%3Ccircle cx='108' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.41'/%3E%3Ccircle cx='114' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.92'/%3E%3Ccircle cx='120' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.82'/%3E%3Ccircle cx='126' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.25'/%3E%3Ccircle cx='132' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.82'/%3E%3Ccircle cx='138' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.79'/%3E%3Ccircle cx='144' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.61'/%3E%3Ccircle cx='150' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.74'/%3E%3Ccircle cx='156' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.83'/%3E%3Ccircle cx='162' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.34'/%3E%3Ccircle cx='168' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.3'/%3E%3Ccircle cx='174' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.31'/%3E%3Ccircle cx='180' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.98'/%3E%3Ccircle cx='186' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.83'/%3E%3Ccircle cx='192' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.34'/%3E%3Ccircle cx='198' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.58'/%3E%3Ccircle cx='204' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.85'/%3E%3Ccircle cx='210' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='1'/%3E%3Ccircle cx='216' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.51'/%3E%3Ccircle cx='222' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.19'/%3E%3Ccircle cx='228' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.41'/%3E%3Ccircle cx='234' cy='13.4' r='1.55' fill='%235B6BFF' fill-opacity='0.78'/%3E%3Ccircle cx='3' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.22'/%3E%3Ccircle cx='9' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.33'/%3E%3Ccircle cx='15' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.64'/%3E%3Ccircle cx='21' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.87'/%3E%3Ccircle cx='27' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.18'/%3E%3Ccircle cx='33' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.55'/%3E%3Ccircle cx='39' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.43'/%3E%3Ccircle cx='45' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.39'/%3E%3Ccircle cx='51' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.95'/%3E%3Ccircle cx='57' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.78'/%3E%3Ccircle cx='63' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.69'/%3E%3Ccircle cx='69' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.77'/%3E%3Ccircle cx='75' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.34'/%3E%3Ccircle cx='81' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.78'/%3E%3Ccircle cx='87' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.39'/%3E%3Ccircle cx='93' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.87'/%3E%3Ccircle cx='99' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.2'/%3E%3Ccircle cx='105' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.35'/%3E%3Ccircle cx='111' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.34'/%3E%3Ccircle cx='117' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.19'/%3E%3Ccircle cx='123' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.77'/%3E%3Ccircle cx='129' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.23'/%3E%3Ccircle cx='135' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.81'/%3E%3Ccircle cx='141' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.54'/%3E%3Ccircle cx='147' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.8'/%3E%3Ccircle cx='153' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.49'/%3E%3Ccircle cx='159' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.42'/%3E%3Ccircle cx='165' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.99'/%3E%3Ccircle cx='171' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.37'/%3E%3Ccircle cx='177' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.19'/%3E%3Ccircle cx='183' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.55'/%3E%3Ccircle cx='189' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.65'/%3E%3Ccircle cx='195' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.45'/%3E%3Ccircle cx='201' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.45'/%3E%3Ccircle cx='207' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.88'/%3E%3Ccircle cx='213' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.52'/%3E%3Ccircle cx='219' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.54'/%3E%3Ccircle cx='225' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.51'/%3E%3Ccircle cx='231' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.52'/%3E%3Ccircle cx='237' cy='18.2' r='1.55' fill='%235B6BFF' fill-opacity='0.2'/%3E%3C/svg%3E");
  }

  .effort-head { display:flex; align-items:baseline; gap:6px; margin-bottom:8px; }
  .effort-head .effort-lbl { font-size:12px; font-weight:600; color:var(--color-text-secondary); letter-spacing:.01em; }
  .effort-lvl { font-size:13px; font-weight:600; color:var(--color-text-primary); transition:color var(--motion-base) var(--easing-standard); }
  .effort-pop.is-max .effort-lvl { color:var(--color-primary); }

  .effort-track { position:relative; height:var(--trk); }

  /* native range — transparent track, full-height pill thumb on top (z above the dot layer) */
  .effort-pop input[type=range] {
    -webkit-appearance:none; appearance:none;
    display:block; width:100%; height:var(--trk); margin:0; padding:0;
    background:transparent; cursor:pointer; position:relative; z-index:3;
  }
  .effort-pop input[type=range]:focus { outline:none; }
  .effort-pop input[type=range]::-webkit-slider-runnable-track,
  .effort-pop input[type=range]::-moz-range-track {
    box-sizing:border-box; height:var(--trk); border:0; background:transparent;
  }

  /* NON-MAX channel: recess + --ev progress fill ending under the thumb centre. Hidden at max. */
  .effort-chan {
    position:absolute; inset:0; height:var(--trk);
    border-radius:var(--radius-sm); border:1px solid var(--color-border);
    pointer-events:none; z-index:1;
    transition:opacity var(--motion-base) var(--easing-standard);
    background:
      linear-gradient(90deg, var(--fill) 0, var(--fill) calc(var(--ethumb)/2 + var(--ev) * (100% - var(--ethumb))), transparent calc(var(--ethumb)/2 + var(--ev) * (100% - var(--ethumb)))),
      var(--ch);
    background-repeat:no-repeat;
  }
  .effort-pop.is-max .effort-chan { opacity:0; }

  /* MAX matrix: single-accent dot field (random per-dot opacity = twinkle) over the recess,
     scrolling right→left; ::after lays a fixed left→right brightness gradient. Max only. */
  .effort-grid {
    position:absolute; inset:0; height:var(--trk);
    border-radius:var(--radius-sm); border:1px solid var(--color-border);
    pointer-events:none; z-index:1; overflow:hidden;
    opacity:0; transition:opacity var(--motion-base) var(--easing-standard);
    background-color:var(--ch);
    background-image:var(--eff-grid);
    background-repeat:repeat-x; background-position:0 center; background-size:240px var(--trk);
  }
  .effort-grid::after {
    content:""; position:absolute; inset:0; pointer-events:none;
    background:linear-gradient(90deg, var(--ch) 0%, color-mix(in srgb, var(--ch) 55%, transparent) 32%, transparent 64%);
  }
  .effort-pop.is-max .effort-grid { opacity:1; }
  @media (prefers-reduced-motion: no-preference) {
    .effort-pop.is-max .effort-grid { animation:effortFlow 6s linear infinite; }
  }
  @keyframes effortFlow { from { background-position:0 center; } to { background-position:-240px center; } }
  @media (prefers-reduced-motion: reduce) {
    .effort-pop.is-max .effort-grid { animation:none; }
  }

  /* discrete step dots — ALWAYS visible, own layer above chan/grid, below the thumb;
     4 dots at the true thumb-stop centres, rightmost (max) = accent. */
  .effort-dots {
    position:absolute; inset:0; height:var(--trk);
    pointer-events:none; z-index:2;
    transition:opacity var(--motion-base) var(--easing-standard);
    background:
      radial-gradient(circle at calc(100% - var(--ethumb)/2) 50%, var(--accent) 0 2.3px, transparent 2.7px),
      radial-gradient(circle at calc(var(--ethumb)/2) 50%, var(--dot) 0 1.8px, transparent 2.1px),
      radial-gradient(circle at calc(var(--ethumb)/2 + (100% - var(--ethumb))/3) 50%, var(--dot) 0 1.8px, transparent 2.1px),
      radial-gradient(circle at calc(var(--ethumb)/2 + (100% - var(--ethumb)) * 2 / 3) 50%, var(--dot) 0 1.8px, transparent 2.1px);
    background-repeat:no-repeat;
  }
  .effort-pop.is-max .effort-dots { opacity:0; }   /* at max the matrix is the whole point — drop the position dots */

  /* full-height pill thumb (fills the track, no vertical gap) */
  .effort-pop input[type=range]::-webkit-slider-thumb {
    -webkit-appearance:none; appearance:none; box-sizing:border-box;
    width:var(--ethumb); height:var(--trk); margin-top:0;
    border-radius:7px;
    background:#F4F6FC; border:1px solid var(--color-border-strong);
    box-shadow:0 1px 3px rgba(0,0,0,.45), 0 0 0 .5px rgba(0,0,0,.25);
    transition:background var(--motion-base) var(--easing-standard);
  }
  .effort-pop input[type=range]:hover::-webkit-slider-thumb { background:#ffffff; }
  .effort-pop input[type=range]:focus-visible::-webkit-slider-thumb {
    box-shadow:0 1px 3px rgba(0,0,0,.45), 0 0 0 3px color-mix(in srgb, var(--color-primary) 55%, transparent);
  }
  .effort-pop input[type=range]::-moz-range-thumb {
    box-sizing:border-box; width:var(--ethumb); height:var(--trk);
    border:1px solid var(--color-border-strong); border-radius:7px; background:#F4F6FC;
    box-shadow:0 1px 3px rgba(0,0,0,.45), 0 0 0 .5px rgba(0,0,0,.25);
    transition:background var(--motion-base) var(--easing-standard);
  }
  .effort-pop input[type=range]:hover::-moz-range-thumb { background:#ffffff; }
  .effort-pop input[type=range]:focus-visible::-moz-range-thumb {
    box-shadow:0 1px 3px rgba(0,0,0,.45), 0 0 0 3px color-mix(in srgb, var(--color-primary) 55%, transparent);
  }
  .effort-pop input[type=range]::-moz-range-progress { background:transparent; height:var(--trk); }
  .effort-pop input[type=range]::-moz-focus-outer { border:0; }
  :root[data-theme="light"] .effort-pop input[type=range]::-webkit-slider-thumb,
  :root[data-theme="light"] .effort-pop input[type=range]::-moz-range-thumb {
    background:#ffffff; border-color:var(--color-border-strong);
    box-shadow:0 1px 2px rgba(17,22,34,.18), 0 0 0 .5px rgba(17,22,34,.10);
  }

  /* end labels */
  .effort-scale { display:flex; justify-content:space-between; font-size:10px; color:var(--color-text-muted); margin-top:6px; letter-spacing:.02em; }
  /* max-height fits an empty (min-height) chat box so the upward menu never towers over a fresh box */
  .bmenu-up { position:absolute; left:0; bottom:calc(100% + 8px); min-width:210px; max-width:300px; max-height:200px; overflow-y:auto; overscroll-behavior:contain; background:var(--color-elevated); border:1px solid var(--color-border-strong); border-radius:var(--radius-md); box-shadow:var(--shadow-lg); padding:4px; z-index:30; }
  /* slash-command (quick questions) menu on the Help input, opening upward */
  .cmd-wrap { position:absolute; left:7px; bottom:6px; }
  .cmdbtn { display:inline-flex; align-items:center; justify-content:center; width:30px; height:30px; padding:0; border:0; border-radius:var(--radius-sm); background:transparent; color:var(--color-text-muted); font-family:var(--font-mono); font-size:1.05rem; line-height:1; cursor:pointer; transition:background var(--motion-base) var(--easing-standard), color var(--motion-base) var(--easing-standard); }
  .cmdbtn:hover { background:var(--color-elevated); color:var(--color-primary); }
  .cmd-menu { position:absolute; left:0; bottom:calc(100% + 8px); min-width:260px; max-width:min(340px, calc(100vw - 32px)); max-height:min(280px, 45dvh); overflow-y:auto; overscroll-behavior:contain; background:var(--color-elevated); border:1px solid var(--color-border-strong); border-radius:var(--radius-md); box-shadow:var(--shadow-lg); padding:4px; z-index:30; }
  .cmd-item { display:flex; align-items:center; min-height:40px; width:100%; padding:8px 11px; border:0; background:transparent; color:var(--color-text-secondary); font-size:0.8rem; text-align:left; border-radius:var(--radius-sm); cursor:pointer; }
  .cmd-item:hover { background:var(--color-surface); color:var(--color-text-primary); }
  .cmd-sep { height:1px; margin:4px 6px; background:var(--color-border); }
  .cmd-danger:hover { background:var(--color-danger-soft); color:var(--color-danger); }
  .cmd-slash { font-family:var(--font-mono); font-size:0.74rem; color:var(--color-text-muted); margin-right:7px; flex-shrink:0; }
  .bmodel-item { display:flex; align-items:center; gap:8px; width:100%; padding:8px 9px; border:0; background:transparent; color:var(--color-text-secondary); font-family:var(--font-mono); font-size:0.78rem; text-align:left; border-radius:var(--radius-sm); cursor:pointer; white-space:nowrap; }
  .bmodel-item:hover { background:var(--color-surface); color:var(--color-text-primary); }
  .bmodel-item[aria-selected="true"] { color:var(--color-text-primary); background:var(--color-primary-hover); }
  .cdots { display:inline-flex; gap:4px; align-items:center; }
  .cdots span { width:6px; height:6px; border-radius:var(--radius-full); background:var(--color-text-muted); animation:cdot 1s infinite var(--easing-standard); }
  .cdots span:nth-child(2) { animation-delay:.15s; }
  .cdots span:nth-child(3) { animation-delay:.3s; }
  @keyframes cdot { 0%,60%,100% { opacity:.25; transform:translateY(0); } 30% { opacity:1; transform:translateY(-3px); } }

  /* ---- live balance refresh: flash primary, ease back */
  .stat-value { transition: color .6s var(--easing-standard); }
  .stat-value.balflash { color: var(--color-primary-hover); transition: color .12s var(--easing-standard); }

  /* ---- mobile density: trim stacked padding/margins so content fills more of a ~375px screen.
     Placed at the END of PORTAL_CSS on purpose: @media adds no specificity, so these <=560px
     overrides must come source-order AFTER the base rules they target (.chatpane/.chatbox-body/
     .chatisland/.mdrop are declared further down than the main @media block above). ---- */
  @media (max-width:560px) {
    .hint { margin:var(--space-2) var(--space-1) 0; }
    .topbar { margin-bottom:var(--space-3); }
    .card { padding:var(--space-4); gap:10px; }
    .balcard { padding:var(--space-4); gap:var(--space-3); }
    .codewrap { margin-top:var(--space-3); }
    .mdrop { margin-top:var(--space-2); }
    .chatpane { padding:var(--space-3); }
    .chatisland { margin-top:var(--space-3); }
    .chatbox-body { padding:10px; }
  }

  /* ---- Light theme: opt-in via data-theme="light"; JS resolves 'auto' from the system ---- */
  :root[data-theme="light"] {
    color-scheme: light;
    --color-background: #F4F6FA;
    --color-surface: #FFFFFF;
    --color-elevated: #ECEFF5;
    --color-overlay: rgba(17, 22, 34, 0.45);
    --color-border: #E1E5EE;
    --color-border-strong: #C7CDDA;
    --color-border-soft: rgba(17, 22, 34, 0.05);
    --color-text-primary: #14161D;
    --color-text-secondary: #515A6B;
    --color-text-muted: #858C9C;
    --color-text-inverse: #FFFFFF;
    --color-primary-hover: #4A59E6;
    --color-success: #12A150;
    --color-warning: #AD6F00;
    --color-info: #0E93AE;
    --color-danger: #E11D48;
    --color-success-soft: rgba(18, 161, 80, 0.12);
    --color-warning-soft: rgba(173, 111, 0, 0.14);
    --color-info-soft: rgba(14, 147, 174, 0.12);
    --color-danger-soft: rgba(225, 29, 72, 0.10);
    --shadow-sm: 0 1px 2px rgba(17, 22, 34, 0.08);
    --shadow-md: 0 8px 24px rgba(17, 22, 34, 0.10);
    --shadow-lg: 0 24px 60px rgba(17, 22, 34, 0.14);
    --focus-ring: 0 0 0 3px rgba(91, 107, 255, 0.32);
  }
  /* theme + language switches share the brand row's right cluster */
  .topbar-actions { display:inline-flex; align-items:center; gap:8px; flex-shrink:0; }
  .themebtn { flex-shrink:0; display:inline-flex; align-items:center; justify-content:center; width:32px; height:32px; background:var(--color-surface); border:1px solid var(--color-border); border-radius:var(--radius-full); color:var(--color-text-secondary); cursor:pointer; transition:background var(--motion-base) var(--easing-standard), color var(--motion-base) var(--easing-standard), border-color var(--motion-base) var(--easing-standard); }
  .themebtn:hover { color:var(--color-text-primary); border-color:var(--color-border-strong); }
  .themebtn svg { width:16px; height:16px; }
  .pushbtn.is-on { color:var(--color-primary); border-color:var(--color-primary); background:var(--color-primary-soft, var(--color-surface)); }
  .pushmsg { margin:6px 12px 0; padding:8px 12px; font-size:13px; line-height:1.4; color:var(--color-text-secondary); background:var(--color-surface); border:1px solid var(--color-border); border-radius:var(--radius-md, 8px); cursor:pointer; }
