/* stx role tokens — override any of these to re-theme by meaning. */
:root {
  --stx-fg: oklch(20.5% 0 0);
  --stx-fg-strong: oklch(37.1% 0 0);
  --stx-fg-muted: oklch(43.9% 0 0);
  --stx-fg-soft: oklch(55.6% 0 0);
  --stx-fg-subtle: oklch(70.8% 0 0);
  --stx-surface: oklch(98.5% 0 0);
  --stx-surface-raised: oklch(97% 0 0);
  --stx-surface-sunken: oklch(92.2% 0 0);
  --stx-panel: #fff;
  --stx-field: #fff;
  --stx-page: oklch(98.5% 0 0);
  --stx-content: #fff;
  --stx-surface-hover: oklch(97% 0 0);
  --stx-surface-raised-hover: oklch(92.2% 0 0);
  --stx-surface-sunken-hover: oklch(87% 0 0);
  --stx-field-hover: oklch(98.5% 0 0);
  --stx-link: oklch(62.3% 0.214 259.815);
  --stx-link-hover: oklch(54.6% 0.245 262.881);
  --stx-inverse: oklch(20.5% 0 0);
  --stx-inverse-ink: #fff;
  --stx-line: oklch(92.2% 0 0);
  --stx-line-strong: oklch(87% 0 0);
  --stx-line-hover: oklch(70.8% 0 0);
  --stx-accent: oklch(54.6% 0.245 262.881);
  --stx-info: oklch(60.9% 0.126 221.723);
  --stx-danger: oklch(57.7% 0.245 27.325);
  --stx-success: oklch(62.7% 0.194 149.214);
  --stx-warning: oklch(68.1% 0.162 75.834);
  --stx-accent-solid: oklch(62.3% 0.214 259.815);
  --stx-info-solid: oklch(71.5% 0.143 215.221);
  --stx-danger-solid: oklch(63.7% 0.237 25.331);
  --stx-success-solid: oklch(72.3% 0.219 149.579);
  --stx-warning-solid: oklch(79.5% 0.184 86.047);
  --stx-accent-solid-hover: oklch(54.6% 0.245 262.881);
  --stx-info-solid-hover: oklch(60.9% 0.126 221.723);
  --stx-danger-solid-hover: oklch(57.7% 0.245 27.325);
  --stx-success-solid-hover: oklch(62.7% 0.194 149.214);
  --stx-warning-solid-hover: oklch(68.1% 0.162 75.834);
  --stx-accent-ink: #fff;
  --stx-info-ink: oklch(20.5% 0 0);
  --stx-danger-ink: #fff;
  --stx-success-ink: oklch(20.5% 0 0);
  --stx-warning-ink: oklch(20.5% 0 0);
  --stx-accent-soft: oklch(93.2% 0.032 255.585);
  --stx-accent-soft-ink: oklch(42.4% 0.199 265.638);
  --stx-info-soft: oklch(95.6% 0.045 203.388);
  --stx-info-soft-ink: oklch(45% 0.085 224.283);
  --stx-danger-soft: oklch(93.6% 0.032 17.717);
  --stx-danger-soft-ink: oklch(44.4% 0.177 26.899);
  --stx-success-soft: oklch(96.2% 0.044 156.743);
  --stx-success-soft-ink: oklch(44.8% 0.119 151.328);
  --stx-warning-soft: oklch(97.3% 0.071 103.193);
  --stx-warning-soft-ink: oklch(47.6% 0.114 61.907);
  --stx-secondary: oklch(55.8% 0.288 302.321);
  --stx-secondary-solid: oklch(62.7% 0.265 303.9);
  --stx-secondary-solid-hover: oklch(55.8% 0.288 302.321);
  --stx-secondary-ink: #fff;
  --stx-secondary-soft: oklch(94.6% 0.033 307.174);
  --stx-secondary-soft-ink: oklch(43.8% 0.218 303.724);
  --stx-danger-fg: oklch(39.6% 0.141 25.723);
  --stx-danger-fg-subtle: oklch(80.8% 0.114 19.571);
  --stx-danger-line: oklch(80.8% 0.114 19.571);
  --stx-danger-focus: oklch(63.7% 0.237 25.331);
}
.dark {
  --stx-fg: oklch(97% 0 0);
  --stx-fg-strong: oklch(87% 0 0);
  --stx-fg-muted: oklch(70.8% 0 0);
  --stx-fg-soft: oklch(70.8% 0 0);
  --stx-fg-subtle: oklch(55.6% 0 0);
  --stx-surface: oklch(26.9% 0 0);
  --stx-surface-raised: oklch(37.1% 0 0);
  --stx-surface-sunken: oklch(37.1% 0 0);
  --stx-panel: oklch(26.9% 0 0);
  --stx-field: oklch(37.1% 0 0);
  --stx-page: oklch(20.5% 0 0);
  --stx-content: oklch(20.5% 0 0);
  --stx-surface-hover: oklch(37.1% 0 0);
  --stx-surface-raised-hover: oklch(43.9% 0 0);
  --stx-surface-sunken-hover: oklch(43.9% 0 0);
  --stx-field-hover: oklch(43.9% 0 0);
  --stx-link: oklch(70.7% 0.165 254.624);
  --stx-link-hover: oklch(80.9% 0.105 251.813);
  --stx-inverse: oklch(37.1% 0 0);
  --stx-inverse-ink: #fff;
  --stx-line: oklch(37.1% 0 0);
  --stx-line-strong: oklch(43.9% 0 0);
  --stx-line-hover: oklch(55.6% 0 0);
  --stx-accent: oklch(70.7% 0.165 254.624);
  --stx-info: oklch(78.9% 0.154 211.53);
  --stx-danger: oklch(70.4% 0.191 22.216);
  --stx-success: oklch(79.2% 0.209 151.711);
  --stx-warning: oklch(85.2% 0.199 91.936);
  --stx-accent-solid: oklch(54.6% 0.245 262.881);
  --stx-info-solid: oklch(60.9% 0.126 221.723);
  --stx-danger-solid: oklch(57.7% 0.245 27.325);
  --stx-success-solid: oklch(62.7% 0.194 149.214);
  --stx-warning-solid: oklch(68.1% 0.162 75.834);
  --stx-accent-solid-hover: oklch(48.8% 0.243 264.376);
  --stx-info-solid-hover: oklch(52% 0.105 223.128);
  --stx-danger-solid-hover: oklch(50.5% 0.213 27.518);
  --stx-success-solid-hover: oklch(52.7% 0.154 150.069);
  --stx-warning-solid-hover: oklch(55.4% 0.135 66.442);
  --stx-accent-ink: #fff;
  --stx-info-ink: oklch(20.5% 0 0);
  --stx-danger-ink: #fff;
  --stx-success-ink: oklch(20.5% 0 0);
  --stx-warning-ink: oklch(20.5% 0 0);
  --stx-accent-soft: oklch(37.9% 0.146 265.522);
  --stx-accent-soft-ink: oklch(88.2% 0.059 254.128);
  --stx-info-soft: oklch(39.8% 0.07 227.392);
  --stx-info-soft-ink: oklch(91.7% 0.08 205.041);
  --stx-danger-soft: oklch(39.6% 0.141 25.723);
  --stx-danger-soft-ink: oklch(88.5% 0.062 18.334);
  --stx-success-soft: oklch(39.3% 0.095 152.535);
  --stx-success-soft-ink: oklch(92.5% 0.084 155.995);
  --stx-warning-soft: oklch(42.1% 0.095 57.708);
  --stx-warning-soft-ink: oklch(94.5% 0.129 101.54);
  --stx-secondary: oklch(71.4% 0.203 305.504);
  --stx-secondary-solid: oklch(55.8% 0.288 302.321);
  --stx-secondary-solid-hover: oklch(49.6% 0.265 301.924);
  --stx-secondary-ink: #fff;
  --stx-secondary-soft: oklch(38.1% 0.176 304.987);
  --stx-secondary-soft-ink: oklch(90.2% 0.063 306.703);
  --stx-danger-fg: oklch(80.8% 0.114 19.571);
  --stx-danger-fg-subtle: oklch(63.7% 0.237 25.331);
  --stx-danger-line: oklch(57.7% 0.245 27.325);
  --stx-danger-focus: oklch(70.4% 0.191 22.216);
}
/* stx shape tokens — a radius by what the thing is. */
:root {
  --stx-radius-control: 0.375rem;
  --stx-radius-panel: 0.5rem;
  --stx-radius-pill: 9999px;
}
/* stx density tokens — how much room a control or a table cell takes. */
:root {
  --stx-control-px: 1rem;
  --stx-control-py: 0.5rem;
  --stx-control-text: 1rem;
  --stx-control-leading: 1.5rem;
  --stx-cell-px: 1.5rem;
  --stx-cell-py: 1rem;
  --stx-cell-text: 0.875rem;
  --stx-cell-leading: 1.25rem;
  --stx-cell-head-py: 0.75rem;
  --stx-cell-head-text: 0.75rem;
  --stx-cell-head-leading: 1rem;
}
.wordmark {
  font-weight: 700;
  letter-spacing: -0.03em;
}

.field {
  background-color: var(--bg);
  border-width: 1px;
  border-color: var(--border);
  border-radius: 10px;
  color: var(--text);
}

.field:focus {
  outline-style: none;
  border-color: var(--accent);
  --tc-shadow: 0 0 0 3px color-mix(in srgb,var(--accent) 16%,transparent);
  --tc-shadow-colored: 0 0 0 3px color-mix(in srgb,var(--accent) 16%,transparent);
  box-shadow: var(--tc-inset-shadow, 0 0 #0000), var(--tc-inset-ring-shadow, 0 0 #0000), var(--tc-ring-offset-shadow, 0 0 #0000), var(--tc-ring-shadow, 0 0 #0000), var(--tc-shadow, 0 0 #0000);
}

.auth-submit {
  padding-top: 0.625rem !important;
  padding-bottom: 0.625rem !important;
  --tc-shadow: 0 0 #0000 !important;
  box-shadow: var(--tc-inset-shadow, 0 0 #0000), var(--tc-inset-ring-shadow, 0 0 #0000), var(--tc-ring-offset-shadow, 0 0 #0000), var(--tc-ring-shadow, 0 0 #0000), var(--tc-shadow, 0 0 #0000) !important;
  transition: transform 0.12s ease,opacity 0.15s ease !important;
}

.auth-submit:hover {
  background-color: color-mix(in srgb,var(--accent) 88%,#000) !important;
}

.auth-submit:active {
  transform: translateY(1px);
}

.auth-submit:disabled {
  opacity: 0.6 !important;
  cursor: default !important;
}

.oauth-btn {
  background-color: var(--panel);
  border-width: 1px;
  border-color: var(--border);
  border-radius: 10px;
  color: var(--text);
  transition: border-color 0.15s ease,transform 0.12s ease;
}

.oauth-btn:hover {
  border-color: color-mix(in srgb,var(--accent) 45%,var(--border));
}

.oauth-btn:active {
  transform: translateY(1px);
}

.err-box {
  background-color: color-mix(in srgb,#ef4444 12%,transparent);
  color: #ef4444;
}

.notice-box {
  padding-left: 0.75rem;
  padding-right: 0.75rem;
  font-size: 0.875rem;
  line-height: 1.25rem;
  border-radius: 0.5rem;
}
@layer tc-base {
/*
! Tailwind CSS Preflight | MIT License | https://tailwindcss.com
*/

/*
  The fallback is a neutral grey, not currentColor.

  currentColor makes every border whose colour was never set take the TEXT
  colour, which is near-black on a light page and near-white on a dark one.
  That is never what an author means by a divider: the divide-* and
  border-width utilities set a width and no colour, so a plain divide-y
  rendered as a heavy black rule instead of a hairline.

  It also punished the obvious workaround. Setting border-color on a parent
  does not reach divide-* children, because divide targets
  "> :not([hidden]) ~ :not([hidden])" and the child declaration from this
  block wins.

  Tailwind preflight resolves this the same way (its default is gray-200).
  --border-color stays the escape hatch: set it once on :root, or per
  theme, and every uncoloured border follows.
*/
*,
::before,
::after {
  box-sizing: border-box;
  border-width: 0;
  border-style: solid;
  border-color: var(--border-color, #e5e7eb);
}

::before,
::after {
  --tc-content: '';
}

html,
:host {
  line-height: 1.5;
  -webkit-text-size-adjust: 100%;
  -moz-tab-size: 4;
  tab-size: 4;
  font-family: Space Grotesk, ui-sans-serif, system-ui, sans-serif;
  font-feature-settings: normal;
  font-variation-settings: normal;
  -webkit-tap-highlight-color: transparent;
}

body {
  margin: 0;
  line-height: inherit;
}

hr {
  height: 0;
  color: inherit;
  border-top-width: 1px;
}

abbr:where([title]) {
  text-decoration: underline dotted;
}

h1,
h2,
h3,
h4,
h5,
h6 {
  font-size: inherit;
  font-weight: inherit;
}

a {
  color: inherit;
  text-decoration: inherit;
}

b,
strong {
  font-weight: bolder;
}

code,
kbd,
samp,
pre {
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
  font-feature-settings: normal;
  font-variation-settings: normal;
  font-size: 1em;
}

small {
  font-size: 80%;
}

sub,
sup {
  font-size: 75%;
  line-height: 0;
  position: relative;
  vertical-align: baseline;
}

sub {
  bottom: -0.25em;
}

sup {
  top: -0.5em;
}

table {
  text-indent: 0;
  border-color: var(--border-color, inherit);
  border-collapse: collapse;
}

button,
input,
optgroup,
select,
textarea {
  font-family: inherit;
  font-feature-settings: inherit;
  font-variation-settings: inherit;
  font-size: 100%;
  font-weight: inherit;
  line-height: inherit;
  letter-spacing: inherit;
  color: inherit;
  margin: 0;
  padding: 0;
}

button,
select {
  text-transform: none;
}

button,
input:where([type='button']),
input:where([type='reset']),
input:where([type='submit']) {
  -webkit-appearance: button;
  background-color: transparent;
  background-image: none;
}

:-moz-focusring {
  outline: auto;
}

:-moz-ui-invalid {
  box-shadow: none;
}

progress {
  vertical-align: baseline;
}

::-webkit-inner-spin-button,
::-webkit-outer-spin-button {
  height: auto;
}

[type='search'] {
  -webkit-appearance: textfield;
  outline-offset: -2px;
}

::-webkit-search-decoration {
  -webkit-appearance: none;
}

::-webkit-file-upload-button {
  -webkit-appearance: button;
  font: inherit;
}

summary {
  display: list-item;
}

blockquote,
dl,
dd,
h1,
h2,
h3,
h4,
h5,
h6,
hr,
figure,
p,
pre {
  margin: 0;
}

fieldset {
  margin: 0;
  padding: 0;
}

legend {
  padding: 0;
}

ol,
ul,
menu {
  list-style: none;
  margin: 0;
  padding: 0;
}

dialog {
  padding: 0;
}

textarea {
  resize: vertical;
}

input::placeholder,
textarea::placeholder {
  opacity: 1;
  color: color-mix(in oklab, currentColor 50%, transparent);
}

button,
[role="button"] {
  cursor: pointer;
}

:disabled {
  cursor: default;
}

img,
svg,
video,
canvas,
audio,
iframe,
embed,
object {
  display: block;
  vertical-align: middle;
}

img,
video {
  max-width: 100%;
  height: auto;
}

[hidden] {
  display: none;
}
}

@layer tc-base {

:root {
  /* The one declaration that reaches the parts of the page we do not draw.
   *
   * Native UI — the select popup, scrollbars, the date and colour pickers, form
   * control backgrounds, the spellcheck underline, the caret — is painted by the
   * browser from `color-scheme`, not from our custom properties. Undeclared it
   * defaults to `light`, so on a dark loghq the project dropdown opened as a
   * white popup on a #090b11 page and the scrollbars stayed light. No amount of
   * token work reaches those pixels; this is the only thing that does.
   *
   * It is declared on all four blocks below and not once on `:root` with both
   * values, because `color-scheme: light dark` means "either is fine, follow the
   * OS" — which is wrong the moment someone picks a theme explicitly. The
   * attribute blocks have to be able to override the media query, exactly like
   * every colour here. */
  color-scheme: light;
  --bg: #fbfbfd;
  --panel: #ffffff;
  --border: rgba(15, 23, 42, 0.09);
  --text: #0b0f19;
  --text-2: #4b5565;
  /* --text-3 was #97a1b2, which measured 2.52:1 against --bg and 2.61:1
   * against --panel. WCAG AA wants 4.5:1 for body text, so every "subtle"
   * label in the app failed it — 73 elements in light and 82 in dark, measured
   * in a real browser across seven pages. It is the same token in both themes
   * and it failed in both (dark was #667085, 3.73:1 on --panel).
   *
   * #6b7280 gives 4.83:1 on --panel and 4.68:1 on --bg; the dark #79839a gives
   * 4.88:1 and 5.18:1. Both are the smallest step that clears AA on the worse
   * of the two surfaces, so "subtle" still reads as subtle. */
  --text-3: #6b7280;
  /* Emerald, not the rose this shipped with.
   *
   * The old --accent was #e11d48, which is byte-for-byte --sev-error below. In
   * a product whose whole surface is log severity, the brand colour WAS the
   * error colour: every button, link and focus ring carried the one hue the
   * severity scale reserves for something being wrong.
   *
   * Green collides with --ok instead, which is the milder trade. --ok is a UI
   * success state, not a severity: nothing in the sev-* scale is green, so the
   * severity reading stays unambiguous. Brand-as-healthy misleads nobody;
   * brand-as-error did.
   *
   * #047857 rather than the more obvious #059669: emerald-600 measures 3.65:1
   * on --bg, under the 4.5 floor this file holds everything else to. This one
   * measures 5.31:1 on --bg and 5.48:1 on --panel, which is also an improvement
   * on the rose it replaces (4.54:1, passing by 0.04). */
  --accent: #047857;
  --accent-soft: rgba(4, 120, 87, 0.08);
  /* Ink for text sitting ON a saturated fill — the accent, --warn, and the
   * Slack/Discord brand colours.
   *
   * It cannot be a hardcoded #fff, which is what the app markup and
   * app-chrome.css assumed. In dark mode the fills get LIGHTER, not darker:
   * --accent is #34d399 and the dashboard's indigo is #818cf8, where white
   * measures 1.92:1 and 2.98:1. The dark value here measures 9.83:1 and 6.34:1
   * on those same fills, and 6.83:1 on the dark --warn.
   *
   * marketing.css has had this token, correctly themed, since the marketing
   * pages were built; it just never reached the app surface, because that
   * sheet only loads on marketing routes. Declared here it covers both, and
   * marketing.css no longer declares its own copy — see the .reveal note there
   * for what two copies of one token cost. */
  --accent-ink: #ffffff;
  --ok: #16a34a;
  --warn: #b91c1c;
  --sans: 'Space Grotesk', ui-sans-serif, system-ui, sans-serif;
  --mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Log severity. These were six hex literals inside a levelColor() switch in
   * dashboard.stx, with two of them repeated in the stats array — so the same
   * "warning amber" was written twice and could drift.
   *
   * They were also a single set used on BOTH themes. The dark values below are
   * exactly what shipped before, so dark is unchanged; light gets darker,
   * higher-contrast variants, because #fb7185 on a #fbfbfd background is not a
   * readable label. */
  --sev-critical: #be123c;
  --sev-error: #e11d48;
  --sev-warning: #b45309;
  --sev-notice: #0369a1;
  --sev-info: #1d4ed8;
  --sev-debug: #64748b;
}

@media (prefers-color-scheme: dark) {
  :root {
    color-scheme: dark;
    --bg: #090b11;
    --panel: #10131c;
    --border: rgba(148, 163, 184, 0.12);
    --text: #f3f5f9;
    --text-2: #b3bccb;
    --text-3: #79839a;
    --accent: #34d399;
    --accent-soft: rgba(52, 211, 153, 0.1);
    --accent-ink: #04140d;
    --ok: #4ade80;
    --warn: #f87171;
  --sev-critical: #f43f5e;
  --sev-error: #fb7185;
  --sev-warning: #f59e0b;
  --sev-notice: #38bdf8;
  --sev-info: #60a5fa;
  --sev-debug: #94a3b8;
  }
}

:root[data-theme='dark'] {
  color-scheme: dark;
  --bg: #090b11;
  --panel: #10131c;
  --border: rgba(148, 163, 184, 0.12);
  --text: #f3f5f9;
  --text-2: #b3bccb;
  --text-3: #79839a;
  --accent: #34d399;
  --accent-soft: rgba(52, 211, 153, 0.1);
  --accent-ink: #04140d;
  --ok: #4ade80;
  --warn: #f87171;
  --sev-critical: #f43f5e;
  --sev-error: #fb7185;
  --sev-warning: #f59e0b;
  --sev-notice: #38bdf8;
  --sev-info: #60a5fa;
  --sev-debug: #94a3b8;
}

:root[data-theme='light'] {
  color-scheme: light;
  --bg: #fbfbfd;
  --panel: #ffffff;
  --border: rgba(15, 23, 42, 0.09);
  --text: #0b0f19;
  --text-2: #4b5565;
  --text-3: #6b7280;
  --accent: #047857;
  --accent-soft: rgba(4, 120, 87, 0.08);
  --accent-ink: #ffffff;
  --ok: #16a34a;
  --warn: #b91c1c;
  --sev-critical: #be123c;
  --sev-error: #e11d48;
  --sev-warning: #b45309;
  --sev-notice: #0369a1;
  --sev-info: #1d4ed8;
  --sev-debug: #64748b;
}

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  -webkit-font-smoothing: antialiased;
}

/* Skeleton shimmer, from account.stx's <style> block. Utilities cannot declare
 * a @keyframes, so this is a preflight, which is the documented home for one.
 *
 * Named loghq-pulse rather than pulse on purpose. Crosswind emits its own
 * `@keyframes pulse` (0%,100% opacity 1; 50% opacity .5) as soon as any page
 * uses `animate-pulse`, into a sheet that is linked AFTER this file. A
 * same-named keyframe there would silently replace this one and change the
 * animation rather than error.
 */
@keyframes loghq-pulse {
  0%,
  100% {
    opacity: 0.5;
  }
  50% {
    opacity: 0.9;
  }
}

/* The one element that uses it, as a named class rather than an arbitrary
 * `[animation:loghq-pulse_1.4s_ease-in-out_infinite]` utility.
 *
 * That utility worked. What never worked was the guard beside it,
 * `motion-reduce:[animation:none]`: a variant on an arbitrary property is not
 * recognised by crosswind's class extractor, so it produced no rule at all and
 * the skeleton kept pulsing for people who asked their system not to animate.
 * Silent, as that whole class of miss is -- no error, no warning, nothing in
 * the sheet. Filed as stacksjs/ts-css#37; the generator side of it is fixed in
 * 0.3.14 (#36), the extractor is not.
 *
 * Both halves live here, in source order, so the reduced-motion case does not
 * depend on the extractor, on crosswind's output ordering, or on an
 * !important. It also cannot be separated from the keyframes it guards. Note
 * this file is linked BEFORE the generated sheet, which is why the animation
 * is declared here rather than left as a utility for this rule to fight.
 */
.skeleton-pulse {
  animation: loghq-pulse 1.4s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
  .skeleton-pulse {
    animation: none;
  }
}

/* Theme-toggle icon swap. Three identical copies of this lived in
 * dashboard.stx, settings.stx and projects/index.stx.
 *
 * It stays CSS because no utility can express it: the selector is an
 * attribute-state descendant, `[data-t="light"] .ic-sun`, driven by the
 * `theme()` signal through `:data-t` on the button. The alternative — a
 * `:show` binding on each icon — would need `style="display:none"` on both to
 * avoid showing both icons before hydration, trading a state rule for two
 * inline styles and a hydration dependency on something that is currently
 * pure CSS.
 */
.theme-btn .ic-sun,
.theme-btn .ic-moon {
  display: none;
}

/* Keyed off the ROOT element, not off the button.
 *
 * These used to read `.theme-btn[data-t='light']`, where data-t came from a
 * `:data-t="theme()"` binding — a client signal. So before hydration the button
 * carried no data-t at all, neither rule matched, and the pair above left BOTH
 * icons display:none: the theme control rendered as an empty box on every cold
 * load. There is no server-known theme to put in a static counterpart either,
 * so the fix is not a static attribute; it is keying off something that IS set
 * before first paint.
 *
 * stx's color-mode boot script sets data-theme on the root above every
 * stylesheet (config/ui.ts app.colorMode), and useColorMode keeps it current
 * afterwards, so the correct icon paints immediately and the mirror signal the
 * binding needed is gone from all three pages. */
:root[data-theme='light'] .theme-btn .ic-sun {
  display: block;
}

:root[data-theme='dark'] .theme-btn .ic-moon {
  display: block;
}

}

@layer tc-base {

/* ---------------------------------------------------------------------------
 * Page-scoped tokens
 *
 * dashboard is the one surface with its own accent: indigo, so navigation
 * never reads as a severity colour (see 20f40ed). It used to be a `:root`
 * block inside dashboard.stx's <style>, scoped only by the accident of which
 * page carried the tag. Declared globally that would repaint the whole app, so
 * it hangs off a wrapper class on the dashboard's root element and cascades to
 * its descendants — including the fixed-position chrome, which is inside the
 * wrapper.
 * ------------------------------------------------------------------------ */
.page-dashboard {
  --accent: #4f46e5;
  --rail: rgba(79, 70, 229, 0.14);
}

@media (prefers-color-scheme: dark) {
  .page-dashboard {
    --accent: #818cf8;
    --rail: rgba(129, 140, 248, 0.16);
  }
}

:root[data-theme='dark'] .page-dashboard {
  --accent: #818cf8;
  --rail: rgba(129, 140, 248, 0.16);
}

:root[data-theme='light'] .page-dashboard {
  --accent: #4f46e5;
  --rail: rgba(79, 70, 229, 0.14);
}

/* Channel brand colours. Only settings uses them, but they are declared here
 * with everything else rather than in a page tag. */
:root {
  --slack: #611f69;
  --discord: #5865f2;
}

@media (prefers-color-scheme: dark) {
  :root {
    --discord: #818cf8;
  }
}

:root[data-theme='dark'] {
  --discord: #818cf8;
}

:root[data-theme='light'] {
  --discord: #5865f2;
}

/* Tabular numerals for the log stream's counts and timestamps, so digits do
 * not jitter as values change.
 *
 * This is a real rule rather than an arbitrary property because the value has
 * to be quoted — `font-feature-settings: 'tnum' 1` — and a quoted value cannot
 * survive Crosswind's class-name syntax. Written as
 * [font-feature-settings:'tnum'_1] it generates NOTHING; the three
 * font-feature-settings declarations in the served sheet are all preflight
 * resets, and the computed value on the element stayed `normal`.
 *
 * `tabular-nums` is not a substitute: it sets font-variant-numeric, a
 * different property, and would not reproduce the measured baseline.
 */
.tnum {
  font-feature-settings: 'tnum' 1;
}

/* ---------------------------------------------------------------------------
 * Bare element selectors — no utility targets an element type
 * ------------------------------------------------------------------------ */
html {
  scroll-behavior: smooth;
}

/* ---------------------------------------------------------------------------
 * settings: the alert-channel toggle
 *
 * The knob is a ::after pseudo-element and both states are attribute-driven.
 * Crosswind generates nothing for `after:` or for a `[data-on]` variant.
 * ------------------------------------------------------------------------ */
.tgl::after {
  content: '';
  position: absolute;
  top: 2px;
  left: 2px;
  width: 18px;
  height: 18px;
  border-radius: 999px;
  background: #fff;
  transition: transform 0.15s ease;
}

/* The four rules below carry !important, and they are exactly the ones whose
 * element also carries a utility for the same property. While this was a
 * linked stylesheet they won on specificity -- an attribute-state or
 * tag-scoped selector outranks a single-class utility. As a preflight they are
 * in @layer tc-base and a utility is unlayered, which beats a layer at ANY
 * specificity, so without the marks they stop applying.
 *
 * Measured on a probe page carrying the real class lists from settings.stx and
 * dashboard.stx, with the before and after sheets swapped underneath it:
 *
 *   .tgl[data-on='1']          rgb(74,222,128) -> rgba(148,163,184,0.12), ie
 *                              the toggle stops turning green and reads as off
 *                              in both states (loses to `bg-line`)
 *   .seg-slack[data-sel='1']   rgb(97,31,105) -> rgb(16,19,28), the selected
 *                              channel loses its brand fill (`bg-panel`), and
 *                              .seg's own colour goes with it (`text-muted`)
 *   .dz-overlay[hidden]        display none -> flex, so the delete-zone modal
 *                              is permanently open over the settings page
 *                              (loses to `flex`)
 *   a.pill:hover               the hover paint stops arriving at all, because
 *                              the utilities it has to beat (`bg-accent`,
 *                              `border-accent`, `text-accent-ink`) carry no
 *                              hover variant and so apply in every state
 *
 * Marked per declaration rather than per rule: only the properties that
 * actually collide, so the override is exactly as wide as the utility it has
 * to beat. */
.tgl[data-on='1'] {
  background: var(--ok) !important;
}

.tgl[data-on='1']::after {
  transform: translateX(16px);
}

/* settings: the Slack/Discord channel picker. Selected state is attribute
 * driven, and each brand paints its own fill. */
.seg[data-sel='1'] {
  color: var(--accent-ink) !important;
  border-color: transparent !important;
}

.seg-slack[data-sel='1'] {
  background: var(--slack) !important;
}

.seg-discord[data-sel='1'] {
  background: var(--discord) !important;
}

/* settings: delete-zone modal. `[hidden]` has to beat the overlay's own
 * `display: flex`, which a utility cannot guarantee — the engine's own
 * preflight `[hidden]{display:none}` ties with `.flex` on specificity and
 * loses on order, and this rule, being layered, loses to it outright. Hence
 * the mark. */
.dz-overlay[hidden] {
  display: none !important;
}

@keyframes dz-fade {
  from {
    opacity: 0;
  }

  to {
    opacity: 1;
  }
}

@keyframes dz-pop {
  from {
    opacity: 0;
    transform: translateY(6px) scale(0.98);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

/* ---------------------------------------------------------------------------
 * dashboard
 *
 * Moved verbatim from dashboard.stx's <style> block. Every family below is
 * entangled with a selector no utility reaches, so splitting them would have
 * meant half a component in each place:
 *
 *   .pill*        hover/active are tag-scoped (`a.pill:hover, button.pill:hover`)
 *                 on purpose — the disabled pager is a <span class="pill"> and
 *                 must NOT light up on hover.
 *   .log-row      `details[open] > .log-row` has to outrank the hover state.
 *   .search-input ::placeholder and :focus-visible.
 *   .chrome-*     `.chrome-pro, .chrome-pro:hover` cancels .chrome-upgrade's
 *                 hover: Pro is a status, not an action.
 *   summary       bare element selector plus ::-webkit-details-marker.
 *   :focus-visible a bare-element accessibility rule, not optional.
 *   .grain,       data-URI backgrounds with prefers-color-scheme variants.
 *   select.app-panel
 *   .reveal       @keyframes plus a reduced-motion variant.
 *
 * What IS expressible went the other way and is now utilities in the markup:
 * .mono, .wordmark, .wordmark-link, .panel, .lvl-chip, .ctx-pre and .icon-btn.
 * ------------------------------------------------------------------------ */
.pill { border-radius: 999px; transition: color 0.15s ease, border-color 0.15s ease, background-color 0.15s ease, transform 0.12s ease; }
a.pill:hover, button.pill:hover { color: var(--text) !important; border-color: color-mix(in srgb, var(--accent) 45%, var(--border)) !important; background: color-mix(in srgb, var(--accent) 6%, transparent) !important; }
a.pill:active, button.pill:active { transform: translateY(1px); }
/* Filter-tab state. These were inline style ternaries on every tab, which
  outrank the hover rules above and could not be themed. The two levels differ
  because the severity tabs are the primary control and the range tabs are
  secondary. */
.pill-on { color: var(--accent-ink); background: var(--accent); border-color: var(--accent); }
a.pill-on:hover { color: var(--accent-ink); background: var(--accent); border-color: var(--accent); }
.pill-off { color: var(--text-2); border-color: var(--border); }
.pill-on-soft { color: var(--accent); border-color: var(--accent); }
.pill-off-soft { color: var(--text-3); border-color: var(--border); }
.log-row { transition: background-color 0.12s ease; }
.log-row:hover { background: color-mix(in srgb, var(--accent) 4%, transparent); }
details[open] > .log-row { background: color-mix(in srgb, var(--accent) 5%, transparent); }
summary { list-style: none; cursor: pointer; }
summary::-webkit-details-marker { display: none; }
.search-input { background: var(--panel); border: 1px solid var(--border); border-radius: 999px; color: var(--text); outline: none; transition: border-color 0.15s ease; }
.search-input:focus { border-color: color-mix(in srgb, var(--accent) 50%, var(--border)); }
.search-input::placeholder { color: var(--text-3); }
/* Position was an inline style string assembled in JS. It lives here now, so
  the chrome is styleable and themeable like everything else. */
.chrome-logout, .chrome-upgrade { position: fixed; top: 16px; z-index: 60; padding: 8px 13px; border-radius: 9px; font-size: 13px; line-height: 1; font-family: var(--sans, ui-sans-serif); }
.chrome-logout { right: 18px; font-weight: 500; cursor: pointer; border: 1px solid var(--border); background: var(--panel); color: var(--text-2); transition: color 0.15s ease, border-color 0.15s ease; }
.chrome-logout:hover { color: var(--text); border-color: color-mix(in srgb, var(--accent) 45%, var(--border)); }
.chrome-upgrade { right: 112px; font-weight: 600; text-decoration: none; background: var(--accent); color: var(--accent-ink); transition: filter 0.15s ease, transform 0.12s ease; }
.chrome-upgrade:hover { filter: brightness(1.12); }
.chrome-upgrade:active { transform: translateY(1px); }
/* Pro is a status, not an action: no link, no hover lift. */
.chrome-pro, .chrome-pro:hover { background: transparent; color: var(--accent); border: 1px solid var(--accent); cursor: default; filter: none; }
/* The ONLY .reveal in the app. marketing.css carried a second copy with
  different values (0.6s/12px against this one's 0.5s/10px) and a second
  @keyframes of the same name; both sheets load on every marketing page, so the
  marketing copy won there and this one only ever reached the dashboard. These
  are the marketing values, kept because 23 pages used them and one did not. */
.reveal { opacity: 0; transform: translateY(12px); animation: reveal 0.6s cubic-bezier(0.16, 1, 0.3, 1) forwards; }
@keyframes reveal { to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .reveal { animation: none; opacity: 1; transform: none; } }
/* Keyboard focus — a visible ring on every interactive control (accessibility,
  not optional). Search gets an inset ring so it doesn't clash with its pill.

  This rule used to also declare `border-radius: 8px`, which was not a property
  of the ring — it RESHAPED THE ELEMENT for as long as it held focus. Tabbing
  onto a filter tab squared off its 999px pill; the same happened to the pager
  and to every rounded control here, because `a:focus-visible` (0,1,1) outranks
  `.pill` (0,1,0). Nothing about a keyboard user's focus should change an
  element's geometry.

  Nothing replaces it: `outline` has followed the element's own border-radius
  since Chrome 94 / Firefox 88 / Safari 16.4, so the ring is correctly rounded
  on a pill and correctly square on a square control, which is what the 8px was
  reaching for in the first place. */
a:focus-visible, button:focus-visible, summary:focus-visible, select:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
}
summary:focus-visible { outline-offset: -2px; }
.search-input:focus-visible { outline: none; border-color: color-mix(in srgb, var(--accent) 60%, var(--border)); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent); }
/* Physical press feedback on a log row. */
.log-row:active { background: color-mix(in srgb, var(--accent) 9%, transparent); }
/* Log stream aligned as fixed columns: rail · time · level · channel · message. */
.log-row { display: grid; grid-template-columns: 3px 4.75rem 3.75rem 6rem minmax(0, 1fr); align-items: center; column-gap: 0.75rem; }
/* Subtle grain so the flat surfaces don't read as sterile. Fixed, non-blocking,
  barely-there; sits under the floating chrome (z-60). */
.grain { position: fixed; inset: 0; z-index: 5; pointer-events: none; opacity: 0.03;
  background-size: 170px 170px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='170' height='170'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"); }
@media (prefers-reduced-motion: no-preference) { .grain { opacity: 0.032; } }
/* Project dropdown: the native select chevron hugged the rounded border. Reset
  the native appearance and draw our own with a comfortable inset + room for the
  value text. Chevron is themed to --text-3 in each mode. */
select.app-panel {
  -webkit-appearance: none; -moz-appearance: none; appearance: none;
  /* The one declaration here that a utility also sets: the element carries
   * `px-3`, and layered this rule loses to it outright where it used to win
   * on specificity. Measured: padding-right 32px -> 12px, which puts the
   * chevron on top of the project name. The appearance and background
   * properties have no utility on this element and stay unmarked. */
  padding-right: 2rem !important; background-repeat: no-repeat;
  background-position: right 0.7rem center; background-size: 13px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%2397a1b2' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
}
@media (prefers-color-scheme: dark) { select.app-panel { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23667085' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E"); } }

/* Log severity, driven by one data attribute rather than an inline style.
 *
 * The rail and the level badge on a log row both used
 * `style="background: {{ levelColor(entry.level) }}"`, and the stat dot and
 * value used `style="color: {{ s.color }}"` — four inline declarations carrying
 * hex literals computed in the view. `data-level` on the row sets `--sev` once
 * and both children read it, so the colour is named in exactly one place
 * (public/tokens.css) and follows the theme.
 *
 * The default covers a level the server does not recognise: it falls back to
 * the debug tone rather than to no colour, so the rail never disappears. */
[data-level] { --sev: var(--sev-debug); }
[data-level='emergency'], [data-level='alert'], [data-level='critical'] { --sev: var(--sev-critical); }
[data-level='error'] { --sev: var(--sev-error); }
[data-level='warning'] { --sev: var(--sev-warning); }
[data-level='notice'] { --sev: var(--sev-notice); }
[data-level='info'] { --sev: var(--sev-info); }
.log-rail { background: var(--sev); min-height: 20px; }
.log-level { color: var(--sev); background: color-mix(in srgb, var(--sev) 14%, transparent); }
/* One segment of the level-mix bars on /analytics. Reads the same --sev the
 * rail and the chip do, so a colour still means the same severity across the
 * whole app and the analytics page names no palette of its own. */
.level-seg { background: var(--sev); }

/* Stat cards. `data-tone` is set only when the count is non-zero, so an empty
 * warnings/errors card stays neutral — which is what `s.on` expressed inline. */
.stat-dot { background: var(--text-3); opacity: 0.35; }
.stat-value { color: var(--text); }
[data-tone='warning'] .stat-dot { background: var(--sev-warning); opacity: 1; }
[data-tone='warning'] .stat-value { color: var(--sev-warning); }
[data-tone='error'] .stat-dot { background: var(--sev-critical); opacity: 1; }
[data-tone='error'] .stat-value { color: var(--sev-critical); }

/* ---------------------------------------------------------------------------
 * Narrow viewports
 *
 * This sheet had NO width query at all, while marketing.css has four. The app
 * surface is the half that people actually work in, and it was the half with no
 * mobile behaviour — the two rules below are both fixed geometry that a phone
 * cannot satisfy.
 *
 * Everything here adjusts rules THIS FILE owns. It deliberately does not try to
 * override a utility (the page's own `px-5 py-10`, for instance): this sheet is
 * linked before the Crosswind sheet precisely so utilities win a specificity
 * tie, so a `.page-dashboard { padding-top }` here would be silently dead. Any
 * responsive change to a utility-styled element belongs in the markup as an
 * `sm:`/`md:` variant.
 *
 * 40rem rather than a round 375px: the breakpoint is where the content stops
 * fitting, and it is in rem so it also fires for someone at a large default
 * font size on a wider screen, who has the same problem for a different reason.
 * ------------------------------------------------------------------------ */
@media (max-width: 40rem) {
  /* The log stream was a single row of five fixed columns:
   *   3px rail + 4.75rem time + 3.75rem level + 6rem channel
   * plus four 0.75rem gaps and the row's own 20px side padding — 323px spoken
   * for before the message column starts. On a 375px phone that leaves the
   * message 52px, about four characters, on the one line that carries what
   * actually happened. The row was not narrow, it was empty.
   *
   * It becomes two rows: metadata above, message across the full width below.
   * Nothing is dropped — the channel is not repeated in the expanded panel, so
   * hiding it would have lost the only place it appears.
   *
   * Addressed by position because these are bare spans in the markup with no
   * hooks of their own, and the order is fixed by the template: rail, time,
   * level, channel, message. */
  .log-row {
    grid-template-columns: 3px auto auto minmax(0, 1fr);
    column-gap: 0.5rem;
    row-gap: 0.2rem;
  }

  /* The rail spans both rows so it stays one continuous severity stripe beside
   * the whole entry rather than a stub next to the timestamp. */
  .log-row > :nth-child(1) { grid-row: 1 / span 2; }
  .log-row > :nth-child(5) { grid-column: 2 / -1; }

  /* The floating chrome is positioned for a desktop margin: `top: 16px` with
   * 8px padding puts its lower edge at about 46px, and the page's own content
   * starts at 40px. On a wide screen the centred column leaves that gutter
   * empty so nothing shows; on a phone the column is the full width and the
   * header runs underneath the buttons.
   *
   * Smaller and tighter, so the chrome's lower edge lands near 32px and closes
   * the overlap window rather than merely making it less likely. */
  .chrome-logout, .chrome-upgrade {
    top: 10px;
    padding: 5px 10px;
    font-size: 12px;
    border-radius: 8px;
  }

  .chrome-logout { right: 12px; }
  .chrome-upgrade { right: 88px; }
}

}

@layer tc-base {

html:has(meta[name="stx-layout-group"][content="marketing"]) {
  --surface: #ffffff;
  --surface-2: #f4f5f8;
  --border-strong: rgba(15, 23, 42, 0.16);
  --accent-line: rgba(4, 120, 87, 0.34);
  --code-bg: #0b0f19;
  --code-ink: #d6deeb;
  /* Caption ink for the code surface. Not --text-3: the code block is dark;
   * in BOTH themes, so the light --text-3 (#6b7280) lands on it at 3.96:1 —
   * the one WCAG AA failure left after the token pass. This clears 6.37:1 on
   * the light --code-bg and 6.70:1 on the dark one, so it needs no variant. */
  --code-cap: #8b95ab;
  --r: 14px;
  --r-sm: 9px;
  --sans: "Space Grotesk", ui-sans-serif, system-ui, -apple-system, sans-serif;
}

@media (prefers-color-scheme: dark) {
  html:has(meta[name="stx-layout-group"][content="marketing"]) {
    --surface: #10131c; --surface-2: #161a24;
    --border-strong: rgba(148, 163, 184, 0.2);
    --accent-line: rgba(52, 211, 153, 0.32);
    --code-bg: #05070c;
  }
}
html:has(meta[name="stx-layout-group"][content="marketing"])[data-theme="dark"] {
  --surface: #10131c; --surface-2: #161a24;
  --border-strong: rgba(148, 163, 184, 0.2);
  --accent-line: rgba(52, 211, 153, 0.32);
  --code-bg: #05070c;
}
html:has(meta[name="stx-layout-group"][content="marketing"])[data-theme="light"] {
  --surface: #ffffff; --surface-2: #f4f5f8;
  --border-strong: rgba(15, 23, 42, 0.16);
  --accent-line: rgba(4, 120, 87, 0.34);
  --code-bg: #0b0f19;
}

html:has(meta[name="stx-layout-group"][content="marketing"]), html:has(meta[name="stx-layout-group"][content="marketing"]) * { box-sizing: border-box; }
html:has(meta[name="stx-layout-group"][content="marketing"]) { background: var(--bg); scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
html:has(meta[name="stx-layout-group"][content="marketing"]) body {
  margin: 0; min-height: 100vh; overflow-x: hidden;
  color: var(--text); background: var(--bg);
  font-family: var(--sans); font-size: 16px; line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

html:has(meta[name="stx-layout-group"][content="marketing"]) {
a { color: inherit; text-decoration: none; }

.shell { width: min(1180px, calc(100% - 48px)); margin: 0 auto; }
.shell-narrow { width: min(920px, calc(100% - 48px)); margin: 0 auto; }
.mono { font-family: var(--mono); }

/* nav */
.nav {
  position: sticky; top: 0; z-index: 30;
  border-bottom: 1px solid var(--border);
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
}
.nav-inner { display: flex; align-items: center; justify-content: space-between; gap: 1.25rem; min-height: 68px; }
.brand { display: inline-flex; align-items: center; gap: 0.6rem; }
.brand-mark {
  /* Mono for the glyph: Space Grotesk draws lowercase "l" as a bare vertical
     stroke, which reads as a capital "I" at 30px. */
  font-family: var(--mono);
  display: grid; place-items: center; width: 30px; height: 30px;
  border: 1px solid var(--accent-line); border-radius: var(--r-sm);
  color: var(--accent); font-weight: 700; font-size: 1rem; line-height: 1;
}
.brand-name { font-weight: 700; font-size: 1.12rem; letter-spacing: -0.02em; }
.nav-links { display: flex; align-items: center; gap: 1.6rem; margin-left: auto; color: var(--text-2); font-size: 0.9rem; }
.nav-links a { transition: color 0.16s ease; }
.nav-links a:hover { color: var(--text); }
.nav-cta { margin-left: 1.6rem; }

.nav-menu { display: none; margin-left: auto; position: relative; }
.nav-menu > summary {
  list-style: none; display: grid; place-items: center; width: 40px; height: 40px;
  border: 1px solid var(--border-strong); border-radius: var(--r-sm); cursor: pointer;
}
.nav-menu > summary::-webkit-details-marker { display: none; }
.nav-menu > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.burger, .burger::before, .burger::after {
  display: block; width: 18px; height: 1.5px; background: var(--text);
  transition: transform 0.2s ease, opacity 0.2s ease;
}
.burger { position: relative; }
.burger::before { content: ""; position: absolute; top: -5px; }
.burger::after { content: ""; position: absolute; top: 5px; }
.nav-menu[open] .burger { background: transparent; }
.nav-menu[open] .burger::before { transform: translateY(5px) rotate(45deg); }
.nav-menu[open] .burger::after { transform: translateY(-5px) rotate(-45deg); }
.nav-menu-panel {
  position: absolute; right: 0; top: calc(100% + 12px); z-index: 50;
  display: flex; flex-direction: column; gap: 0.25rem; min-width: 232px; padding: 0.6rem;
  max-height: calc(100dvh - 92px); overflow-y: auto; overscroll-behavior: contain;
  background: var(--surface); border: 1px solid var(--border-strong); border-radius: var(--r);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.22);
}
.nav-menu-panel a { padding: 0.6rem 0.7rem; border-radius: var(--r-sm); color: var(--text-2); font-size: 0.95rem; }
.nav-menu-panel a:hover { color: var(--text); background: var(--surface-2); }
.nav-menu-panel .btn { margin-top: 0.35rem; justify-content: center; }

/* buttons */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem;
  min-height: 46px; padding: 0 1.15rem; border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  color: var(--text); font-family: var(--sans); font-weight: 600; font-size: 0.92rem;
  white-space: nowrap; background: transparent; cursor: pointer;
  transition: transform 0.16s ease, border-color 0.16s ease, background 0.16s ease;
}
.btn.sm { min-height: 38px; padding: 0 0.85rem; font-size: 0.86rem; }
.btn.primary { border-color: var(--accent); color: var(--accent-ink); background: var(--accent); }
.btn.primary:hover { background: color-mix(in srgb, var(--accent) 88%, #000); }
.btn.ghost:hover { border-color: var(--accent-line); }
.btn:active { transform: translateY(1px); }

/* section scaffolding */
.section { padding: 3.5rem 0; }
.section-head { max-width: 62ch; margin-bottom: 1.75rem; }
.section-title { margin: 0; font-weight: 700; font-size: clamp(1.6rem, 3.5vw, 2.2rem); letter-spacing: -0.03em; line-height: 1.1; }
.section-intro { margin: 0.9rem 0 0; color: var(--text-2); font-size: 1.02rem; line-height: 1.6; }
.eyebrow { font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--accent); }
.textlink { color: var(--accent); font-weight: 500; }
.textlink:hover { text-decoration: underline; }

/* hero */
.hero { display: grid; grid-template-columns: 1.05fr 1fr; gap: 3.5rem; align-items: center; padding: 3.5rem 0 4rem; }
.hero-title { margin: 0; font-weight: 700; font-size: clamp(2.3rem, 5.4vw, 3.4rem); letter-spacing: -0.035em; line-height: 1.04; }
.hero-sub { margin: 1.25rem 0 0; color: var(--text-2); font-size: 1.08rem; line-height: 1.6; max-width: 54ch; }
.hero-actions { display: flex; flex-wrap: wrap; gap: 0.75rem; margin-top: 2rem; }

/* single-column feature/use-case hero */
.feat-hero { padding: 2.5rem 0 1.5rem; max-width: 62ch; }
.feat-hero .kicker { display: inline-flex; align-items: center; gap: 0.5rem; font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--accent); }
.feat-hero h1 { margin: 1rem 0 0; font-weight: 700; font-size: clamp(2.1rem, 5vw, 3.1rem); line-height: 1.05; letter-spacing: -0.03em; }
.feat-hero p { margin: 1.1rem 0 0; color: var(--text-2); font-size: 1.05rem; line-height: 1.6; }
.feat-hero .hero-actions { margin-top: 1.75rem; }

.subnav { display: flex; align-items: center; gap: 0.5rem; padding-top: 1.75rem; color: var(--text-3); font-size: 0.88rem; }
.subnav a { color: var(--text-2); transition: color 0.16s ease; }
.subnav a:hover { color: var(--text); }
.subnav .sep { color: var(--text-3); }
/* The trail is an <ol> so its order is exposed to assistive tech. The list and
  its items carry the flex layout the nav used to hold directly, so the visual
  result is unchanged. `display: contents` would be shorter and is avoided
  deliberately — several engines drop list items from the accessibility tree
  when it is applied, which would undo the reason for using a list. */
.subnav ol { display: flex; align-items: center; gap: 0.5rem; margin: 0; padding: 0; list-style: none; }
.subnav li { display: flex; align-items: center; gap: 0.5rem; }

/* code panel */
.code { background: var(--code-bg); border: 1px solid var(--border); border-radius: var(--r); overflow: hidden; }
.code-bar { display: flex; align-items: center; gap: 0.6rem; padding: 0.75rem 1rem; border-bottom: 1px solid rgba(148,163,184,0.14); }
.code-body { margin: 0; padding: 1.1rem 1.25rem; overflow-x: auto; font-family: var(--mono); font-size: 12.5px; line-height: 1.65; color: var(--code-ink); }
.chart-cap { font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-3); }
/* Only on the code surface. `.chart-cap` is also used inside `.panel-head`,
  which sits on the normal page surface where --text-3 is the correct token. */
.code-bar .chart-cap { color: var(--code-cap); }

/* panel (data viz container) */
.panel { border: 1px solid var(--border); border-radius: var(--r); background: var(--surface); padding: 1.4rem 1.5rem; }
.panel-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 1rem; }
.panel-tag { font-family: var(--mono); font-size: 0.7rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-3); }
.live { display: inline-flex; align-items: center; gap: 0.5rem; font-size: 0.85rem; color: var(--text-2); }
.live-dot { width: 8px; height: 8px; border-radius: 999px; background: var(--accent); box-shadow: 0 0 0 4px var(--accent-soft); }
.stat-big { margin: 0; font-weight: 700; font-size: 2.6rem; letter-spacing: -0.03em; }
.stat-label { margin: 0.15rem 0 0; color: var(--text-3); font-size: 0.9rem; }

/* trackless bars */
.bar-row { display: grid; grid-template-columns: 148px 1fr 52px; align-items: center; gap: 0.9rem; padding: 0.5rem 0; }
.bar-row + .bar-row { border-top: 1px solid var(--border); }
.bar-label { color: var(--text-2); font-size: 0.88rem; }
.bar-track { height: 8px; border-radius: 999px; background: transparent; }
.bar-fill { display: block; height: 100%; border-radius: 999px; background: var(--accent); opacity: 0.82; min-width: 4px; }
.bar-value { font-family: var(--mono); font-size: 0.82rem; color: var(--text); text-align: right; }

/* stat/severity tiles */
.vitals { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1px; background: var(--border); border: 1px solid var(--border); border-radius: var(--r); overflow: hidden; }
.vital { padding: 1.4rem 1.5rem; background: var(--surface); }
.vital-k { font-family: var(--mono); font-size: 0.78rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-3); }
.vital-v { margin-top: 0.5rem; font-weight: 700; font-size: 1.9rem; letter-spacing: -0.02em; color: var(--text); }
.vital-tag { margin-top: 0.4rem; display: inline-flex; font-size: 0.78rem; color: var(--accent); }

/* numbered flow */
.flow { display: grid; gap: 1px; background: var(--border); border: 1px solid var(--border); border-radius: var(--r); overflow: hidden; }
.flow-step { display: grid; grid-template-columns: auto 1fr; gap: 1.1rem; padding: 1.4rem 1.5rem; background: var(--surface); }
.flow-num { font-family: var(--mono); font-size: 0.82rem; color: var(--accent); padding-top: 0.15rem; }
.flow-step h3 { margin: 0; font-weight: 600; font-size: 1.05rem; letter-spacing: -0.01em; }
.flow-step p { margin: 0.4rem 0 0; color: var(--text-2); font-size: 0.95rem; line-height: 1.55; }

/* metric tiles */
.metrics { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.5rem 2.5rem; }
.metric .m-value { font-weight: 700; font-size: clamp(1.8rem, 4vw, 2.4rem); letter-spacing: -0.02em; color: var(--text); }
.metric .m-label { margin-top: 0.35rem; color: var(--text-2); font-size: 0.9rem; line-height: 1.5; }

/* chips grid */
.chips { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1.5rem; }
.chip { border: 1px solid var(--border); border-radius: var(--r); padding: 1.4rem 1.5rem; background: var(--surface); }
.chip h3 { margin: 0; font-weight: 600; font-size: 1.05rem; letter-spacing: -0.01em; }
.chip p { margin: 0.5rem 0 0; color: var(--text-2); font-size: 0.94rem; line-height: 1.6; }

/* feature bento (landing) */
.bento { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1px; background: var(--border); border: 1px solid var(--border); border-radius: var(--r); overflow: hidden; }
.cell { display: block; padding: 1.5rem 1.6rem; background: var(--surface); transition: background 0.16s ease; }
a.cell { cursor: pointer; }
a.cell:hover { background: var(--surface-2); }
.cell h3 { margin: 0; font-weight: 600; font-size: 1.08rem; letter-spacing: -0.015em; }
.cell p { margin: 0.5rem 0 0; color: var(--text-2); font-size: 0.93rem; line-height: 1.55; }
.cell.lead { grid-column: span 1; }
.cell.tint { background: var(--accent-soft); }
a.cell.tint:hover { background: color-mix(in srgb, var(--accent) 14%, var(--surface)); }
/* Featured bento cell: a soft rose wash (bughq accent) tinted into a corner, so
  the grid has visual variation rather than six identical text cards. */
.cell.feature { background: radial-gradient(120% 140% at 100% 0%, var(--accent-soft), transparent 58%), var(--surface); }
a.cell.feature:hover { background: radial-gradient(120% 140% at 100% 0%, color-mix(in srgb, var(--accent) 16%, transparent), transparent 60%), var(--surface-2); }
.cell.feature h3 { color: var(--accent); }
.cell-more { display: inline-flex; align-items: center; gap: 0.35rem; margin-top: 1rem; font-family: var(--mono); font-size: 0.74rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-3); transition: color 0.16s ease, gap 0.16s ease; }
.cell-more::after { content: "\2192"; }
a.cell:hover .cell-more { color: var(--accent); gap: 0.55rem; }

/* comparison table */
.cmp { display: grid; grid-template-columns: 1.1fr 1fr 1fr; border: 1px solid var(--border); border-radius: var(--r); overflow: hidden; }
.cmp-cell { padding: 1rem 1.2rem; border-top: 1px solid var(--border); background: var(--surface); font-size: 0.92rem; }
.cmp-cell:nth-child(-n+3) { border-top: none; font-weight: 600; }
.cmp-dim { color: var(--text-3); }
.cmp-ghost { color: var(--text); }

/* related features */
.related { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1px; background: var(--border); border: 1px solid var(--border); border-radius: var(--r); overflow: hidden; }
.related a { display: block; padding: 1.3rem 1.4rem; background: var(--surface); transition: background 0.16s ease; }
.related a:hover { background: var(--surface-2); }
.related .r-name { font-weight: 600; font-size: 1rem; color: var(--text); letter-spacing: -0.01em; }
.related .r-desc { margin-top: 0.3rem; color: var(--text-3); font-size: 0.86rem; line-height: 1.45; }

/* use-case cards */
.usecases { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1.5rem; }
.usecase { border: 1px solid var(--border); border-radius: var(--r); overflow: hidden; background: var(--surface); }
.usecase img { display: block; width: 100%; height: 168px; object-fit: cover; }
.usecase-body { padding: 1.4rem 1.5rem 1.6rem; }
.usecase-body h2 { margin: 0; font-weight: 700; font-size: 1.15rem; letter-spacing: -0.02em; }
.usecase-body p { margin: 0.55rem 0 0; color: var(--text-2); font-size: 0.94rem; line-height: 1.6; }
.usecase-body .textlink { margin-top: 0.9rem; display: inline-block; }

/* cta band */
.cta-band { border: 1px solid var(--border); border-radius: var(--r); padding: 2.5rem; background: var(--surface); text-align: center; }
.cta-band h2 { margin: 0 auto; max-width: 30ch; font-weight: 700; font-size: clamp(1.5rem, 3.5vw, 2rem); letter-spacing: -0.03em; }
.cta-actions { display: flex; flex-wrap: wrap; gap: 0.75rem; justify-content: center; margin-top: 1.5rem; }

/* subscribe form
  Sized to the band's own rhythm: the input borrows the .btn min-height so the
  field and its button line up without a magic number, and the row collapses to
  a stack under 30rem rather than squeezing a 40-character field. */
.sub-form { display: flex; flex-wrap: wrap; gap: 0.6rem; justify-content: center; margin: 1.5rem auto 0; max-width: 27rem; }
.sub-field { flex: 1 1 15rem; min-width: 0; min-height: 44px; padding: 0 0.9rem; border: 1px solid var(--border-strong, var(--border)); border-radius: calc(var(--r) - 4px); background: var(--bg); color: var(--text); font: inherit; font-size: 0.95rem; transition: border-color 0.16s ease, box-shadow 0.16s ease; }
.sub-field::placeholder { color: var(--text-3); }
.sub-field:focus-visible { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent); }
/* Defined here rather than assumed from the utility layer: this stylesheet is
  the page's own contract, and a visually-hidden helper that silently is not
  emitted shows up as a stray label sitting above the field. */
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
.sub-note { margin: 0.85rem auto 0; max-width: 40ch; color: var(--text-3); font-size: 0.84rem; line-height: 1.5; }
.sub-note a { color: var(--text-2); text-decoration: underline; text-underline-offset: 2px; }
/* One line, reserved by min-height so a reply does not shift the section. */
.sub-status { margin: 0.85rem auto 0; min-height: 1.25rem; color: var(--text-2); font-size: 0.88rem; }
.sub-status[data-state="error"] { color: var(--accent); }
@media (max-width: 30rem) {
  .sub-form { flex-direction: column; }
  /* A row's 15rem width basis becomes height when the form stacks. */
  .sub-field { flex: none; }
  .sub-form .btn { width: 100%; justify-content: center; }
}

/* footer */
.footer { padding: 2.5rem 0; }
.footer-bottom { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 1rem; padding-top: 1.5rem; border-top: 1px solid var(--border); color: var(--text-3); font-size: 0.88rem; }

/* motion — `.reveal` is NOT declared here.
 *
 * It used to be, and app-chrome.css declared it too: two `.reveal` rules and
 * two identically-named `@keyframes reveal` in two sheets that are both loaded
 * on every marketing page. This file wins on order, so marketing pages animated
 * over 0.6s/12px and the dashboard — the one app page that uses .reveal, and
 * which never loads this file — animated over 0.5s/10px. Nothing intended that
 * split; it was drift between two copies.
 *
 * The single definition lives in app-chrome.css, which is the site-wide sheet,
 * and it carries these values because 23 marketing pages used them against the
 * dashboard's one. A same-named @keyframes in a later sheet REPLACES rather
 * than merges, so the duplicate was also a live footgun: editing the copy here
 * would have silently changed marketing pages only.
 */

/* responsive */
@media (max-width: 900px) {
  body:has(.nav-menu[open]) { overflow: hidden; }
  .hero { grid-template-columns: 1fr; gap: 2rem; padding-top: 2.5rem; }
  .bento, .related, .cmp { grid-template-columns: 1fr; }
  .metrics { grid-template-columns: 1fr 1fr; }
  .chips, .usecases { grid-template-columns: 1fr; }
  .nav-links { display: none; }
  .nav-cta { display: none; }
  .nav-menu { display: block; }
}
@media (max-width: 560px) {
  .metrics, .vitals { grid-template-columns: 1fr; }
  .flow-step { grid-template-columns: 1fr; gap: 0.4rem; }
  .bar-row { grid-template-columns: 120px 1fr 44px; }
}

/* login link beside the Sign up nav button */
.nav-login { color: var(--text-2); font-size: 0.9rem; transition: color 0.16s ease; }
.nav-login:hover { color: var(--text); }
.nav-cta { margin-left: 0.95rem; }

/* CSS-only mega menu, from SiteNav.stx's <style> block. It lives here rather
 * than in the partial because none of what follows is expressible as a
 * utility: two pseudo-elements (the caret and the invisible hover bridge that
 * lets the pointer cross the 14px gap), ancestor-state descendants
 * (`.mega:hover .mega-panel`), a `:not(:first-child)`, and a max-width media
 * query — Crosswind emits nothing for any of them. The leaf styling that IS
 * expressible (.mega-t, .mega-d, the panel links, the menu group's own box)
 * became utilities in the markup and is deliberately absent here.
 *
 * A linked stylesheet is also the router-safe home: the SPA router destroys
 * every <head> style that is not the Crosswind tag on navigation.
 */
.mega { position: relative; display: inline-flex; align-items: center; }
.mega-trigger { display: inline-flex; align-items: center; gap: 0.32rem; cursor: pointer; }
.mega-trigger::after {
  content: "\25BE"; font-size: 0.62em; line-height: 1; color: var(--text-3);
  transition: transform 0.18s ease, color 0.18s ease;
}
.mega:hover .mega-trigger, .mega:focus-within .mega-trigger { color: var(--text); }
.mega:hover .mega-trigger::after, .mega:focus-within .mega-trigger::after { transform: rotate(180deg); color: var(--accent); }

.mega-panel {
  position: absolute; top: 100%; left: 50%; z-index: 50;
  margin-top: 14px;
  display: grid; grid-template-columns: repeat(2, minmax(216px, 1fr)); gap: 0.12rem;
  min-width: 484px; padding: 0.55rem;
  background: var(--surface); border: 1px solid var(--border-strong); border-radius: var(--r);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.22);
  opacity: 0; visibility: hidden; pointer-events: none;
  transform: translateX(-50%) translateY(6px);
  transition: opacity 0.18s ease, transform 0.18s ease, visibility 0.18s ease;
}
.mega-panel::before { content: ""; position: absolute; top: -14px; left: 0; right: 0; height: 14px; }
.mega:hover .mega-panel, .mega:focus-within .mega-panel {
  opacity: 1; visibility: visible; pointer-events: auto;
  transform: translateX(-50%) translateY(0);
}
.nav-menu-group:not(:first-child) { margin-top: 0.35rem; border-top: 1px solid var(--border); }

@media (prefers-reduced-motion: reduce) {
  .mega-trigger::after, .mega-panel { transition: none; }
}
@media (max-width: 900px) {
  /* desktop mega hidden with .nav-links; the <details> menu takes over */
  .mega-panel { display: none; }
}
}

}

@layer tc-base {

.range-tool {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  min-height: 2.25rem;
  padding: 0 0.72rem;
  border: 1px solid var(--border);
  border-radius: 9px;
  background: var(--panel);
  color: var(--text-2);
  font: 600 0.8125rem/1 var(--sans, ui-sans-serif);
  text-decoration: none;
  cursor: pointer;
  transition: color 0.15s ease, border-color 0.15s ease, background-color 0.15s ease, transform 0.15s ease;
}
.range-tool:hover { color: var(--text); border-color: var(--accent); }
.range-tool:active { transform: scale(0.98); }
.range-tool:focus-visible,
.range-link:focus-visible,
.chrome-btn:focus-visible,
.icon-btn:focus-visible,
select.panel:focus-visible,
input:focus-visible,
textarea:focus-visible,
summary:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.range-tool.is-active { color: var(--accent-ink); background: var(--accent); border-color: var(--accent); }
.range-tool i { width: 1rem; height: 1rem; }
.date-menu { position: relative; }
.date-menu > summary { list-style: none; }
.date-menu > summary::-webkit-details-marker { display: none; }
.date-popover {
  position: absolute;
  right: 0;
  top: calc(100% + 0.5rem);
  z-index: 40;
  width: min(44rem, calc(100vw - 2.5rem));
  padding: 0.75rem;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--panel);
  box-shadow: 0 18px 50px color-mix(in srgb, var(--text) 10%, transparent);
}
/* Period picker: presets down the left, two months on the right. The range is
   drawn flat with rounded ends, the way Fathom's is, on the --bar wash the KPI
   bars already use so it reads as the same accent at the same strength. */
.drp-backdrop { position: fixed; inset: 0; z-index: 39; background: transparent; cursor: default; }
.drp { display: grid; grid-template-columns: 10.5rem minmax(0, 1fr); gap: 0.75rem; }
.drp-presets { display: flex; flex-direction: column; gap: 0.15rem; padding-right: 0.75rem; border-right: 1px solid var(--border); }
.drp-preset {
  display: block;
  width: 100%;
  padding: 0.5rem 0.7rem;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--text-2);
  font: 500 0.8125rem/1.2 var(--sans, ui-sans-serif);
  text-align: left;
  cursor: pointer;
}
.drp-preset:hover { color: var(--text); background: color-mix(in srgb, var(--text) 6%, transparent); }
.drp-preset.is-active { color: var(--accent-ink); background: var(--accent); }
.drp-cals { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
.drp-head { display: grid; grid-template-columns: 2rem minmax(0, 1fr) minmax(0, 1fr) 2rem; align-items: center; gap: 0.35rem; margin-bottom: 0.5rem; }
.drp-nav {
  display: inline-grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  border: 1px solid transparent;
  border-radius: 8px;
  background: transparent;
  color: var(--text-2);
  cursor: pointer;
}
.drp-nav:hover { color: var(--text); border-color: var(--border); }
.drp-nav svg { width: 1rem; height: 1rem; }
.drp-nav.is-hidden { visibility: hidden; }
.drp-sel {
  min-width: 0;
  height: 2rem;
  padding: 0 0.5rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg);
  color: var(--text);
  font: 600 0.8125rem/1 var(--sans, ui-sans-serif);
}
.drp-dow, .drp-grid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); }
.drp-dow span { padding: 0.25rem 0; color: var(--text-3); font: 600 0.7rem/1.2 var(--sans, ui-sans-serif); text-align: center; }
.drp-day {
  height: 2.25rem;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--text);
  font: 500 0.8125rem/1 var(--mono, ui-monospace);
  cursor: pointer;
}
.drp-day:hover { background: color-mix(in srgb, var(--accent) 22%, transparent); }
.drp-day.is-out { color: var(--text-3); }
.drp-day.is-today { font-weight: 700; text-decoration: underline; text-underline-offset: 3px; }
.drp-day.is-range { background: var(--accent-soft); }
.drp-day.is-edge { background: var(--accent); color: var(--accent-ink); border-radius: 8px; }
.drp-day.is-disabled { color: var(--text-3); opacity: 0.45; cursor: default; }
.drp-day.is-disabled:hover { background: transparent; }
.drp-day:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; border-radius: 8px; }
@media (max-width: 1023px) {
  .date-menu { position: static; }
  .date-popover { left: 0; right: auto; width: calc(100vw - 2rem); max-height: calc(100dvh - 6rem); overflow-y: auto; overscroll-behavior: contain; }
  .drp { grid-template-columns: minmax(0, 1fr); }
  .drp-presets { flex-direction: row; flex-wrap: wrap; gap: 0.35rem; padding: 0 0 0.6rem; border-right: 0; border-bottom: 1px solid var(--border); }
  .drp-preset { width: auto; padding: 0.45rem 0.65rem; border: 1px solid var(--border); border-radius: 999px; }
  .drp-cals { grid-template-columns: minmax(0, 1fr); }
  .drp-cal.is-right { display: none; }
  .drp-cal.is-left .drp-nav.is-hidden { visibility: visible; }
  .drp-day { height: 2.5rem; }
}

}

.flex {
  display: flex;
}

.items-center {
  align-items: center;
}

.justify-center {
  justify-content: center;
}

.min-h-\[100dvh\] {
  min-height: 100dvh;
}

.max-w-sm {
  max-width: 24rem;
}

.w-full {
  width: 100%;
}

.text-center {
  text-align: center;
}

.text-2xl {
  font-size: 1.5rem;
  line-height: 2rem;
}

.text-sm {
  font-size: 0.875rem;
  line-height: 1.25rem;
}

.text-subtle {
  color: var(--text-3);
}

.block {
  display: block;
}

.font-medium {
  font-weight: 500;
}

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

.text-xs {
  font-size: 0.75rem;
  line-height: 1rem;
}

.justify-between {
  justify-content: space-between;
}

.text-accent {
  color: var(--accent);
}

.gap-2 {
  gap: 0.5rem;
}

.cursor-pointer {
  cursor: pointer;
}

.select-none {
  user-select: none;
}

.h-4 {
  height: 1rem;
}

.w-4 {
  width: 1rem;
}

.accent-\[var\(--accent\)\] {
  accent-color: var(--accent);
}

.inline-flex {
  display: inline-flex;
}

.font-semibold {
  font-weight: 600;
}

.rounded-control {
  border-radius: 10px;
}

.transition-all {
  transition-property: all;
  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
  transition-duration: 150ms;
}

.duration-200 {
  transition-duration: 200ms;
}

.focus\:outline-none:focus {
  outline-style: none;
}

.focus\:ring-2:focus {
  --tc-ring-offset-shadow: var(--tc-ring-inset,) 0 0 0 var(--tc-ring-offset-width, 0px) var(--tc-ring-offset-color, #fff);
  --tc-ring-shadow: var(--tc-ring-inset,) 0 0 0 calc(2px + var(--tc-ring-offset-width, 0px)) var(--tc-ring-color, currentcolor);
  box-shadow: var(--tc-inset-shadow, 0 0 #0000), var(--tc-inset-ring-shadow, 0 0 #0000), var(--tc-ring-offset-shadow, 0 0 #0000), var(--tc-ring-shadow, 0 0 #0000), var(--tc-shadow, 0 0 #0000);
}

.focus\:ring-offset-2:focus {
  --tc-ring-offset-width: 2px;
}

.focus\:ring-offset-panel:focus {
  --tc-ring-offset-color: var(--panel);
}

.focus\:ring-accent:focus {
  --tc-ring-color: var(--accent);
}

.disabled\:opacity-50:disabled {
  opacity: 0.5;
}

.disabled\:cursor-not-allowed:disabled {
  cursor: not-allowed;
}

.disabled\:pointer-events-none:disabled {
  pointer-events: none;
}

.bg-accent-solid {
  background-color: var(--accent);
}

.hover\:bg-accent-solid-hover:hover {
  background-color: color-mix(in srgb, var(--accent) 92%, var(--text));
}

.text-accent-ink {
  color: var(--accent-ink);
}

.shadow-md {
  --tc-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
  --tc-shadow-colored: 0 4px 6px -1px var(--tc-shadow-color), 0 2px 4px -2px var(--tc-shadow-color);
  box-shadow: var(--tc-inset-shadow, 0 0 #0000), var(--tc-inset-ring-shadow, 0 0 #0000), var(--tc-ring-offset-shadow, 0 0 #0000), var(--tc-ring-shadow, 0 0 #0000), var(--tc-shadow, 0 0 #0000);
}

.hover\:shadow-lg:hover {
  --tc-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
  --tc-shadow-colored: 0 10px 15px -3px var(--tc-shadow-color), 0 4px 6px -4px var(--tc-shadow-color);
  box-shadow: var(--tc-inset-shadow, 0 0 #0000), var(--tc-inset-ring-shadow, 0 0 #0000), var(--tc-ring-offset-shadow, 0 0 #0000), var(--tc-ring-shadow, 0 0 #0000), var(--tc-shadow, 0 0 #0000);
}

.gap-1\.5 {
  gap: 0.375rem;
}

.animate-spin {
  animation: spin 1s linear infinite;
}

.opacity-25 {
  opacity: 0.25;
}

.opacity-75 {
  opacity: 0.75;
}

.gap-3 {
  gap: 0.75rem;
}

.text-\[12px\] {
  font-size: 12px;
}

.flex-1 {
  flex: 1 1 0%;
}

.h-px {
  height: 1px;
}

.bg-line {
  background-color: var(--border);
}

.px-5 {
  padding-left: 1.25rem;
  padding-right: 1.25rem;
}

.py-12 {
  padding-top: 3rem;
  padding-bottom: 3rem;
}

.py-2 {
  padding-top: 0.5rem;
  padding-bottom: 0.5rem;
}

.space-y-4 > :not([hidden]) ~ :not([hidden]) {
  --tc-space-y-reverse: 0;
  margin-top: calc(1rem * calc(1 - var(--tc-space-y-reverse)));
  margin-bottom: calc(1rem * var(--tc-space-y-reverse));
}

.px-3\.5 {
  padding-left: 0.875rem;
  padding-right: 0.875rem;
}

.py-2\.5 {
  padding-top: 0.625rem;
  padding-bottom: 0.625rem;
}

.px-3 {
  padding-left: 0.75rem;
  padding-right: 0.75rem;
}

.py-1\.5 {
  padding-top: 0.375rem;
  padding-bottom: 0.375rem;
}

.my-5 {
  margin-top: 1.25rem;
  margin-bottom: 1.25rem;
}

.space-y-2\.5 > :not([hidden]) ~ :not([hidden]) {
  --tc-space-y-reverse: 0;
  margin-top: calc(0.625rem * calc(1 - var(--tc-space-y-reverse)));
  margin-bottom: calc(0.625rem * var(--tc-space-y-reverse));
}

.mb-8 {
  margin-bottom: 2rem;
}

.mt-2 {
  margin-top: 0.5rem;
}

.mb-4 {
  margin-bottom: 1rem;
}

.mb-1\.5 {
  margin-bottom: 0.375rem;
}

.mt-6 {
  margin-top: 1.5rem;
}

@keyframes spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}