/* ==========================================================================
   MASTER-UI-ENGINE — Components
   The canonical stylesheet behind every preview in components/, examples/
   and templates/. Link it after the engine and the markup pastes ready:

     <link rel="stylesheet" href="design-tokens/engine.css">
     <link rel="stylesheet" href="styles/components.css">

   Rules here read design tokens only: no hardcoded colors, durations or
   easings. Re-theme the library by overriding a custom property, re-time it by
   overriding --duration-* / --ease-*, and nothing in this file needs editing.

   Everything is scoped under .page (preview scaffolding) or a component class,
   so linking this sheet never restyles markup in a consuming application.
   Each #region below is a copy unit: styles/mue.js slices these markers so the
   "markup + CSS" clipboard payload contains exactly the block a snippet needs.
   ========================================================================== */

/* #region tokens */
:root {
  --control-h: 2.75rem;          /* 44px: the smallest clickable row in the kit */
  --control-h-sm: 2.25rem;       /* 36px: compact controls, still above WCAG 2.2 AA */
  --control-h-lg: 3.25rem;
  --code-bg: hsl(220 45% 9%);
  --code-fg: hsl(210 30% 84%);
  --code-attr: hsl(160 60% 62%);
  --code-val: hsl(38 92% 62%);
  --hairline: var(--border-light);
}
/* #endregion tokens */

/* #region chrome */
/* Preview page scaffolding. Scope is body.page on purpose: .section and .meta
   are common names, and a consuming app must not inherit them by accident. */
.page {
  margin: 0;
  padding: var(--space-6);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  color: var(--text-primary);
  background: var(--bg-body);
  -webkit-font-smoothing: antialiased;
  transition: background-color var(--duration-base) var(--ease-standard),
    color var(--duration-base) var(--ease-standard);
}
.page .shell {
  max-width: var(--shell-w, 900px);
  margin: 0 auto;
}
.page .masthead,
.page .page-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-3);
  padding: var(--space-2) 0 var(--space-4);
  border-bottom: 1px solid var(--hairline);
  margin-bottom: var(--space-6);
}
.page .brand {
  font-weight: var(--font-bold);
  font-size: var(--text-xl);
  letter-spacing: var(--tracking-tight);
  color: var(--text-primary);
}
.page .meta {
  font-size: var(--text-sm);
  color: var(--text-secondary);
}
.page h1 {
  font-family: var(--font-display);
  font-size: var(--text-3xl);
  font-weight: var(--font-bold);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
  margin: 0 0 var(--space-2);
}
.page .subtitle {
  color: var(--text-secondary);
  font-size: var(--text-lg);
  line-height: var(--leading-relaxed);
  margin: 0 0 var(--space-8);
  max-width: 60ch;
}
.page .section {
  margin-bottom: var(--space-12);
  /* The #sections primitives carry their own vertical rhythm. A preview page
     is not a marketing page, so the chrome block opts out of it. */
  --section-pad-y: 0;
  --section-pad-x: 0;
}
/* A marketing demo nests the real primitive inside that block, so the opt-out
   has to stop here: "initial" makes --section-pad-* guaranteed-invalid again and
   the fallback in #sections takes over. */
.page .section .section {
  --section-pad-y: initial;
  --section-pad-x: initial;
}
.page .section h2 {
  font-size: var(--text-xl);
  font-weight: var(--font-semibold);
  letter-spacing: var(--tracking-tight);
  margin: 0 0 var(--space-2);
}
.page .section > h3 {
  font-size: var(--text-base);
  font-weight: var(--font-semibold);
  margin: 0 0 var(--space-2);
}
.page .section > p {
  color: var(--text-secondary);
  font-size: var(--text-sm);
  margin: 0 0 var(--space-4);
  max-width: 68ch;
}
.page .demo-area {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-5);
  border: 1px dashed var(--border-medium);
  border-radius: var(--radius-md);
  background: var(--bg-surface);
}
.page .meta-card {
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md);
  padding: var(--space-4) var(--space-5);
  margin-bottom: var(--space-8);
  background: var(--bg-surface);
  box-shadow: var(--shadow-xs);
}
.theme-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 2.25rem;
  padding: var(--space-1) var(--space-4);
  background: var(--bg-surface-hover);
  color: var(--text-primary);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-full);
  font: inherit;
  font-size: var(--text-sm);
  cursor: pointer;
  transition: var(--motion-colors), transform var(--duration-tick) var(--ease-exit);
}
.theme-toggle:hover {
  border-color: var(--border-medium);
  background: var(--bg-surface-active);
}
.theme-toggle:active {
  transform: scale(0.98);
}
.theme-toggle .dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--primary-bg);
  transition: background-color var(--duration-fast) var(--ease-standard),
    box-shadow var(--duration-fast) var(--ease-standard);
}
html.dark .theme-toggle .dot {
  background: hsl(var(--color-primary-400));
  box-shadow: 0 0 0 3px hsla(var(--color-primary-400) / 0.25);
}
/* Code panel: a literal dark surface in both themes, which is what a reader
   expects and what keeps the syntax colors legible without extra overrides. */
.code-wrap {
  margin-top: var(--space-6);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--code-bg);
}
.code-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3) var(--space-2) var(--space-4);
  background: hsl(220 40% 13%);
  color: hsl(210 25% 78%);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  border-bottom: 1px solid hsl(220 30% 20%);
}
.code-wrap pre {
  margin: 0;
  padding: var(--space-4);
  overflow: auto;
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  line-height: var(--leading-relaxed);
  color: var(--code-fg);
  -webkit-text-size-adjust: none;
}
.code-wrap .hl-attr {
  color: var(--code-attr);
}
.code-wrap .hl-val {
  color: var(--code-val);
}
.copy-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-height: var(--control-h-sm);
  padding: 0 var(--space-3);
  font: inherit;
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide);
  text-transform: none;
  color: hsl(210 25% 88%);
  background: hsl(220 30% 22%);
  border: 1px solid hsl(220 25% 32%);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: var(--motion-colors), transform var(--duration-tick) var(--ease-exit);
}
.copy-btn:hover {
  background: hsl(220 30% 28%);
  border-color: hsl(220 25% 45%);
}
.copy-btn:active {
  transform: translateY(1px);
}
.copy-btn[data-state="done"] {
  color: var(--code-attr);
  border-color: hsla(var(--color-accent-400) / 0.6);
}
.copy-btn[data-state="error"] {
  color: var(--code-val);
  border-color: hsla(var(--color-warning-500) / 0.6);
}
.copy-btn:focus-visible {
  outline: 2px solid hsl(var(--color-primary-400));
  outline-offset: 2px;
}
@media (max-width: 640px) {
  .page {
    padding: var(--space-4);
  }
  .page h1 {
    font-size: var(--text-2xl);
  }
  .page .subtitle {
    font-size: var(--text-base);
    margin-bottom: var(--space-6);
  }
  .page .section {
    margin-bottom: var(--space-8);
  }
}
/* #endregion chrome */

/* #region buttons */
.btn,
.btn-primary,
.btn-secondary,
.btn-outline,
.btn-ghost,
.btn-danger,
.btn-success,
.btn-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: var(--control-h);
  padding: 0 var(--space-5);
  font-family: inherit;
  font-size: var(--text-base);
  font-weight: var(--font-medium);
  line-height: var(--leading-none);
  letter-spacing: var(--tracking-normal);
  white-space: nowrap;
  border: 1px solid transparent;
  border-radius: var(--radius-base);
  cursor: pointer;
  text-decoration: none;
  user-select: none;
  transition: var(--motion-colors), transform var(--duration-tick) var(--ease-exit),
    box-shadow var(--duration-fast) var(--ease-standard);
}
.btn:focus-visible,
.btn-primary:focus-visible,
.btn-secondary:focus-visible,
.btn-outline:focus-visible,
.btn-ghost:focus-visible,
.btn-danger:focus-visible,
.btn-success:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
  box-shadow: var(--ring-focus);
}
.btn:active:not(:disabled),
.btn-primary:active:not(:disabled),
.btn-secondary:active:not(:disabled),
.btn-outline:active:not(:disabled),
.btn-ghost:active:not(:disabled),
.btn-danger:active:not(:disabled) {
  transform: translateY(var(--press-depth));
}
.btn:disabled,
.btn-primary:disabled,
.btn-secondary:disabled,
.btn-outline:disabled,
.btn-ghost:disabled,
.btn-danger:disabled,
.btn[aria-disabled="true"] {
  opacity: 0.5;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}
.btn-primary {
  background: var(--primary-bg);
  color: var(--primary-fg);
  box-shadow: var(--shadow-xs);
}
.btn-primary:hover:not(:disabled) {
  background: var(--primary-hover);
  box-shadow: var(--shadow-sm);
  transform: translateY(var(--lift-hover-sm));
}
.btn-primary:active:not(:disabled) {
  background: var(--primary-active);
}
.btn-secondary {
  background: var(--secondary-bg);
  color: var(--secondary-fg);
}
.btn-secondary:hover:not(:disabled) {
  background: var(--secondary-hover);
}
.btn-outline {
  background: var(--outline-bg);
  color: var(--outline-fg);
  border-color: var(--outline-border);
}
.btn-outline:hover:not(:disabled) {
  background: var(--outline-hover);
  border-color: var(--border-dark);
}
.btn-ghost {
  background: var(--ghost-bg);
  color: var(--ghost-fg);
}
.btn-ghost:hover:not(:disabled) {
  background: var(--ghost-hover);
}
.btn-danger {
  background: var(--danger-bg);
  color: var(--danger-fg);
}
.btn-danger:hover:not(:disabled) {
  background: var(--danger-hover);
  box-shadow: var(--shadow-sm);
}
.btn-success {
  background: hsl(var(--color-success-500));
  color: var(--text-inverse);
}
.btn-success:hover:not(:disabled) {
  filter: brightness(1.08);
}
.btn-link {
  background: none;
  border-color: transparent;
  color: var(--text-link);
  text-decoration: underline;
  text-underline-offset: 3px;
  padding-inline: 0;
  /* Text-weight of a link, target height of a control. */
  min-height: 2rem;
}
.btn-link:hover:not(:disabled) {
  color: var(--text-link-hover);
}
.btn-sm {
  min-height: var(--control-h-sm);
  padding: 0 var(--space-4);
  font-size: var(--text-sm);
  border-radius: var(--radius-sm);
}
.btn-lg {
  min-height: var(--control-h-lg);
  padding: 0 var(--space-6);
  font-size: var(--text-lg);
  border-radius: var(--radius-md);
}
.btn-icon {
  width: var(--control-h);
  min-height: var(--control-h);
  padding: 0;
  border-radius: var(--radius-md);
}
.btn-icon.btn-sm {
  width: var(--control-h-sm);
  min-height: var(--control-h-sm);
}
.btn-icon.btn-lg {
  width: var(--control-h-lg);
  min-height: var(--control-h-lg);
}
.btn-icon svg {
  width: 1.125rem;
  height: 1.125rem;
  flex: none;
}
.btn-block {
  width: 100%;
}
.btn-row,
.btn-stack {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}
.btn-stack {
  flex-direction: column;
  align-items: stretch;
}
/* Loading: the shimmer sweeps over the label, the button keeps its width so
   neighbouring controls do not jump when a request starts. */
.loading {
  position: relative;
  overflow: hidden;
  cursor: progress;
}
.loading > .bar {
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: hsla(var(--color-white) / 0.28);
  animation: mue-sweep calc(var(--duration-slowest) * 1.6) var(--ease-in-out) infinite;
}
@keyframes mue-sweep {
  100% {
    transform: translateX(100%);
  }
}
.spinner {
  width: 1.125rem;
  height: 1.125rem;
  flex: none;
  border: 2px solid hsla(var(--color-white) / 0.35);
  border-top-color: currentColor;
  border-radius: 50%;
  animation: mue-spin calc(var(--duration-slowest) * 1.4) var(--ease-linear) infinite;
}
@keyframes mue-spin {
  to {
    transform: rotate(360deg);
  }
}
@media (max-width: 640px) {
  .btn-row--stack {
    flex-direction: column;
    align-items: stretch;
  }
  .btn-row--stack > .btn,
  .btn-row--stack > .btn-primary,
  .btn-row--stack > .btn-outline {
    width: 100%;
  }
}
@media (hover: none) {
  /* No hover state on touch, so lift the tap target instead. */
  .btn,
  .btn-primary,
  .btn-secondary,
  .btn-outline,
  .btn-ghost,
  .btn-danger {
    min-height: var(--control-h-lg);
  }
}
/* #endregion buttons */

/* #region fields */
.field {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-width: 0;
}
.field-label {
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  color: var(--text-primary);
}
.input,
.field input,
.field textarea,
.field select {
  width: 100%;
  min-width: 0;
  min-height: var(--control-h);
  padding: var(--space-2) var(--space-3);
  font: inherit;
  font-size: var(--text-base);
  color: var(--text-primary);
  background: var(--bg-surface);
  border: 1px solid var(--border-medium);
  border-radius: var(--radius-base);
  transition: var(--motion-colors), box-shadow var(--duration-fast) var(--ease-standard);
  appearance: none;
}
.field textarea {
  min-height: 6.5rem;
  resize: vertical;
  line-height: var(--leading-relaxed);
}
.field input::placeholder,
.field textarea::placeholder {
  color: var(--text-tertiary);
  opacity: 1;
}
.field input:hover,
.field textarea:hover,
.field select:hover {
  border-color: var(--border-dark);
}
.field input:focus-visible,
.field textarea:focus-visible,
.field select:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: 1px;
  border-color: var(--border-focus);
  box-shadow: var(--ring-focus);
}
.field input:disabled,
.field textarea:disabled,
.field select:disabled {
  background: var(--bg-surface-hover);
  color: var(--text-secondary);
  cursor: not-allowed;
}
.field-helper {
  font-size: var(--text-sm);
  color: var(--text-secondary);
}
.field.is-error input,
.field.is-error select,
.field.is-error textarea,
.field .input-error {
  border-color: hsl(var(--color-error-500));
}
.field.is-error .field-helper {
  color: var(--text-error);
}
.field-msg {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--text-sm);
  color: var(--text-secondary);
  min-height: 1.25rem;
  transition: color var(--duration-fast) var(--ease-standard);
}
.field.is-error .field-msg {
  color: var(--text-error);
}
.input-group {
  display: flex;
  align-items: stretch;
  min-width: 0;
  gap: var(--space-2);
}
.input-icon {
  position: relative;
  flex: 1;
  min-width: 0;
}
.input-icon svg {
  position: absolute;
  top: 50%;
  left: var(--space-3);
  transform: translateY(-50%);
  width: 1.125rem;
  height: 1.125rem;
  color: var(--text-tertiary);
  pointer-events: none;
}
.input-icon input {
  padding-left: 2.75rem;
}
.addon {
  display: inline-flex;
  align-items: center;
  padding: 0 var(--space-3);
  background: var(--bg-surface-hover);
  border: 1px solid var(--border-medium);
  border-radius: var(--radius-base);
  color: var(--text-secondary);
  font-size: var(--text-sm);
  white-space: nowrap;
}

/* The engine resets appearance on selects, so the chevron is drawn here. */
.select-wrap {
  position: relative;
  min-width: 0;
}
.select-wrap select {
  padding-right: 2.75rem;
}
.select-wrap svg {
  position: absolute;
  top: 50%;
  right: var(--space-3);
  transform: translateY(-50%);
  width: 1.125rem;
  height: 1.125rem;
  color: var(--text-tertiary);
  pointer-events: none;
  transition: color var(--duration-instant) var(--ease-standard);
}
.select-wrap:focus-within svg {
  color: var(--border-focus);
}
.field.is-success input,
.field.is-success select,
.field.is-success textarea {
  border-color: hsl(var(--color-success-500));
}
.field.is-success .field-msg {
  color: var(--text-success);
}
/* Native picker glyphs are dark-on-light in Chrome; re-tint them for dark mode. */
input[type="date"],
input[type="time"] {
  min-width: 0;
  max-width: 100%;
}
input[type="date"]::-webkit-calendar-picker-indicator,
input[type="time"]::-webkit-calendar-picker-indicator {
  cursor: pointer;
  opacity: 0.55;
  transition: opacity var(--duration-instant) var(--ease-standard);
}
input[type="date"]::-webkit-calendar-picker-indicator:hover,
input[type="time"]::-webkit-calendar-picker-indicator:hover {
  opacity: 1;
}
html.dark input[type="date"]::-webkit-calendar-picker-indicator,
html.dark input[type="time"]::-webkit-calendar-picker-indicator {
  filter: invert(1);
  opacity: 0.7;
}
/* #endregion fields */

/* #region choice */
.checkbox,
.radio {
  position: relative;
  display: inline-flex;
  align-items: flex-start;
  gap: var(--space-3);
  min-height: var(--control-h);
  padding: var(--space-2) 0;
  cursor: pointer;
  font-size: var(--text-base);
  color: var(--text-primary);
  user-select: none;
}
.checkbox input,
.radio input {
  position: absolute;
  inset: 0;
  width: 1.25rem;
  height: 1.25rem;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}
.checkbox .box,
.radio .box {
  position: relative;
  flex: none;
  width: 1.25rem;
  height: 1.25rem;
  margin-top: 2px;
  background: var(--bg-surface);
  border: 1.5px solid var(--border-dark);
  border-radius: var(--radius-sm);
  transition: var(--motion-colors), transform var(--duration-fast) var(--ease-spring);
}
.radio .box {
  border-radius: 50%;
}
.checkbox:hover .box,
.radio:hover .box {
  border-color: var(--border-focus);
}
.checkbox input:checked + .box,
.radio input:checked + .box {
  background: var(--primary-bg);
  border-color: var(--primary-bg);
}
.checkbox .box svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  padding: 2px;
  color: var(--primary-fg);
  stroke: currentColor;
  fill: none;
  stroke-width: 3;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0;
  transform: scale(0.6);
  transition: opacity var(--duration-fast) var(--ease-enter),
    transform var(--duration-base) var(--ease-spring);
}
.checkbox input:checked + .box svg {
  opacity: 1;
  transform: scale(1);
}
.radio .box::after {
  content: "";
  position: absolute;
  inset: 3px;
  border-radius: 50%;
  background: var(--primary-fg);
  opacity: 0;
  transform: scale(0.4);
  transition: opacity var(--duration-fast) var(--ease-enter),
    transform var(--duration-base) var(--ease-spring);
}
.radio input:checked + .box::after {
  opacity: 1;
  transform: scale(1);
}
.checkbox input:focus-visible + .box,
.radio input:focus-visible + .box {
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
  box-shadow: var(--ring-focus);
}
.checkbox input:disabled + .box,
.radio input:disabled + .box {
  opacity: 0.5;
  cursor: not-allowed;
}
.radiogroup,
.checkbox-group {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
.switch {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  min-height: var(--control-h);
  cursor: pointer;
  color: var(--text-primary);
}
.switch input {
  position: absolute;
  inset: 0;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}
.switch .track {
  position: relative;
  flex: none;
  width: 2.75rem;
  height: 1.5rem;
  background: var(--bg-surface-active);
  border: 1px solid var(--border-medium);
  border-radius: var(--radius-full);
  transition: background-color var(--duration-base) var(--ease-standard),
    border-color var(--duration-base) var(--ease-standard);
}
.switch .track::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 1.125rem;
  height: 1.125rem;
  border-radius: 50%;
  background: var(--bg-surface);
  box-shadow: var(--shadow-sm);
  transition: transform var(--duration-base) var(--ease-spring);
}
.switch input:checked + .track {
  background: var(--primary-bg);
  border-color: var(--primary-bg);
}
.switch input:checked + .track::after {
  transform: translateX(1.25rem);
}
.switch input:focus-visible + .track {
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
  box-shadow: var(--ring-focus);
}
.switch input:active + .track::after {
  transform: scale(var(--focus-scale));
}
.switch input:checked:active + .track::after {
  transform: translateX(1.25rem) scale(var(--focus-scale));
}
.switch-label {
  font-size: var(--text-sm);
  color: var(--text-secondary);
}
.slider {
  width: 100%;
  min-width: 0;
  height: 1.5rem;
  margin: 0;
  background: none;
  appearance: none;
  cursor: pointer;
}
.slider::-webkit-slider-runnable-track {
  height: 4px;
  border-radius: var(--radius-full);
  background: var(--bg-surface-active);
}
.slider::-moz-range-track {
  height: 4px;
  border-radius: var(--radius-full);
  background: var(--bg-surface-active);
}
.slider::-webkit-slider-thumb {
  appearance: none;
  width: 1.125rem;
  height: 1.125rem;
  margin-top: -0.5rem;
  border: 2px solid var(--primary-bg);
  border-radius: 50%;
  background: var(--bg-surface);
  box-shadow: var(--shadow-sm);
  transition: transform var(--duration-fast) var(--ease-spring),
    box-shadow var(--duration-fast) var(--ease-standard);
}
.slider::-moz-range-thumb {
  width: 1.125rem;
  height: 1.125rem;
  border: 2px solid var(--primary-bg);
  border-radius: 50%;
  background: var(--bg-surface);
}
.slider:hover::-webkit-slider-thumb,
.slider:focus-visible::-webkit-slider-thumb {
  transform: scale(1.15);
  box-shadow: var(--ring-focus);
}

.checkbox input:disabled ~ span,
.radio input:disabled ~ span,
.switch input:disabled + .track,
.switch input:disabled ~ .switch-label {
  opacity: 0.55;
  cursor: not-allowed;
}
/* #endregion choice */

/* #region cards */
.card {
  display: flex;
  flex-direction: column;
  min-width: 0;
  background: var(--bg-surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-xs);
  overflow: hidden;
  transition: var(--motion-lift);
}
.card-body {
  padding: var(--space-5);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-width: 0;
}
.card-title {
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: var(--font-semibold);
  letter-spacing: var(--tracking-tight);
  color: var(--text-primary);
  margin: 0;
}
.card-desc,
.card-text {
  font-size: var(--text-sm);
  line-height: var(--leading-relaxed);
  color: var(--text-secondary);
  margin: 0;
}
.card-head,
.card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--hairline);
}
.card-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-4) var(--space-5);
  border-top: 1px solid var(--hairline);
  margin-top: auto;
}
.card-media {
  position: relative;
  overflow: hidden;
  aspect-ratio: 16 / 10;
  background: var(--bg-surface-hover);
}
.card-media img,
.card-media svg {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--duration-slower) var(--ease-soft);
}
.card-tag {
  align-self: flex-start;
  font-size: var(--text-xs);
  font-weight: var(--font-medium);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text-link);
}
.card-elevated {
  border-color: transparent;
  box-shadow: var(--shadow-base);
}
.card-outlined {
  box-shadow: none;
  border-color: var(--border-medium);
}
.card-interactive,
a.card,
.card[href],
.card[role="button"] {
  cursor: pointer;
}
.card-interactive:hover,
a.card:hover,
.card[href]:hover,
.card[role="button"]:hover {
  transform: translateY(var(--lift-hover));
  box-shadow: var(--shadow-md);
  border-color: var(--border-medium);
}
.card-interactive:hover .card-media img,
a.card:hover .card-media img {
  transform: scale(var(--pop-scale));
}
.card-interactive:focus-visible,
a.card:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: 3px;
}
.card-interactive.is-selected,
.card[aria-pressed="true"] {
  border-color: var(--primary-bg);
  box-shadow: var(--ring-focus);
}

.card-featured {
  border-color: var(--primary-bg);
  box-shadow: var(--shadow-base);
}
.price {
  font-size: var(--text-lg);
  font-weight: var(--font-bold);
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}
/* #endregion cards */

/* #region badges */
.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 0.125rem var(--space-2);
  font-size: var(--text-xs);
  font-weight: var(--font-medium);
  line-height: 1.5;
  letter-spacing: var(--tracking-wide);
  border-radius: var(--radius-full);
  background: var(--tint-neutral);
  color: var(--text-primary);
  white-space: nowrap;
  transition: var(--motion-colors);
}
.badge .dot,
.dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  flex: none;
}
/* Opaque mixes, not translucent tints: a tint laid over an already-tinted
   surface composites to a background too close to its own text colour. */
.badge-primary {
  background: color-mix(in srgb, var(--text-link) 14%, var(--bg-surface));
  color: var(--text-link);
}
.badge-success {
  background: color-mix(in srgb, var(--text-success) 14%, var(--bg-surface));
  color: var(--text-success);
}
.badge-warning {
  background: color-mix(in srgb, var(--text-warning) 14%, var(--bg-surface));
  color: var(--text-warning);
}
.badge-error,
.badge-danger {
  background: color-mix(in srgb, var(--text-error) 14%, var(--bg-surface));
  color: var(--text-error);
}
.badge-info {
  background: color-mix(in srgb, var(--text-info) 14%, var(--bg-surface));
  color: var(--text-info);
}
.badge-solid {
  background: var(--primary-bg);
  color: var(--primary-fg);
}
.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-height: var(--control-h-sm);
  padding: 0 var(--space-3);
  font-size: var(--text-sm);
  color: var(--text-primary);
  background: var(--bg-surface);
  border: 1px solid var(--border-medium);
  border-radius: var(--radius-full);
  cursor: pointer;
  transition: var(--motion-colors);
}
.chip:hover,
.chip[aria-pressed="true"] {
  border-color: var(--primary-bg);
  background: var(--tint-primary);
  color: var(--text-link);
}
/* #endregion badges */

/* #region tabs */
.tabs {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  min-width: 0;
}
.tab-list,
.tabs [role="tablist"] {
  position: relative;
  display: flex;
  gap: var(--space-1);
  border-bottom: 1px solid var(--hairline);
  overflow-x: auto;
  scrollbar-width: thin;
}
.tab {
  position: relative;
  flex: none;
  min-height: var(--control-h);
  padding: 0 var(--space-4);
  font: inherit;
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  color: var(--text-secondary);
  background: none;
  border: 0;
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
  cursor: pointer;
  white-space: nowrap;
  transition: var(--motion-colors);
}
.tab::after {
  content: "";
  position: absolute;
  left: var(--space-2);
  right: var(--space-2);
  bottom: -1px;
  height: 2px;
  border-radius: var(--radius-full);
  background: var(--primary-bg);
  transform: scaleX(0);
  transform-origin: center;
  transition: transform var(--duration-base) var(--ease-soft);
}
.tab:hover {
  color: var(--text-primary);
  background: var(--bg-surface-hover);
}
.tab[aria-selected="true"],
.tab.active {
  color: var(--text-link);
}
.tab[aria-selected="true"]::after,
.tab.active::after {
  transform: scaleX(1);
}
.tab:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: -2px;
}
.tab-panel[hidden] {
  display: none;
}
.tab-panel {
  animation: mue-fade-in var(--duration-slow) var(--ease-enter);
  font-size: var(--text-sm);
  color: var(--text-secondary);
}
@keyframes mue-fade-in {
  from {
    opacity: 0;
    transform: translateY(calc(var(--reveal-shift) / 2));
  }
}
.pills,
.segmented {
  display: inline-flex;
  gap: var(--space-1);
  padding: var(--space-1);
  background: var(--bg-surface-hover);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-full);
}
.pills .tab {
  border-radius: var(--radius-full);
  min-height: 2.25rem;
}
.pills .tab::after {
  display: none;
}
.pills .tab[aria-selected="true"],
.pills .tab.active {
  background: var(--bg-surface);
  color: var(--text-primary);
  box-shadow: var(--shadow-xs);
}
/* #endregion tabs */

/* #region navigation */
.navbar,
.site-header {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: var(--space-4);
  min-height: 4rem;
  padding: 0 var(--space-6);
  background: var(--bg-surface);
  border-bottom: 1px solid var(--hairline);
  box-shadow: var(--shadow-xs);
  transition: box-shadow var(--duration-base) var(--ease-standard),
    background-color var(--duration-base) var(--ease-standard);
}
.navbar.is-scrolled {
  box-shadow: var(--shadow-sm);
}
.nav-brand {
  font-weight: var(--font-bold);
  letter-spacing: var(--tracking-tight);
  color: var(--text-primary);
  text-decoration: none;
  white-space: nowrap;
}
.nav-links {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  list-style: none;
  margin: 0;
  padding: 0;
}
/* The row that opens a menu is a <button>, and a button with no declared
   background wears the UA control face — color-scheme: dark paints that as a
   grey block no token owns, which fails contrast against the link colour. */
.nav-link,
.nav-item > a {
  display: inline-flex;
  align-items: center;
  min-height: var(--control-h);
  padding: 0 var(--space-3);
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  color: var(--text-secondary);
  background: transparent;
  text-decoration: none;
  border-radius: var(--radius-base);
  transition: var(--motion-colors);
}
.nav-link:hover,
.nav-item > a:hover {
  color: var(--text-primary);
  background: var(--bg-surface-hover);
}
.nav-link[aria-current="page"],
.nav-link.active {
  color: var(--text-link);
  background: var(--tint-primary);
}
.nav-link:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
}
.nav-spacer {
  flex: 1;
  min-width: 0;
}
/* Pages cap the search with --nav-search-max-w rather than restating the
   rule, which is what two starters were doing. */
.nav-search {
  flex: 1;
  min-width: 0;
  max-width: var(--nav-search-max-w, 22rem);
}
.hamburger {
  display: none;
  place-items: center;
  width: var(--control-h);
  height: var(--control-h);
  background: none;
  border: 1px solid var(--border-medium);
  border-radius: var(--radius-base);
  color: var(--text-primary);
  cursor: pointer;
  transition: var(--motion-colors);
}
.hamburger:hover {
  background: var(--bg-surface-hover);
}
.breadcrumbs {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: var(--text-sm);
  color: var(--text-secondary);
}
.breadcrumbs a {
  color: var(--text-secondary);
  text-decoration: none;
  padding: var(--space-1) 0;
  transition: var(--motion-colors);
}
.breadcrumbs a:hover {
  color: var(--text-link);
}
.breadcrumbs .separator,
.breadcrumbs li[aria-hidden="true"] {
  color: var(--text-tertiary);
}
.breadcrumbs [aria-current="page"] {
  color: var(--text-primary);
  font-weight: var(--font-medium);
}
.pagination {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1);
  list-style: none;
  margin: 0;
  padding: 0;
}
.pagination a,
.pagination button {
  display: inline-grid;
  place-items: center;
  min-width: var(--control-h);
  height: var(--control-h);
  padding: 0 var(--space-2);
  font: inherit;
  font-size: var(--text-sm);
  color: var(--text-secondary);
  background: var(--bg-surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-base);
  cursor: pointer;
  text-decoration: none;
  transition: var(--motion-colors), transform var(--duration-tick) var(--ease-exit);
}
.pagination a:hover,
.pagination button:hover:not(:disabled) {
  color: var(--text-primary);
  border-color: var(--border-medium);
  background: var(--bg-surface-hover);
}
.pagination a:active {
  transform: translateY(var(--press-depth));
}
.pagination [aria-current="true"],
.pagination .active a,
.pagination .active button {
  color: var(--primary-fg);
  background: var(--primary-bg);
  border-color: var(--primary-bg);
  font-weight: var(--font-semibold);
}
.pagination :disabled {
  opacity: 0.45;
  cursor: not-allowed;
}
@media (max-width: 768px) {
  .navbar,
  .site-header {
    padding: 0 var(--space-4);
  }
  .hamburger {
    display: grid;
  }
  .nav-links {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    display: none;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: var(--space-3) var(--space-4);
    background: var(--bg-surface);
    border-bottom: 1px solid var(--hairline);
    box-shadow: var(--shadow-md);
  }
  .nav-links.is-open,
  .nav-links.open {
    display: flex;
    animation: mue-drop-in var(--duration-slow) var(--ease-enter);
  }
  .nav-links li {
    border-bottom: 1px solid var(--hairline);
  }
  .nav-links li:last-child {
    border-bottom: 0;
  }
  .nav-link {
    width: 100%;
  }
}

.pagination .ellipsis {
  display: inline-grid;
  place-items: center;
  min-width: var(--control-h);
  height: var(--control-h);
  color: var(--text-tertiary);
  font-size: var(--text-sm);
}

/* The brand row and the action row need to share a line down to 768px, but the
   sticky bar cannot stay one line at 375px: let it wrap instead of clipping. */
@media (max-width: 768px) {
  .navbar,
  .site-header {
    flex-wrap: wrap;
    row-gap: var(--space-2);
    padding-block: var(--space-3);
  }
}
/* #endregion navigation */

/* #region sidebar */
.sidebar {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  width: var(--sidebar-w, 16rem);
  flex: none;
  padding: var(--space-5) var(--space-4);
  background: var(--bg-surface);
  border-right: 1px solid var(--hairline);
  min-width: 0;
  transition: width var(--duration-slow) var(--ease-soft);
}
.sidebar-section {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  min-width: 0;
}
.sidebar-heading {
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--text-tertiary);
  padding: 0 var(--space-3) var(--space-1);
}
.sidebar-link,
.sidebar-item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: var(--control-h);
  padding: 0 var(--space-3);
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  color: var(--text-secondary);
  text-decoration: none;
  border: 0;
  border-radius: var(--radius-base);
  background: none;
  cursor: pointer;
  transition: var(--motion-colors);
}
.sidebar-link:hover,
.sidebar-item:hover {
  color: var(--text-primary);
  background: var(--bg-surface-hover);
}
.sidebar-link.active,
.sidebar-link[aria-current="page"] {
  color: var(--text-link);
  background: var(--tint-primary);
}
.sidebar-link svg,
.sidebar-item svg {
  width: 1.125rem;
  height: 1.125rem;
  flex: none;
}
.sidebar-label {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
@media (max-width: 900px) {
  .sidebar {
    width: 100%;
    border-right: 0;
    border-bottom: 1px solid var(--hairline);
  }
}

.sidebar-brand {
  padding: 0 var(--space-3);
  font-size: var(--text-lg);
  font-weight: var(--font-bold);
  letter-spacing: var(--tracking-tight);
  color: var(--text-primary);
}
/* #endregion sidebar */

/* #region dropdown */
.dropdown {
  position: relative;
  display: inline-block;
}
.dropdown-menu,
.menu {
  position: absolute;
  top: calc(100% + var(--space-2));
  left: 0;
  z-index: 30;
  min-width: 12rem;
  max-width: min(20rem, 90vw);
  margin: 0;
  padding: var(--space-1);
  list-style: none;
  background: var(--bg-surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  opacity: 0;
  visibility: hidden;
  transform: translateY(calc(var(--reveal-shift) / -3)) scale(0.98);
  transform-origin: top left;
  pointer-events: none;
  transition: opacity var(--duration-fast) var(--ease-exit),
    transform var(--duration-fast) var(--ease-exit);
}
.dropdown.is-open .dropdown-menu,
.dropdown-menu.is-open,
.dropdown-menu[aria-hidden="false"] {
  opacity: 1;
  visibility: visible;
  transform: none;
  pointer-events: auto;
  transition: opacity var(--duration-base) var(--ease-enter),
    transform var(--duration-base) var(--ease-enter);
}
.menu-item,
.dropdown-item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
  min-height: var(--control-h);
  padding: 0 var(--space-3);
  font: inherit;
  font-size: var(--text-sm);
  color: var(--text-primary);
  text-align: left;
  background: none;
  border: 0;
  border-radius: var(--radius-base);
  cursor: pointer;
  text-decoration: none;
  transition: background-color var(--duration-instant) var(--ease-standard),
    color var(--duration-instant) var(--ease-standard);
}
.menu-item:hover,
.dropdown-item:hover,
.menu-item:focus-visible {
  background: var(--tint-primary);
  color: var(--text-link);
  outline: none;
}
.menu-item.danger:hover {
  background: var(--tint-error);
  color: var(--text-error);
}
.menu-divider {
  height: 1px;
  margin: var(--space-1) 0;
  background: var(--hairline);
}

.menu-item svg,
.dropdown-item svg {
  width: 1.125rem;
  height: 1.125rem;
  flex: none;
  color: var(--text-tertiary);
}
.menu-item:hover svg,
.dropdown-item:hover svg {
  color: var(--text-link);
}
/* #endregion dropdown */

/* #region overlays */
.overlay,
.backdrop,
.scrim {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: grid;
  place-items: center;
  padding: var(--space-4);
  background: var(--scrim);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--duration-slow) var(--ease-exit);
}
.overlay.is-open,
.overlay[open],
.backdrop.is-open {
  opacity: 1;
  pointer-events: auto;
}
.modal,
.dialog {
  position: relative;
  display: flex;
  flex-direction: column;
  width: min(var(--modal-w, 32rem), 100%);
  max-height: min(85vh, 44rem);
  background: var(--bg-surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-xl);
  transform: translateY(var(--reveal-shift-lg)) scale(0.98);
  transition: transform var(--duration-slow) var(--ease-out-expo);
}
.overlay.is-open .modal,
.overlay.is-open .dialog {
  transform: none;
}
.modal-header,
.dialog-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-5) var(--space-6) var(--space-3);
}
.modal-title,
.dialog-title {
  font-size: var(--text-xl);
  font-weight: var(--font-semibold);
  letter-spacing: var(--tracking-tight);
  color: var(--text-primary);
  margin: 0;
}
.modal-body,
.dialog-body {
  padding: 0 var(--space-6) var(--space-5);
  font-size: var(--text-sm);
  line-height: var(--leading-relaxed);
  color: var(--text-secondary);
  overflow: auto;
}
.modal-footer,
.dialog-footer {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--space-2);
  padding: var(--space-4) var(--space-6);
  border-top: 1px solid var(--hairline);
  background: var(--bg-surface-hover);
  border-radius: 0 0 var(--radius-lg) var(--radius-lg);
}
.dialog-close,
.modal-close {
  display: grid;
  place-items: center;
  width: 2.25rem;
  height: 2.25rem;
  flex: none;
  background: none;
  border: 0;
  border-radius: var(--radius-base);
  color: var(--text-secondary);
  cursor: pointer;
  transition: var(--motion-colors), transform var(--duration-tick) var(--ease-exit);
}
.dialog-close:hover,
.modal-close:hover {
  background: var(--bg-surface-active);
  color: var(--text-primary);
}
.dialog-close:active {
  transform: rotate(90deg);
}
@media (max-width: 640px) {
  .overlay,
  .backdrop {
    align-items: end;
    padding: 0;
  }
  .modal,
  .dialog {
    width: 100%;
    max-height: 88vh;
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    transform: translateY(100%);
  }
  .overlay.is-open .modal,
  .overlay.is-open .dialog {
    transform: none;
  }
  .modal-footer,
  .dialog-footer {
    justify-content: stretch;
  }
  .modal-footer .btn,
  .dialog-footer .btn-primary,
  .dialog-footer .btn-outline {
    flex: 1;
  }
}

/* Closed overlays must leave the tab order; opacity alone keeps them focusable,
   which is what display:none used to provide before motion took over. */
.overlay:not(.is-open),
.backdrop:not(.is-open) {
  visibility: hidden;
  transition: var(--motion-overlay), visibility 0s linear var(--duration-slow);
}
.overlay.is-open,
.backdrop.is-open {
  visibility: visible;
  transition: var(--motion-overlay), visibility 0s;
}
/* #endregion overlays */

/* #region notifications */
.toast {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  width: min(24rem, 100%);
  padding: var(--space-4);
  background: var(--bg-surface);
  border: 1px solid var(--hairline);
  border-left: 3px solid var(--text-secondary);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  transition: opacity var(--duration-slow) var(--ease-exit),
    transform var(--duration-slow) var(--ease-exit),
    margin var(--duration-slow) var(--ease-exit);
}
.toast.is-open {
  animation: mue-toast-in var(--duration-slower) var(--ease-out-expo);
}
.toast.is-leaving {
  opacity: 0;
  transform: translateX(var(--reveal-shift-lg));
}
@keyframes mue-toast-in {
  from {
    opacity: 0;
    transform: translateX(var(--reveal-shift-lg)) scale(0.98);
  }
}
.toast-title {
  font-size: var(--text-base);
  font-weight: var(--font-semibold);
  color: var(--text-primary);
}
.toast-msg,
.toast-desc {
  font-size: var(--text-sm);
  line-height: var(--leading-relaxed);
  color: var(--text-secondary);
}
.toast-icon {
  display: grid;
  place-items: center;
  width: 1.75rem;
  height: 1.75rem;
  flex: none;
  border-radius: 50%;
  background: var(--tint-neutral);
  color: var(--text-secondary);
}
.toast-success {
  border-left-color: hsl(var(--color-success-500));
}
.toast-success .toast-icon {
  background: var(--tint-success);
  color: var(--text-success);
}
.toast-error,
.toast-danger {
  border-left-color: hsl(var(--color-error-500));
}
.toast-error .toast-icon {
  background: var(--tint-error);
  color: var(--text-error);
}
.toast-warning {
  border-left-color: hsl(var(--color-warning-500));
}
.toast-warning .toast-icon {
  background: var(--tint-warning);
  color: var(--text-warning);
}
.toast-info {
  border-left-color: hsl(var(--color-info-500));
}
.toast-info .toast-icon {
  background: var(--tint-info);
  color: var(--text-info);
}
.toast-stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  width: min(24rem, 100%);
}
.alert {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-4);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md);
  background: var(--bg-surface);
  font-size: var(--text-sm);
  line-height: var(--leading-relaxed);
  transition: var(--motion-colors);
}
.alert-success {
  background: var(--tint-success);
  border-color: hsla(var(--color-success-500) / 0.35);
  color: var(--text-success);
}
.alert-error {
  background: var(--tint-error);
  border-color: hsla(var(--color-error-500) / 0.35);
  color: var(--text-error);
}
.alert-warning {
  background: var(--tint-warning);
  border-color: hsla(var(--color-warning-500) / 0.35);
  color: var(--text-warning);
}
.alert-info {
  background: var(--tint-info);
  border-color: hsla(var(--color-info-500) / 0.35);
  color: var(--text-info);
}

.toast-body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
.toast-close {
  display: grid;
  place-items: center;
  width: var(--control-h-sm);
  height: var(--control-h-sm);
  flex: none;
  background: none;
  border: 0;
  border-radius: var(--radius-base);
  color: var(--text-tertiary);
  cursor: pointer;
  transition: var(--motion-colors);
}
.toast-close:hover {
  background: var(--bg-surface-active);
  color: var(--text-primary);
}
.toast[hidden] {
  display: none;
}
.toast-region {
  position: fixed;
  right: var(--space-4);
  bottom: var(--space-4);
  z-index: 60;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  width: min(24rem, calc(100vw - var(--space-8)));
  pointer-events: none;
}
.toast-region .toast {
  pointer-events: auto;
}

.alert-icon {
  display: grid;
  place-items: center;
  flex: none;
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  background: var(--tint-info);
  color: var(--text-info);
}
.alert-success .alert-icon {
  background: var(--tint-success);
  color: var(--text-success);
}
.alert-warning .alert-icon {
  background: var(--tint-warning);
  color: var(--text-warning);
}
.alert-error .alert-icon {
  background: var(--tint-error);
  color: var(--text-error);
}
.alert-icon svg {
  width: 1.125rem;
  height: 1.125rem;
}
/* #endregion notifications */

/* #region tables */
.table-wrap {
  overflow-x: auto;
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  background: var(--bg-surface);
  box-shadow: var(--shadow-xs);
  -webkit-overflow-scrolling: touch;
}
.table {
  width: 100%;
  min-width: 40rem;
  border-collapse: collapse;
  font-size: var(--text-sm);
}
.table th,
.table td {
  padding: var(--space-3) var(--space-4);
  text-align: left;
  border-bottom: 1px solid var(--hairline);
  white-space: nowrap;
}
.table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--text-secondary);
  background: var(--bg-surface-hover);
}
.table tbody tr {
  transition: background-color var(--duration-instant) var(--ease-standard);
}
.table tbody tr:hover {
  background: var(--bg-surface-hover);
}
.table tbody tr:last-child td {
  border-bottom: 0;
}
.table-striped tbody tr:nth-child(even) {
  background: var(--bg-surface-hover);
}
.table-compact th,
.table-compact td {
  padding: var(--space-2) var(--space-3);
}
.table [data-sort] {
  cursor: pointer;
  user-select: none;
}
.table [data-sort]::after {
  content: "";
  display: inline-block;
  margin-left: var(--space-1);
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  opacity: 0.4;
  transition: transform var(--duration-fast) var(--ease-standard);
}
.table [data-sort="asc"]::after {
  border-bottom: 5px solid currentColor;
}
.table [data-sort="desc"]::after {
  border-top: 5px solid currentColor;
  transform: rotate(180deg);
}

.table caption {
  padding: var(--space-3) var(--space-4);
  text-align: left;
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--text-tertiary);
  background: var(--bg-surface);
  caption-side: top;
}

/* A table that lives inside a card is already framed; a second border and
   shadow reads as a rendering glitch. */
.card .table-wrap {
  border: 0;
  border-radius: 0;
  box-shadow: none;
  background: transparent;
}
/* #endregion tables */

/* #region feedback */
.skeleton {
  position: relative;
  overflow: hidden;
  background: var(--bg-surface-hover);
  border-radius: var(--radius-sm);
}
.skeleton::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    90deg,
    transparent,
    hsla(var(--color-white) / 0.45),
    transparent
  );
  transform: translateX(-100%);
  animation: mue-shimmer calc(var(--duration-slowest) * 1.8) var(--ease-in-out) infinite;
}
html.dark .skeleton::after {
  background: linear-gradient(
    90deg,
    transparent,
    hsla(var(--color-white) / 0.08),
    transparent
  );
}
@keyframes mue-shimmer {
  100% {
    transform: translateX(100%);
  }
}
.skeleton-text {
  height: 0.75rem;
  margin-bottom: var(--space-2);
}
.skeleton-title {
  height: 1.25rem;
  width: 60%;
  margin-bottom: var(--space-3);
}
.skeleton-avatar {
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 50%;
  flex: none;
}
.skeleton-body {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-5);
}
.progress,
.track {
  position: relative;
  width: 100%;
  height: 0.5rem;
  background: var(--bg-surface-active);
  border-radius: var(--radius-full);
  overflow: hidden;
}
.progress > .bar,
.track > .bar {
  display: block;
  height: 100%;
  width: var(--value, 0%);
  background: var(--primary-bg);
  border-radius: inherit;
  transition: width var(--duration-slower) var(--ease-out-expo);
}
.progress-success > .bar {
  background: hsl(var(--color-success-500));
}
.progress-warning > .bar {
  background: hsl(var(--color-warning-500));
}
.progress-indeterminate > .bar {
  width: 40%;
  animation: mue-indeterminate calc(var(--duration-slowest) * 2.2) var(--ease-in-out) infinite;
}
@keyframes mue-indeterminate {
  0% {
    transform: translateX(-100%);
  }
  100% {
    transform: translateX(250%);
  }
}
.progress-group {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.progress-label {
  display: flex;
  justify-content: space-between;
  gap: var(--space-3);
  font-size: var(--text-sm);
  color: var(--text-secondary);
}
.progress-label .percent {
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
  font-weight: var(--font-medium);
}
.empty-state,
.empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-12) var(--space-6);
  text-align: center;
  border: 1px dashed var(--border-medium);
  border-radius: var(--radius-lg);
  background: var(--bg-surface);
  animation: mue-fade-in var(--duration-slower) var(--ease-enter);
}
.empty-icon {
  display: grid;
  place-items: center;
  width: 3.5rem;
  height: 3.5rem;
  border-radius: 50%;
  background: var(--bg-surface-hover);
  color: var(--text-tertiary);
}
.empty-title {
  font-size: var(--text-lg);
  font-weight: var(--font-semibold);
  color: var(--text-primary);
  margin: 0;
}
.empty-desc {
  font-size: var(--text-sm);
  color: var(--text-secondary);
  max-width: 42ch;
  margin: 0;
}
.error-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-8);
  text-align: center;
  border: 1px solid hsla(var(--color-error-500) / 0.35);
  border-radius: var(--radius-lg);
  background: var(--tint-error);
}
.tooltip {
  position: absolute;
  z-index: 50;
  max-width: min(18rem, 80vw);
  padding: var(--space-1) var(--space-2);
  font-size: var(--text-xs);
  line-height: 1.4;
  color: var(--text-inverse);
  background: var(--bg-inverse);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-md);
  opacity: 0;
  transform: translateY(4px);
  pointer-events: none;
  transition: opacity var(--duration-fast) var(--ease-exit),
    transform var(--duration-fast) var(--ease-exit);
}
.tooltip.is-visible {
  opacity: 1;
  transform: none;
  transition: opacity var(--duration-base) var(--ease-enter),
    transform var(--duration-base) var(--ease-enter);
}
/* A tooltip used to need hand-placed offsets, because .tooltip is absolutely
   positioned and nothing gave it a containing block or a trigger. .tooltip-wrap
   is that containing block, and it shows the tooltip on hover AND keyboard
   focus, so the hint is reachable without a mouse. `translate` centres it while
   `transform` stays free for the entrance nudge above. */
.tooltip-wrap {
  position: relative;
  display: inline-flex;
}
.tooltip-wrap > .tooltip {
  top: auto;
  left: 50%;
  bottom: calc(100% + var(--space-2));
  translate: -50% 0;
}
.tooltip-wrap > .tooltip::after {
  content: "";
  position: absolute;
  top: 100%;
  left: 50%;
  width: 0.5rem;
  height: 0.5rem;
  translate: -50% -50%;
  rotate: 45deg;
  background: var(--bg-inverse);
}
.tooltip-wrap:hover > .tooltip,
.tooltip-wrap:focus-within > .tooltip {
  opacity: 1;
  transform: none;
  transition: opacity var(--duration-base) var(--ease-enter),
    transform var(--duration-base) var(--ease-enter);
}
.tooltip-below > .tooltip {
  bottom: auto;
  top: calc(100% + var(--space-2));
}
.tooltip-below > .tooltip::after {
  top: auto;
  bottom: 100%;
}

.error-inline {
  flex-direction: row;
  align-items: flex-start;
  gap: var(--space-4);
  text-align: left;
  background: var(--bg-surface);
  border-color: hsla(var(--color-error-500) / 0.35);
}
.error-icon {
  display: grid;
  place-items: center;
  flex: none;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 50%;
  background: var(--tint-error);
  color: var(--text-error);
}
.error-body {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
.skeleton-img {
  width: 100%;
  height: 10rem;
  border-radius: var(--radius-lg);
}
.skeleton-btn {
  width: 6rem;
  height: var(--control-h);
  border-radius: var(--radius-base);
}
.skeleton-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--hairline);
}
.progress-striped > .bar {
  background-image: repeating-linear-gradient(
    45deg,
    hsla(var(--color-white) / 0.28) 0 0.5rem,
    transparent 0.5rem 1rem
  );
}
/* #endregion feedback */

/* #region charts */
.chart {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  min-width: 0;
  padding: var(--space-4);
  background: var(--bg-surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
}
.chart canvas,
.chart svg {
  width: 100%;
  height: auto;
  display: block;
}
.axis,
.chart text {
  font-size: var(--text-xs);
  fill: var(--text-tertiary);
  font-family: var(--font-mono);
}
.chart .bar-primary,
.chart .bar {
  transform-origin: bottom;
  animation: mue-grow-up var(--duration-slower) var(--ease-out-expo) backwards;
}
@keyframes mue-grow-up {
  from {
    transform: scaleY(0);
  }
}
.chart .line {
  stroke-dasharray: 1000;
  stroke-dashoffset: 1000;
  animation: mue-draw calc(var(--duration-slowest) * 3.5) var(--ease-soft) forwards;
}
@keyframes mue-draw {
  to {
    stroke-dashoffset: 0;
  }
}
.legend {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3) var(--space-5);
}
.legend-item {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-sm);
  color: var(--text-secondary);
}
.legend-dot {
  width: 10px;
  height: 10px;
  border-radius: 3px;
  flex: none;
}

.chart .bar-primary {
  fill: var(--primary-bg);
}
.chart .bar-success {
  fill: hsl(var(--color-success-500));
}
.chart .bar-warning {
  fill: hsl(var(--color-warning-500));
}
.chart .point {
  fill: var(--primary-bg);
  stroke: var(--bg-surface);
  stroke-width: 2;
}
.chart .grid-line {
  stroke: var(--border-light);
  stroke-width: 1;
}
.chart-title {
  font-size: var(--text-sm);
  font-weight: var(--font-semibold);
  color: var(--text-primary);
}

/* Every dashboard trend chart needed the same two things: a quiet comparison
   series behind the current one, and a wash under the line. */
.chart .prior {
  fill: none;
  stroke: var(--border-dark);
  stroke-width: 2;
  stroke-dasharray: 5 5;
}
.chart .area {
  fill: var(--tint-primary);
  stroke: none;
}
/* #endregion charts */

/* #region footers */
.footer,
.site-footer {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: var(--space-8);
  padding: var(--space-10) var(--space-6);
  background: var(--bg-surface);
  border-top: 1px solid var(--hairline);
}
.footer-heading {
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--text-tertiary);
  margin: 0 0 var(--space-3);
}
.footer-links {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  list-style: none;
  margin: 0;
  padding: 0;
}
.footer-links a {
  font-size: var(--text-sm);
  color: var(--text-secondary);
  text-decoration: none;
  /* Links read as text but are tapped like controls: give them the row height. */
  padding: var(--space-1) var(--space-2) var(--space-1) 0;
  transition: var(--motion-colors);
}
.footer-links a:hover {
  color: var(--text-link);
}

.footer-brand {
  font-size: var(--text-lg);
  font-weight: var(--font-bold);
  letter-spacing: var(--tracking-tight);
  color: var(--text-primary);
}
.footer-desc {
  margin-top: var(--space-2);
  font-size: var(--text-sm);
  line-height: var(--leading-relaxed);
  color: var(--text-secondary);
  max-width: 34ch;
}
.footer-bottom {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding-top: var(--space-5);
  border-top: 1px solid var(--hairline);
  font-size: var(--text-sm);
  color: var(--text-tertiary);
}
.footer-social {
  display: flex;
  gap: var(--space-2);
}
.footer-social a {
  display: grid;
  place-items: center;
  width: var(--control-h-sm);
  height: var(--control-h-sm);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-base);
  color: var(--text-secondary);
  transition: var(--motion-colors), transform var(--duration-tick) var(--ease-exit);
}
.footer-social a:hover {
  color: var(--text-link);
  border-color: var(--primary-bg);
  transform: translateY(var(--lift-hover-sm));
}
/* #endregion footers */

/* #region display */
/* The blocks dashboards, marketing pages and starters repeat most: a metric,
   its delta and a sparkline frame. */
.stat {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-width: 0;
  padding: var(--space-5);
  background: var(--bg-surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-xs);
  transition: var(--motion-lift);
}
.stat:hover {
  transform: translateY(var(--lift-hover-sm));
  box-shadow: var(--shadow-sm);
}
.stat-label {
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--text-tertiary);
}
.stat-value {
  font-family: var(--font-display);
  font-size: var(--text-3xl);
  font-weight: var(--font-bold);
  line-height: var(--leading-none);
  letter-spacing: var(--tracking-tight);
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}
.stat-delta {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  color: var(--text-secondary);
}
.stat-delta.is-up {
  color: var(--text-success);
}
.stat-delta.is-down {
  color: var(--text-error);
}
.spark {
  width: 100%;
  height: 3rem;
  overflow: visible;
}
.spark path.area {
  fill: var(--tint-primary);
}
.spark path.line {
  fill: none;
  stroke: var(--primary-bg);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: var(--spark-length, 600);
  stroke-dashoffset: var(--spark-length, 600);
  animation: mue-draw calc(var(--duration-slowest) * 3) var(--ease-soft) forwards;
}
.metric-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(11rem, 100%), 1fr));
  gap: var(--space-4);
}
.timeline {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  position: relative;
  padding-left: var(--space-6);
}
.timeline::before {
  content: "";
  position: absolute;
  left: 7px;
  top: 6px;
  bottom: 6px;
  width: 2px;
  background: var(--border-light);
}
.timeline-item {
  position: relative;
  font-size: var(--text-sm);
  color: var(--text-secondary);
}
.timeline-item::before {
  content: "";
  position: absolute;
  left: calc(var(--space-6) * -1 + 2px);
  top: 6px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--bg-surface);
  border: 2px solid var(--primary-bg);
  transition: transform var(--duration-fast) var(--ease-spring);
}
.timeline-item:hover::before {
  transform: scale(var(--focus-scale));
}
/* Timeline entries carry the same three states a stepper does, so a changelog
   can mark what is finished, what is happening now and what is still coming.
   The dot alone used to say nothing; now it is filled, ringed or hollow. */
.timeline-item.is-done::before {
  background: var(--primary-bg);
  border-color: var(--primary-bg);
}
.timeline-item.is-current::before {
  background: var(--bg-surface);
  border-color: var(--primary-bg);
  box-shadow: var(--ring-focus);
}
.timeline-item.is-upcoming::before {
  border-style: dashed;
  border-color: var(--border-medium);
  background: var(--bg-body);
}
.timeline-title {
  display: block;
  font-size: var(--text-base);
  font-weight: var(--font-semibold);
  color: var(--text-primary);
}
.timeline-meta {
  display: block;
  font-size: var(--text-xs);
  color: var(--text-tertiary);
}
.avatar {
  display: grid;
  place-items: center;
  width: 2.25rem;
  height: 2.25rem;
  flex: none;
  border-radius: 50%;
  background: var(--tint-primary);
  color: var(--text-link);
  font-size: var(--text-sm);
  font-weight: var(--font-semibold);
  overflow: hidden;
}
/* --tint-primary is an alpha, so an avatar inside a selected row stacks a
   second brand tint under the first. The lifted dark blue is the one step that
   still clears 4.5:1 on that double tint. */
html.dark .avatar {
  color: hsl(var(--color-primary-700));
}
.avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.avatar-group {
  display: flex;
  align-items: center;
}
.avatar-group .avatar {
  box-shadow: 0 0 0 2px var(--bg-surface);
}
.avatar-group .avatar + .avatar {
  margin-left: calc(var(--space-2) * -1);
}
/* #endregion display */

/* #region utilities */
.stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  min-width: 0;
}
.row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  min-width: 0;
}
.spread {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}
/* auto-fit beats a fixed breakpoint: the grid reflows the moment a column no
   longer fits, so narrow phones and ultrawide monitors are both handled. */
.grid-auto {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(var(--col-min, 16rem), 100%), 1fr));
  gap: var(--space-4);
}
.divider {
  height: 1px;
  background: var(--hairline);
  border: 0;
  margin: var(--space-6) 0;
}
.truncate {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tabular {
  font-variant-numeric: tabular-nums;
}
.mono,
code,
kbd,
samp {
  font-family: var(--font-mono);
  font-size: 0.9em;
}
kbd {
  padding: 1px 6px;
  border: 1px solid var(--border-medium);
  border-bottom-width: 2px;
  border-radius: var(--radius-sm);
  background: var(--bg-surface-hover);
  font-size: var(--text-xs);
}
/* Scroll reveal: add .reveal to any block and styles/mue.js flips it to .in
   when it enters the viewport. Stagger siblings with an inline --d delay. */
.reveal {
  opacity: 0;
  transform: translateY(var(--reveal-shift));
  transition: opacity var(--duration-slower) var(--ease-soft) var(--d, 0s),
    transform var(--duration-slower) var(--ease-out-expo) var(--d, 0s);
}
.reveal.in {
  opacity: 1;
  transform: none;
}
.skip-link {
  position: absolute;
  left: var(--space-4);
  top: -4rem;
  z-index: 100;
  padding: var(--space-3) var(--space-5);
  background: var(--primary-bg);
  color: var(--primary-fg);
  border-radius: var(--radius-base);
  text-decoration: none;
  transition: top var(--duration-fast) var(--ease-enter);
}
.skip-link:focus-visible {
  top: var(--space-4);
}
@keyframes mue-drop-in {
  from {
    opacity: 0;
    transform: translateY(calc(var(--reveal-shift) / -2));
  }
}
@keyframes mue-fade-up {
  from {
    opacity: 0;
    transform: translateY(var(--reveal-shift));
  }
}
@media (prefers-reduced-motion: reduce) {
  .reveal {
    opacity: 1;
    transform: none;
  }
  .skeleton::after,
  .loading > .bar,
  .spinner {
    animation: none;
  }
}

/* The bulleted teaching list every component preview ends with. */
.doc-list {
  display: grid;
  gap: var(--space-2);
  margin: 0;
  padding-left: 1.25rem;
  list-style: disc;
  font-size: var(--text-sm);
  line-height: var(--leading-relaxed);
  color: var(--text-secondary);
}
.card-grid,
.demo-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr));
  gap: var(--space-4);
}
/* Text for assistive tech only - the label of a control whose visible face is
   an icon, a star or a dashed upload box. Clip, never display:none, or the
   element leaves the accessibility tree as well as the screen. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* A reveal hides content until the behaviour layer reveals it, so it must only
   hide when that layer actually loaded — otherwise a blocked mue.js leaves the
   page blank. mue.js adds .mue-js to <html> during boot. */
html:not(.mue-js) .reveal {
  opacity: 1;
  transform: none;
}
/* #endregion utilities */

/* #region shell */
/* The app frame every dashboard starter repeats: sidebar rail + scrolling
   main column. Opt in with
   <div class="app"><aside class="sidebar">…</aside><div class="main">…</div></div>
   and override --grid-cols / --sidebar-w per page. */
.app {
  display: flex;
  min-height: 100vh;
  min-height: 100dvh;
}
.app.is-locked {
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
}
.app > .main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  background: var(--bg-body);
}
.app .content {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-8);
  padding: var(--space-6);
}
/* The rail is a column inside a fixed-height frame, so it has to claim the
   leftover height itself. */
.app .sidebar nav {
  flex: 1;
  min-height: 0;
}
.page-head {
  min-width: 0;
}
.page-head h1 {
  margin: 0 0 var(--space-2);
  font-size: var(--text-3xl);
  font-weight: var(--font-bold);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
  color: var(--text-primary);
}
.page-head p {
  margin: 0;
  color: var(--text-secondary);
}
.content-grid {
  display: grid;
  grid-template-columns: var(--grid-cols, 2fr 1fr);
  gap: var(--space-6);
  min-width: 0;
}
.content-grid > .card-wide {
  grid-column: 1 / -1;
}
@media (max-width: 900px) {
  .app {
    flex-direction: column;
  }
  .content-grid {
    grid-template-columns: 1fr;
  }
}
/* #endregion shell */

/* #region chat */
/* Conversation surfaces for the AI templates: a scrolling thread, the two
   message alignments, the typing and streaming states, and the composer. */
.thread {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-5);
  scrollbar-width: thin;
}
.msg {
  display: flex;
  align-items: flex-end;
  gap: var(--space-3);
  min-width: 0;
  max-width: min(46rem, 88%);
  animation: chat-enter var(--duration-slow) var(--ease-enter);
}
.msg.ai {
  align-self: flex-start;
}
.msg.user {
  align-self: flex-end;
  flex-direction: row-reverse;
}
.bubble {
  min-width: 0;
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-lg);
  font-size: var(--text-sm);
  line-height: var(--leading-relaxed);
  overflow-wrap: anywhere;
}
.msg.ai .bubble {
  background: var(--bg-surface);
  border: 1px solid var(--hairline);
  border-bottom-left-radius: var(--radius-sm);
  color: var(--text-primary);
}
.msg.user .bubble {
  background: var(--primary-bg);
  border-bottom-right-radius: var(--radius-sm);
  color: var(--primary-fg);
}
/* Streaming caret: the tail of a message that is still arriving. */
.msg.is-streaming .bubble::after {
  content: "";
  display: inline-block;
  width: 0.5rem;
  height: 1rem;
  margin-left: var(--space-1);
  vertical-align: -0.15rem;
  border-radius: var(--radius-sm);
  background: currentColor;
  animation: chat-caret var(--duration-base) var(--ease-in-out) infinite alternate;
}
/* Typing indicator shown while the model is thinking. */
.msg.typing .bubble {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
}
.msg.typing .bubble i {
  width: 6px;
  height: 6px;
  flex: none;
  border-radius: 50%;
  background: var(--text-tertiary);
  animation: chat-typing var(--duration-slower) var(--ease-in-out) infinite;
}
.msg.typing .bubble i:nth-child(2) {
  animation-delay: calc(var(--duration-fast) / 2);
}
.msg.typing .bubble i:nth-child(3) {
  animation-delay: var(--duration-fast);
}
.conversation-list {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  scrollbar-width: thin;
}
.chat-item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: var(--control-h);
  min-width: 0;
  padding: var(--space-2) var(--space-3);
  border: 0;
  border-radius: var(--radius-base);
  background: none;
  color: var(--text-secondary);
  font: inherit;
  font-size: var(--text-sm);
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  transition: var(--motion-colors);
}
.chat-item:hover {
  background: var(--bg-surface-hover);
  color: var(--text-primary);
}
.chat-item.active,
.chat-item[aria-current="true"] {
  background: var(--tint-primary);
  color: var(--text-link);
}
/* Title block in the topbar: a heading plus its quiet sub-line. */
.chat-head {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
/* The composer reuses .field, but a chat input is one line tall, not 6.5rem. */
.composer {
  flex: none;
  border-top: 1px solid var(--hairline);
  background: var(--bg-surface);
  padding: var(--space-4) var(--space-5);
}
.composer-form {
  display: flex;
  align-items: flex-end;
  gap: var(--space-3);
}
.composer-form .field {
  flex: 1;
  min-width: 0;
}
.composer .field textarea {
  min-height: var(--control-h);
  max-height: 10rem;
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-full);
  resize: none;
  /* .field defaults to --bg-surface, which is the composer's own colour. */
  background: var(--bg-body);
}
@keyframes chat-enter {
  from {
    opacity: 0;
    transform: translateY(calc(var(--reveal-shift) / 2));
  }
}
@keyframes chat-caret {
  from {
    opacity: 0.2;
  }
  to {
    opacity: 0.9;
  }
}
@keyframes chat-typing {
  0%,
  100% {
    opacity: 0.3;
    transform: translateY(0);
  }
  50% {
    opacity: 1;
    transform: translateY(calc(var(--reveal-shift) / -4));
  }
}
/* #endregion chat */

/* #region disclosure */
/* Accordion. The trigger carries aria-expanded and the panel gets .is-open —
   mue.js does that for any [data-disclosure] button. */
.accordion {
  display: grid;
  gap: var(--space-3);
}
.accordion-item {
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md);
  background: var(--bg-surface);
  overflow: hidden;
}
.accordion-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  width: 100%;
  min-height: var(--control-h);
  padding: var(--space-3) var(--space-5);
  background: none;
  border: 0;
  font: inherit;
  font-size: var(--text-base);
  font-weight: var(--font-semibold);
  color: var(--text-primary);
  text-align: left;
  cursor: pointer;
  transition: var(--motion-colors);
}
.accordion-trigger:hover {
  background: var(--bg-surface-hover);
}
.accordion-trigger svg {
  width: 1.1rem;
  height: 1.1rem;
  flex: none;
  color: var(--text-tertiary);
  transition: transform var(--duration-base) var(--ease-out-expo);
}
.accordion-trigger[aria-expanded="true"] svg {
  transform: rotate(45deg);
}
/* Animating grid-template-rows keeps the panel in the flow, so the closed
   height never has to be guessed. */
.accordion-panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--duration-slow) var(--ease-soft);
}
.accordion-panel.is-open {
  grid-template-rows: 1fr;
}
.accordion-panel > div {
  overflow: hidden;
}
.accordion-panel p {
  margin: 0;
  padding: 0 var(--space-5) var(--space-5);
  font-size: var(--text-sm);
  line-height: var(--leading-relaxed);
  color: var(--text-secondary);
  max-width: 68ch;
}
/* #endregion disclosure */

/* #region invert */
/* A dark panel that is dark in BOTH themes — a footer band, a hero, a CTA.
   Every component rule in this sheet reads semantic tokens, so re-declaring
   those tokens on the container re-themes the whole subtree: buttons, fields,
   tabs, chips, tables, toasts and charts all follow with no per-component
   dark rules. Add .invert to the container. */
.invert {
  --bg-body: hsl(var(--color-gray-950));
  --bg-surface: hsl(var(--color-gray-900));
  --bg-surface-hover: hsl(var(--color-gray-800));
  --bg-surface-active: hsl(var(--color-gray-700));
  --text-primary: hsl(var(--color-gray-50));
  --text-secondary: hsl(var(--color-gray-300));
  --text-tertiary: hsl(var(--color-gray-400));
  --text-link: hsl(var(--color-primary-400));
  --text-link-hover: hsl(var(--color-primary-300));
  --hairline: hsl(var(--color-gray-800));
  --border-light: hsl(var(--color-gray-800));
  --border-medium: hsl(var(--color-gray-700));
  --border-dark: hsl(var(--color-gray-600));
  --primary-bg: hsl(var(--color-primary-400));
  --primary-fg: hsl(var(--color-gray-950));
  --tint-primary: hsla(var(--color-primary-400) / 0.18);
  --shadow-xs: none;
  --shadow-sm: none;
  --shadow-base: none;
  color: var(--text-secondary);
  background: hsl(var(--color-gray-900));
}
.invert h1,
.invert h2,
.invert h3,
.invert h4,
.invert strong {
  color: var(--text-primary);
}
.invert .btn-outline {
  color: var(--text-primary);
  border-color: var(--border-medium);
}
.invert .btn-outline:hover {
  background: var(--bg-surface-hover);
}
/* The dark theme mirrors the whole grayscale ramp, so gray-900/950 above turn
   near-white and the panel would flip to a light box inside a dark page. Re-point
   each token at the same *absolute* step of the mirrored ramp: the panel keeps
   its near-black surface and light text in both themes, and a solid primary
   button pairs the lifted blue with the dark ink the theme already uses. */
html.dark .invert {
  --bg-body: hsl(var(--color-gray-50));
  --bg-surface: hsl(var(--color-gray-100));
  --bg-surface-hover: hsl(var(--color-gray-200));
  --bg-surface-active: hsl(var(--color-gray-300));
  --text-primary: hsl(var(--color-gray-950));
  --text-secondary: hsl(var(--color-gray-600));
  --text-tertiary: hsl(var(--color-gray-500));
  --hairline: hsl(var(--color-gray-200));
  --border-light: hsl(var(--color-gray-200));
  --border-medium: hsl(var(--color-gray-300));
  --border-dark: hsl(var(--color-gray-400));
  --primary-bg: hsl(var(--color-primary-500));
  --primary-fg: hsl(var(--color-gray-50));
  background: hsl(var(--color-gray-100));
}
/* #endregion invert */

/* #region sections */
/* Marketing section primitives: the blocks a product or landing page is
   assembled from. Every rhythm comes off the spacing scale - a normal band is
   --space-16 deep, a hero --space-24 - so a whole page can be re-spaced by
   overriding one custom property (--section-pad-y) instead of hunting rules. */
.section {
  padding-block: var(--section-pad-y, var(--space-16));
  padding-inline: var(--section-pad-x, var(--space-6));
}
/* Eyebrow + title + lede. Left aligned by default; .is-centered centres the
   block and keeps the lede on a readable measure either way. */
.section-head {
  display: grid;
  justify-items: start;
  gap: var(--space-3);
  max-width: 46rem;
  margin-bottom: var(--space-10);
}
.section-head.is-centered {
  margin-inline: auto;
  justify-items: center;
  text-align: center;
}
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-xs);
  font-weight: var(--font-bold);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--text-link);
}
/* Title and lede carry their own classes: a bare h2 inherits whatever the host
   page already decided, and a marketing headline is a decision, not a default.
   The two-selector list keeps the block usable standalone AND keeps its size
   when a preview nests it inside page chrome. */
.section-head .section-title,
.section .section-head .section-title {
  margin: 0;
  max-width: 24ch;
  font-size: var(--text-3xl);
  font-weight: var(--font-bold);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
  color: var(--text-primary);
  text-wrap: balance;
  overflow-wrap: break-word;
}
.section-head .section-lede,
.section .section-head .section-lede {
  margin: 0;
  max-width: 60ch;
  font-size: var(--text-lg);
  line-height: var(--leading-relaxed);
  color: var(--text-secondary);
}
/* Hero: copy on one side, an optional media slot on the other. Add .hero-split
   to get the two columns; without it the media simply stacks under the copy.
   The container carries rhythm only and the layout lives on .hero-split, because
   two example pages in this kit already use the bare word .hero for their own
   bespoke band and link this sheet: a display:grid from here would have quietly
   re-flowed both of them. */
.hero {
  padding-block: var(--hero-pad-y, var(--space-24));
  padding-inline: var(--hero-pad-x, var(--space-6));
}
.hero-split {
  display: grid;
  align-items: center;
  gap: var(--space-8);
}
.hero-copy {
  display: grid;
  align-content: center;
  justify-items: start;
  gap: var(--space-4);
  min-width: 0;
}
.hero .hero-title {
  margin: 0;
  font-size: var(--text-4xl);
  font-weight: var(--font-extrabold);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
  color: var(--text-primary);
  text-wrap: balance;
  overflow-wrap: break-word;
}
.hero-sub {
  margin: 0;
  max-width: 56ch;
  font-size: var(--text-lg);
  line-height: var(--leading-relaxed);
  color: var(--text-secondary);
}
.hero-cta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin: 0;
}
.hero-note {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  font-size: var(--text-sm);
  color: var(--text-secondary);
}
.hero-media {
  position: relative;
  display: grid;
  place-items: center;
  min-width: 0;
  margin-block-start: var(--space-8);
  aspect-ratio: 16 / 10;
  overflow: hidden;
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  background: linear-gradient(180deg, var(--tint-primary), var(--bg-surface-hover) 72%);
  color: var(--text-link);
}
/* Inside a split hero the grid gap owns that space already. */
.hero-split .hero-media {
  margin-block-start: 0;
}
.hero-media img,
.hero-media svg {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* Feature grid: auto-fit columns, so the row count follows the available width
   and nobody has to maintain a breakpoint. */
.feature-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(var(--col-min, 17rem), 100%), 1fr));
  gap: var(--space-8) var(--space-6);
}
.feature {
  display: grid;
  align-content: start;
  gap: var(--space-3);
  min-width: 0;
}
.feature-icon {
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: var(--radius-md);
  background: var(--tint-primary);
  color: var(--text-link);
}
.feature-icon svg {
  width: 1.35rem;
  height: 1.35rem;
}
.feature-title {
  margin: 0;
  font-size: var(--text-lg);
  font-weight: var(--font-semibold);
  letter-spacing: var(--tracking-tight);
  color: var(--text-primary);
}
.feature-text {
  margin: 0;
  font-size: var(--text-sm);
  line-height: var(--leading-relaxed);
  color: var(--text-secondary);
}
/* Pricing. .is-recommended is the highlighted tier, and it is also labelled by
   a .price-flag badge, so the emphasis never rests on colour alone. */
.pricing {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(17rem, 100%), 1fr));
  gap: var(--space-4);
  align-items: start;
}
.price-card {
  position: relative;
  display: grid;
  align-content: start;
  gap: var(--space-4);
  min-width: 0;
  padding: var(--space-6);
  background: var(--bg-surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-xs);
  transition: var(--motion-colors);
}
.price-card.is-recommended {
  border-color: var(--primary-bg);
  box-shadow: var(--shadow-md);
}
.price-flag {
  position: absolute;
  inset-block-start: calc(var(--space-3) * -1);
  inset-inline-start: var(--space-6);
}
.price-name {
  margin: 0;
  font-size: var(--text-base);
  font-weight: var(--font-semibold);
  color: var(--text-primary);
}
.price-amount {
  display: flex;
  align-items: baseline;
  gap: var(--space-1);
  margin: 0;
  font-size: var(--text-4xl);
  font-weight: var(--font-extrabold);
  line-height: var(--leading-none);
  letter-spacing: var(--tracking-tight);
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
}
.price-period {
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  color: var(--text-secondary);
}
.price-list {
  display: grid;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--text-sm);
  line-height: var(--leading-relaxed);
  color: var(--text-secondary);
}
.price-list li {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  min-width: 0;
}
.price-list svg {
  flex: none;
  width: 1.1rem;
  height: 1.1rem;
  margin-top: 2px;
  color: var(--text-success);
}
.price-note {
  margin: 0;
  font-size: var(--text-xs);
  line-height: var(--leading-normal);
  color: var(--text-secondary);
}
.price-card .btn {
  width: 100%;
}
/* Testimonial: quote first, attribution second, optional source link. */
.testimonial {
  display: grid;
  align-content: start;
  gap: var(--space-4);
  min-width: 0;
  padding: var(--space-6);
  background: var(--bg-surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
}
.quote-mark {
  font-family: var(--font-display);
  font-size: var(--text-4xl);
  line-height: var(--leading-none);
  color: var(--primary-bg);
}
.testimonial-quote {
  margin: 0;
  font-size: var(--text-lg);
  line-height: var(--leading-relaxed);
  color: var(--text-primary);
}
.testimonial-person {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-width: 0;
}
.testimonial-name {
  font-size: var(--text-sm);
  font-weight: var(--font-semibold);
  color: var(--text-primary);
}
.testimonial-role {
  font-size: var(--text-sm);
  color: var(--text-secondary);
}
/* Closing call to action. Pair with .invert for a dark band that stays dark in
   both themes, or leave it on the surface and it follows the theme. */
.cta-band {
  display: grid;
  justify-items: center;
  gap: var(--space-4);
  padding: var(--space-10) var(--space-6);
  text-align: center;
  background: var(--bg-surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
}
.cta-band-title {
  margin: 0;
  font-size: var(--text-2xl);
  font-weight: var(--font-bold);
  letter-spacing: var(--tracking-tight);
  color: var(--text-primary);
  text-wrap: balance;
}
.cta-band-text {
  margin: 0;
  max-width: 52ch;
  font-size: var(--text-base);
  line-height: var(--leading-relaxed);
  color: var(--text-secondary);
}
.cta-band-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-3);
}
.cta-band-note {
  margin: 0;
  font-size: var(--text-xs);
  color: var(--text-secondary);
}
/* Team card: avatar, role, and link buttons that clear 44px on their own. */
.team-card {
  display: grid;
  justify-items: center;
  gap: var(--space-2);
  min-width: 0;
  padding: var(--space-6);
  text-align: center;
  background: var(--bg-surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  transition: var(--motion-colors);
}
.team-card .avatar {
  width: 4.5rem;
  height: 4.5rem;
  font-size: var(--text-lg);
}
.team-name {
  margin: 0;
  font-size: var(--text-base);
  font-weight: var(--font-semibold);
  color: var(--text-primary);
}
.team-role {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--text-secondary);
}
.team-bio {
  margin: 0;
  font-size: var(--text-sm);
  line-height: var(--leading-relaxed);
  color: var(--text-secondary);
}
.team-links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-2);
  margin-top: var(--space-2);
}
.team-links a {
  display: inline-grid;
  place-items: center;
  width: var(--control-h);
  height: var(--control-h);
  color: var(--text-secondary);
  background: var(--bg-surface-hover);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-full);
  transition: var(--motion-colors);
}
.team-links a:hover {
  color: var(--text-link);
  border-color: var(--border-medium);
}
.team-links a:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
}
.team-links svg {
  width: 1.15rem;
  height: 1.15rem;
}
/* FAQ: the #disclosure accordion does the behaviour, these two classes only
   widen the hit area and centre the column. */
.faq-list {
  display: grid;
  gap: var(--space-3);
  max-width: 46rem;
  margin-inline: auto;
}
.faq-item > .accordion-trigger {
  padding: var(--space-4) var(--space-5);
  font-size: var(--text-base);
}
.faq-item .accordion-panel p {
  padding: 0 var(--space-5) var(--space-6);
}
@media (min-width: 60rem) {
  .hero-split {
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
  }
  .hero .hero-title {
    font-size: var(--text-5xl);
  }
}
/* #endregion sections */

/* #region stepper */
/* Progress through a multi-part task. Vertical (rail down the left) on a phone,
   horizontal (rail between the dots) from 640px up - one breakpoint, because
   the two layouts genuinely differ rather than just rescale.
   States: .is-done, .is-current (which should also carry aria-current="step")
   and .is-upcoming. */
.stepper {
  --stepper-dot: 2.25rem;
  position: relative;
  display: grid;
  gap: var(--space-4);
  margin: 0;
  padding: 0;
  list-style: none;
}
.stepper::before {
  content: "";
  position: absolute;
  inset-block: var(--space-6);
  left: calc(var(--stepper-dot) / 2 - 1px);
  width: 2px;
  border-radius: var(--radius-full);
  background: var(--border-light);
}
.stepper-item {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: var(--stepper-dot) minmax(0, 1fr);
  gap: var(--space-3);
  align-items: center;
  min-height: var(--control-h);
  min-width: 0;
}
/* The coloured progress segment belongs to a completed step and runs down to
   the next dot; the next dot paints over the end of it. */
.stepper-item.is-done::after {
  content: "";
  position: absolute;
  left: calc(var(--stepper-dot) / 2 - 1px);
  top: 50%;
  bottom: calc(-50% - var(--space-4));
  width: 2px;
  border-radius: var(--radius-full);
  background: var(--primary-bg);
}
.stepper-dot {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  width: var(--stepper-dot);
  height: var(--stepper-dot);
  border-radius: var(--radius-full);
  background: var(--bg-surface);
  border: 2px solid var(--border-medium);
  color: var(--text-secondary);
  font-size: var(--text-sm);
  font-weight: var(--font-semibold);
  font-variant-numeric: tabular-nums;
  transition: var(--motion-colors);
}
.stepper-dot svg {
  width: 1.1rem;
  height: 1.1rem;
}
.stepper-label {
  display: grid;
  gap: 2px;
  min-width: 0;
  font-size: var(--text-sm);
  color: var(--text-secondary);
}
.stepper-name {
  font-weight: var(--font-semibold);
  color: var(--text-secondary);
}
.stepper-text {
  line-height: var(--leading-normal);
}
.stepper-item.is-done .stepper-dot {
  background: var(--primary-bg);
  border-color: var(--primary-bg);
  color: var(--primary-fg);
}
.stepper-item.is-done .stepper-name,
.stepper-item.is-current .stepper-name {
  color: var(--text-primary);
}
.stepper-item.is-current .stepper-dot,
.stepper-item[aria-current="step"] .stepper-dot {
  border-color: var(--primary-bg);
  color: var(--text-link);
  box-shadow: var(--ring-focus);
}
.stepper-item.is-upcoming .stepper-dot {
  border-style: dashed;
  color: var(--text-tertiary);
}
@media (min-width: 40rem) {
  .stepper {
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    gap: 0;
  }
  .stepper::before {
    display: none;
  }
  .stepper-item {
    grid-template-columns: none;
    grid-template-rows: auto auto;
    justify-items: center;
    gap: var(--space-3);
    padding-inline: var(--space-3);
    text-align: center;
  }
  .stepper-item.is-done::after {
    content: none;
  }
  /* Equal columns make the maths exact: -50% lands on the previous dot. */
  .stepper-item + .stepper-item::before {
    content: "";
    position: absolute;
    top: calc(var(--stepper-dot) / 2 - 1px);
    left: -50%;
    right: 50%;
    height: 2px;
    border-radius: var(--radius-full);
    background: var(--border-light);
  }
  .stepper-item.is-done + .stepper-item::before,
  .stepper-item.is-current + .stepper-item::before,
  .stepper-item + .stepper-item[aria-current="step"]::before {
    background: var(--primary-bg);
  }
  .stepper-label {
    justify-items: center;
  }
}
/* #endregion stepper */

/* #region dropzone */
/* File upload target. The real <input type="file"> is stretched across the box
   at zero opacity, so a click, a drag and a Tab all hit the native control -
   no label gymnastics, no JS to open the picker. */
.dropzone {
  position: relative;
  display: grid;
  justify-items: center;
  gap: var(--space-2);
  padding: var(--space-8) var(--space-6);
  text-align: center;
  background: var(--bg-surface);
  border: 2px dashed var(--border-medium);
  border-radius: var(--radius-lg);
  transition: var(--motion-colors);
}
.dropzone:hover {
  border-color: var(--border-focus);
  background: var(--bg-surface-hover);
}
.dropzone:focus-within {
  border-color: var(--border-focus);
  box-shadow: var(--ring-focus);
}
/* The consuming app toggles .is-dragging on dragover/dragleave. */
.dropzone.is-dragging {
  border-color: var(--primary-bg);
  background: var(--tint-primary);
}
/* The element selector is load-bearing: a dropzone inside an app's own
   .field wrapper must not pick up the sheet's text-input styling. */
input.dropzone-input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  border-radius: inherit;
  font-size: var(--text-sm);
  color: transparent;
  opacity: 0;
  cursor: pointer;
}
input.dropzone-input::file-selector-button {
  cursor: pointer;
}
.dropzone-icon {
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: var(--radius-full);
  background: var(--tint-primary);
  color: var(--text-link);
}
.dropzone-icon svg {
  width: 1.35rem;
  height: 1.35rem;
}
.dropzone-title {
  font-size: var(--text-base);
  font-weight: var(--font-semibold);
  color: var(--text-primary);
}
.dropzone-link {
  color: var(--text-link);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.dropzone-hint {
  font-size: var(--text-sm);
  color: var(--text-secondary);
}
.dropzone-list {
  display: grid;
  gap: var(--space-2);
  margin: var(--space-4) 0 0;
  padding: 0;
  list-style: none;
}
.file-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-width: 0;
  padding: var(--space-2) var(--space-3);
  background: var(--bg-surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-base);
}
.file-icon {
  display: grid;
  place-items: center;
  flex: none;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: var(--radius-base);
  background: var(--tint-neutral);
  color: var(--text-secondary);
}
.file-icon svg {
  width: 1.15rem;
  height: 1.15rem;
}
.file-name {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  font-size: var(--text-sm);
  color: var(--text-primary);
  text-overflow: ellipsis;
  white-space: nowrap;
}
.file-size {
  flex: none;
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
  color: var(--text-secondary);
}
.file-remove {
  display: inline-grid;
  place-items: center;
  flex: none;
  width: var(--control-h);
  height: var(--control-h);
  margin: calc(var(--space-2) * -1) calc(var(--space-3) * -1) calc(var(--space-2) * -1) 0;
  background: none;
  border: 1px solid transparent;
  border-radius: var(--radius-base);
  color: var(--text-secondary);
  cursor: pointer;
  transition: var(--motion-colors);
}
.file-remove svg {
  width: 1.15rem;
  height: 1.15rem;
}
.file-remove:hover {
  color: var(--text-error);
  background: var(--tint-error);
}
.file-remove:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
}
/* #endregion dropzone */

/* #region rating */
/* Star rating. Read-only: .rating with an aria-label that states the score.
   Interactive: a plain radio group in natural order (1 to 5), so Right and
   Down raise the score, and "fill up to the chosen star" is expressed with
   :has() instead of the reversed-DOM trick that fakes it in CSS-only kits. */
.rating {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  font-size: var(--text-sm);
  color: var(--text-secondary);
}
.rating-stars {
  display: inline-flex;
  gap: 1px;
  font-size: var(--text-lg);
  line-height: var(--leading-none);
}
.star {
  /* The empty slot is a shape the reader has to find in order to count five, so
     it falls under non-text contrast (3:1) rather than decoration. Measured:
     gray-300 is 1.56:1 and gray-400 2.63:1 on white, --text-tertiary is 5.07:1
     light and 7.35:1 on the dark surface. */
  color: var(--text-tertiary);
}
.star.is-filled {
  color: var(--text-warning);
}
/* Half a star: the glyph is clipped by a hard gradient stop, so it needs no
   second element and stays crisp at any size. */
.star.is-half {
  background-image: linear-gradient(90deg, var(--text-warning) 50%, var(--text-tertiary) 50%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.rating-value {
  font-weight: var(--font-semibold);
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
}
.rating-input {
  display: inline-flex;
  gap: var(--space-1);
  margin: 0;
  padding: 0;
  border: 0;
}
.rating-radio {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
.rating-star {
  display: inline-grid;
  place-items: center;
  width: var(--control-h);
  height: var(--control-h);
  font-size: var(--text-2xl);
  line-height: var(--leading-none);
  /* Same reason as .star: an empty, clickable slot has to be findable at 3:1. */
  color: var(--text-tertiary);
  border-radius: var(--radius-base);
  cursor: pointer;
  transition: var(--motion-colors), transform var(--duration-fast) var(--ease-spring);
}
.rating-star:hover {
  transform: translateY(var(--lift-hover-sm));
}
.rating-radio:focus-visible + .rating-star {
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
}
/* The rule is written twice over: without :has() support the chosen star still
   fills, so the control degrades to readable rather than broken. */
.rating-radio:checked + .rating-star,
.rating-star:has(~ .rating-radio:checked),
.rating-star:hover,
.rating-star:has(~ .rating-star:hover) {
  color: var(--text-warning);
}
/* #endregion rating */

/* #region popover */
/* Non-modal surface on hover or focus - the annotation counterpart to
   #dropdown, which is a click-opened menu of choices. It is a sibling of the
   trigger inside .popover-wrap, so :hover and :focus-within both reach it and
   keyboard users get it for free. Surfaces are semantic, so it is correct in
   dark without .invert. */
.popover-wrap {
  position: relative;
  display: inline-flex;
}
.popover-trigger {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--control-h);
  padding: var(--space-2) var(--space-4);
  font: inherit;
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  color: var(--text-primary);
  background: var(--bg-surface);
  border: 1px solid var(--border-medium);
  border-radius: var(--radius-base);
  cursor: pointer;
  transition: var(--motion-colors);
}
.popover-trigger:hover {
  background: var(--bg-surface-hover);
  border-color: var(--border-dark);
}
.popover-trigger:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
}
.popover {
  position: absolute;
  z-index: 40;
  inset-block-end: calc(100% + var(--space-3));
  left: 50%;
  translate: -50% 0;
  width: max-content;
  max-width: min(20rem, 80vw);
  padding: var(--space-4);
  text-align: left;
  background: var(--bg-surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  opacity: 0;
  visibility: hidden;
  transform: translateY(var(--press-depth));
  transition: opacity var(--duration-fast) var(--ease-exit),
    transform var(--duration-fast) var(--ease-exit),
    visibility 0s linear var(--duration-fast);
}
/* Two boxes make hover survivable: ::before bridges the gap so moving the
   pointer from trigger to surface never leaves .popover-wrap, and ::after is
   the arrow, drawn as a rotated square with the surface's own border. */
.popover::before {
  content: "";
  position: absolute;
  inset-block-start: 100%;
  left: 0;
  width: 100%;
  height: var(--space-4);
}
.popover::after {
  content: "";
  position: absolute;
  inset-block-start: 100%;
  left: 50%;
  width: 0.75rem;
  height: 0.75rem;
  translate: -50% -50%;
  rotate: 45deg;
  background: var(--bg-surface);
  border-inline-end: 1px solid var(--hairline);
  border-block-end: 1px solid var(--hairline);
}
.popover-wrap:hover .popover,
.popover-wrap:focus-within .popover,
.popover-wrap.is-open .popover {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: opacity var(--duration-base) var(--ease-enter),
    transform var(--duration-base) var(--ease-enter), visibility 0s;
}
.popover-title {
  display: block;
  margin: 0 0 var(--space-1);
  font-size: var(--text-sm);
  font-weight: var(--font-semibold);
  color: var(--text-primary);
}
.popover-body {
  display: block;
  margin: 0;
  font-size: var(--text-sm);
  line-height: var(--leading-relaxed);
  color: var(--text-secondary);
}
.popover-body a {
  color: var(--text-link);
}
.popover-list {
  display: grid;
  gap: var(--space-2);
  margin: var(--space-3) 0 0;
  padding: 0;
  list-style: none;
  font-size: var(--text-sm);
  color: var(--text-secondary);
}
.popover-list li {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
}
.popover-list svg {
  flex: none;
  width: 1rem;
  height: 1rem;
  margin-top: 3px;
  color: var(--text-success);
}
/* Open below the trigger when the surface would be clipped by the top edge. */
.popover-below {
  inset-block-end: auto;
  inset-block-start: calc(100% + var(--space-3));
}
.popover-below::before {
  inset-block-start: auto;
  inset-block-end: 100%;
}
.popover-below::after {
  inset-block-start: auto;
  inset-block-end: 100%;
  border-inline-end: 0;
  border-block-end: 0;
  border-inline-start: 1px solid var(--hairline);
  border-block-start: 1px solid var(--hairline);
}
.popover-start {
  left: 0;
  translate: 0 0;
}
.popover-start::after {
  left: var(--space-5);
  translate: 0 -50%;
}
/* A centred surface needs half its own width either side of the trigger, so a
   trigger within that distance of a viewport edge spills past it - and a hidden
   surface spills too, because visibility: hidden still lays it out. Anchor the
   near-edge ones instead: .popover-start pins the left, .popover-end the right,
   and the arrow follows. */
.popover-end {
  left: auto;
  right: 0;
  translate: 0 0;
}
.popover-end::after {
  left: auto;
  right: var(--space-5);
  translate: 0 -50%;
}
/* Touch screens have no hover, so the app opens it with a tap and .is-open. */
@media (hover: none) {
  .popover-wrap:hover .popover {
    opacity: 0;
    visibility: hidden;
    transform: translateY(var(--press-depth));
  }
}
/* #endregion popover */

/* #region descriptions */
/* antd's Descriptions - the label/value grid behind every detail panel and
   settings page. The list is a <dl> whose pairs are wrapped in
   .descriptions-item; in the inline layout that wrapper is display: contents,
   so the dt and dd join the parent grid themselves and every label column lines
   up across rows - a nested box can never promise that alignment. The stacked
   variant needs a real box to sit the label above its value, so it puts the
   wrapper back. Column count is an attribute, mirroring the [data-sort] idiom
   in #region tables: data-cols is the only knob a consumer needs. */
.descriptions {
  --desc-cols: 2;
  --desc-label-w: 7.5rem;
  display: grid;
  grid-template-columns: repeat(
    var(--desc-cols),
    minmax(var(--desc-label-w), 1fr) minmax(0, 1.8fr)
  );
  gap: var(--space-4) var(--space-6);
  margin: 0;
  min-width: 0;
  font-size: var(--text-sm);
}
.descriptions[data-cols="1"] {
  --desc-cols: 1;
}
.descriptions[data-cols="3"] {
  --desc-cols: 3;
}
.descriptions-item {
  display: contents;
}
.descriptions-label {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2);
  min-width: 0;
  margin: 0;
  color: var(--text-secondary);
  font-weight: var(--font-medium);
}
.descriptions-value {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2);
  min-width: 0;
  margin: 0;
  color: var(--text-primary);
  /* Values are emails, tracking numbers and URLs - one unbreakable token that
     has to split rather than push the column past the panel. */
  overflow-wrap: break-word;
}
/* Values are frequently a badge, an avatar or a link. Centring the row keeps a
   16px avatar and a 20px pill on the same baseline without nudging the text. */
.descriptions-value a {
  color: var(--text-link);
  text-decoration: none;
  transition: var(--motion-colors);
}
.descriptions-value a:hover {
  color: var(--text-link-hover);
  text-decoration: underline;
}
.descriptions-title {
  margin: 0 0 var(--space-4);
  font-size: var(--text-base);
  font-weight: var(--font-semibold);
  letter-spacing: var(--tracking-tight);
  color: var(--text-primary);
}
/* Label above value: the shape a settings page wants when values are long. */
.descriptions-stacked {
  grid-template-columns: repeat(var(--desc-cols), minmax(0, 1fr));
}
.descriptions-stacked .descriptions-item {
  display: grid;
  gap: var(--space-1);
  min-width: 0;
}
/* Bordered reads as a table, so the gaps close and the rules appear. Two edges
   come from the frame and two from the cells - a full border on the container
   would double the line where the first label and the last row already draw
   their own. */
.descriptions-bordered {
  gap: 0;
  border-block-start: 1px solid var(--hairline);
  border-inline-end: 1px solid var(--hairline);
  border-radius: var(--radius-md);
  background: var(--bg-surface);
  overflow: hidden;
}
.descriptions-bordered .descriptions-label,
.descriptions-bordered .descriptions-value {
  padding: var(--space-3) var(--space-4);
  border-block-end: 1px solid var(--hairline);
}
.descriptions-bordered .descriptions-label {
  background: var(--bg-surface-hover);
  border-inline-start: 1px solid var(--hairline);
}
.descriptions-sm {
  gap: var(--space-3) var(--space-5);
}
.descriptions-lg {
  gap: var(--space-5) var(--space-8);
}
.descriptions-lg .descriptions-label,
.descriptions-lg .descriptions-value {
  font-size: var(--text-base);
}
.descriptions-bordered.descriptions-sm .descriptions-label,
.descriptions-bordered.descriptions-sm .descriptions-value {
  padding: var(--space-2) var(--space-3);
}
@media (max-width: 640px) {
  /* The collapse has to out-specify data-cols, or a three-column panel keeps
     three columns and pushes the page sideways on a phone. */
  .descriptions,
  .descriptions[data-cols] {
    --desc-cols: 1;
  }
}
/* #endregion descriptions */

/* #region datatable */
/* antd's Table - the kit's signature enterprise surface. Everything structural
   stays in #region tables (.table, .table-wrap, .table-compact, .table-striped,
   the [data-sort] caret); this region adds the behaviours around them: row
   selection, a sort button, a column filter, expandable rows, in-table states
   and a scroll frame with a head that gets a rule only once rows pass under
   it. */

/* The frame. min-width is wider than a plain .table because eight real columns
   at 40rem would wrap; the wrap still pans instead of squeezing the page. */
.table.datatable {
  min-width: var(--table-min-w, 54rem);
}
.table-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3) var(--space-4);
  margin-block-end: var(--space-4);
}
/* The search box is the only toolbar control that has to give way on a narrow
   screen, so it grows but never past a readable line length. */
.table-search {
  flex: 1 1 13rem;
  min-inline-size: 11rem;
  max-inline-size: 20rem;
}
.table-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3) var(--space-4);
  margin-block-start: var(--space-4);
}
.table-foot .select-wrap {
  inline-size: 7.5rem;
  flex: none;
}
.table-foot-count {
  font-size: var(--text-sm);
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}
/* Sticky head inside a scroll frame. thead th is already sticky (#region
   tables), so .table-scroll only supplies the height to stick against. The
   rule under it is drawn by the header's own ::after and stays at zero until
   the frame scrolls - a hairline that is always on would read as a second
   border. #region navigation raises .is-scrolled the same way on the navbar. */
.table-scroll {
  max-height: var(--table-max-h, 26rem);
  overflow: auto;
}
.table-scroll .table thead th::after {
  content: "";
  position: absolute;
  inset-block-start: 100%;
  inset-inline: 0;
  height: 1px;
  background: var(--hairline);
  box-shadow: var(--shadow-xs);
  opacity: 0;
  transition: opacity var(--duration-base) var(--ease-standard);
}
.table-scroll.is-scrolled .table thead th::after {
  opacity: 1;
}
/* Sort control. A real <button> so the column is reachable by Tab and Enter;
   aria-sort stays on the th, because that is the element AT reports as the
   column header. The cell loses its padding and the button takes it, which is
   what keeps the target a full 44px instead of a 14px caret. */
.sort-btn {
  display: flex;
  align-items: center;
  gap: 0;
  width: 100%;
  min-height: var(--control-h);
  padding: 0 var(--space-4);
  font: inherit;
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  text-align: start;
  color: var(--text-secondary);
  background: none;
  border: 0;
  border-radius: 0;
  cursor: pointer;
  transition: var(--motion-colors);
}
.sort-btn:hover {
  color: var(--text-primary);
  background: var(--bg-surface-active);
}
.sort-btn:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: -2px;
  box-shadow: var(--ring-focus);
}
.table th:has(.sort-btn) {
  padding: 0;
}
/* The third state. [data-sort="asc"] and [data-sort="desc"] already draw a
   caret in #region tables; an unsorted column needs a faint neutral one so the
   affordance is visible before the first click. */
.table [data-sort="none"]::after {
  border-block-end: 4px solid currentColor;
  opacity: 0.3;
}
.table th[aria-sort="ascending"] .sort-btn,
.table th[aria-sort="descending"] .sort-btn {
  color: var(--text-primary);
}
.table th[aria-sort="ascending"] .sort-btn::after,
.table th[aria-sort="descending"] .sort-btn::after {
  opacity: 1;
}
/* Column filter. The whole header cell is the trigger, which is what makes the
   target 44px without a second row of controls; the menu itself stays
   #region dropdown's. is-filtered is the only cue that a column is narrowed -
   the funnel takes the link colour so the header reads as edited. */
.table th:has(.th-filter) {
  padding: 0;
}
.cell-filter .dropdown {
  display: block;
}
.th-filter {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: var(--space-2);
  width: 100%;
  min-height: var(--control-h);
  padding: 0 var(--space-3) 0 var(--space-4);
  font: inherit;
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  text-align: start;
  color: var(--text-secondary);
  background: none;
  border: 0;
  cursor: pointer;
  transition: var(--motion-colors);
}
.th-filter:hover {
  color: var(--text-primary);
  background: var(--bg-surface-active);
}
.th-filter:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: -2px;
  box-shadow: var(--ring-focus);
}
.th-filter svg {
  width: 0.875rem;
  height: 0.875rem;
  flex: none;
  color: var(--text-tertiary);
}
.th-filter.is-filtered,
.th-filter.is-filtered svg {
  color: var(--text-link);
}
/* Selection. The check cell is a .checkbox from #region choice, stripped of the
   label's vertical padding because the cell now owns the row's height. */
.cell-check {
  width: 3.5rem;
  padding-block: 0;
  padding-inline: var(--space-4) var(--space-2);
}
.cell-toggle {
  width: 3.5rem;
  padding-block: 0;
  padding-inline: var(--space-2);
  text-align: center;
}
.table .cell-check .checkbox {
  min-height: var(--control-h);
  padding: 0;
  align-items: center;
}
.table .cell-check .box {
  margin-top: 0;
}
/* The header checkbox spends its life between checked and unchecked: mixed.
   A dash, not a tick, is what tells the reader "some, not all". */
.checkbox input:indeterminate + .box {
  background: var(--primary-bg);
  border-color: var(--primary-bg);
}
.checkbox input:indeterminate + .box::after {
  content: "";
  position: absolute;
  inset-block-start: 50%;
  inset-inline: 3px;
  height: 2px;
  translate: 0 -50%;
  background: var(--primary-fg);
  border-radius: var(--radius-full);
}
/* Ordered after #region tables on purpose: .is-selected and the striped even
   row have the same specificity, so source order is the tie-break. */
.table tbody tr.is-selected,
.table-striped tbody tr.is-selected {
  background: var(--tint-primary);
}
.table tbody tr.is-selected:hover {
  background: var(--tint-primary-strong);
}
.table-selection {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2) var(--space-4);
  margin-block-end: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--tint-primary);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-base);
}
.table-selection-count {
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}
/* The bar is a flexbox, so it has to out-specify the UA [hidden] rule or the
   "0 selected" strip can never be put away. */
.table-selection[hidden] {
  display: none;
}
/* Column filter: #region dropdown for the surface, #region choice for the
   boxes. The menu is padding and typography only - it must survive being
   opened inside a scroll frame, so it stays short. */
.menu-filter {
  min-width: 13rem;
  padding: var(--space-2);
  display: grid;
  gap: var(--space-1);
  /* The menu lives inside a thead cell, so it would otherwise inherit the
     header's uppercase and shout at the data ("DISPUTED" not "Disputed"). */
  text-transform: none;
}
.menu-filter-head {
  padding: var(--space-1) var(--space-3) var(--space-2);
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--text-tertiary);
}
.menu-filter-option {
  min-height: var(--control-h);
  padding: 0 var(--space-3);
  font-size: var(--text-sm);
  align-items: center;
  border-radius: var(--radius-base);
  transition: var(--motion-colors);
}
.menu-filter-option:hover {
  background: var(--tint-primary);
}
.menu-filter-option .box {
  margin-top: 0;
}
.menu-filter-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding-block: var(--space-1);
}
/* Expandable rows. The caret is the whole control, so it gets a 44px box and
   the cell gives up its padding to hold the row at one height. */
.row-toggle {
  display: inline-grid;
  place-items: center;
  width: var(--control-h);
  height: var(--control-h);
  padding: 0;
  color: var(--text-secondary);
  background: none;
  border: 0;
  border-radius: var(--radius-base);
  cursor: pointer;
  transition: var(--motion-colors), transform var(--duration-tick) var(--ease-exit);
}
.row-toggle:hover {
  color: var(--text-primary);
  background: var(--bg-surface-active);
}
.row-toggle:active {
  transform: translateY(var(--press-depth));
}
.row-toggle:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: -2px;
  box-shadow: var(--ring-focus);
}
.row-toggle svg {
  width: 1rem;
  height: 1rem;
  transition: transform var(--duration-base) var(--ease-out-expo);
}
.row-toggle[aria-expanded="true"] svg {
  transform: rotate(90deg);
}
/* The detail panel is inset to the row content it belongs to and carries
   .descriptions, never a second table. It has to out-specify .table td to
   undo the nowrap that the columns above it rely on. */
.table td.table-detail {
  padding: 0;
  white-space: normal;
  background: var(--bg-body);
  border-block-end: 1px solid var(--hairline);
}
.table-detail-inner {
  padding: var(--space-5) var(--space-5) var(--space-6) calc(var(--space-4) + var(--space-8));
  animation: mue-detail-open var(--duration-slow) var(--ease-enter);
}
@keyframes mue-detail-open {
  from {
    opacity: 0;
    transform: translateY(calc(var(--reveal-shift) / -2));
  }
}
/* In-table states. A skeleton cell takes its width from --sk-w so the columns
   keep their proportions while loading - the shape of the answer is visible
   before the answer is. */
.sk-cell {
  display: inline-block;
  inline-size: var(--sk-w, 6rem);
  block-size: 0.75rem;
  vertical-align: middle;
}
.table .table-empty {
  padding: var(--space-4);
  white-space: normal;
}
.table .table-empty .empty {
  border: 0;
  background: none;
  padding: var(--space-8) var(--space-4);
}
/* Money and counts align right, so the column sums by eye. */
.table .col-num {
  text-align: end;
  font-variant-numeric: tabular-nums;
}
.table th.col-num .sort-btn {
  justify-content: flex-end;
}
/* Paging and filtering hide rows with the hidden attribute. This is a guard,
   not a fix: any author-side display on a row would beat the UA's [hidden]
   rule, and a filtered-out row that keeps painting is the worst kind of bug. */
.table tr[hidden],
.table tbody[hidden] {
  display: none;
}
/* The two-line cell an identity column needs: the name carries the scan and
   the sub-line the context, and the pair stays on one baseline with the avatar. */
.cell-user {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-width: 0;
}
.cell-user > :last-child {
  display: block;
  min-width: 0;
}
.cell-user-name {
  display: block;
  font-weight: var(--font-medium);
  color: var(--text-primary);
}
.cell-user-sub {
  display: block;
  font-size: var(--text-xs);
  font-weight: var(--font-normal);
  letter-spacing: var(--tracking-normal);
  text-transform: none;
  /* The email is content, not a caption: tertiary grey at 12px lands under 4.5:1
     once the row's selected tint sits underneath it. */
  color: var(--text-secondary);
  overflow-wrap: anywhere;
}
@media (max-width: 640px) {
  .table-detail-inner {
    padding-inline-start: var(--space-4);
  }
}
/* #endregion datatable */

/* #region guidance */
/* antd's Tour and FloatButton: the two surfaces that live on top of the app
   rather than inside it. */

/* The stage is what turns the highlight into a spotlight. .tour-target paints a
   9999px scrim as its own box-shadow, and the clipped frame makes that scrim
   stop at the edge of the surface being taught - no overlay element needed. */
.tour-stage {
  position: relative;
  overflow: hidden;
}
.tour {
  position: relative;
  display: inline-flex;
  max-width: 100%;
}
.tour-target {
  position: relative;
  z-index: 2;
  border-radius: var(--radius-md);
  transition: var(--motion-colors);
}
.tour.is-open > .tour-target {
  box-shadow: 0 0 0 2px var(--primary-bg), 0 0 0 6px var(--state-focus-ring),
    0 0 0 9999px var(--scrim);
}
.tour-card {
  position: relative;
  /* Not 100%: inside a tour the card's containing block is its own target,
     which is often a 90px button. The viewport gutter is the only measure
     that keeps the card readable and off the edge of a phone. */
  inline-size: min(21rem, calc(100vw - 4rem));
  padding: var(--space-5);
  background: var(--bg-surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-xl);
  color: var(--text-primary);
  z-index: 3;
}
/* Inside a tour the card is pinned to its target and only arrives when that
   step is open. A bare .tour-card stays in the flow, which is how the variant
   row can show one without a target. */
.tour > .tour-card {
  position: absolute;
  inset-block-start: calc(100% + var(--space-8));
  inset-inline-start: 0;
  opacity: 0;
  visibility: hidden;
  transform: translateY(calc(var(--reveal-shift) / -2));
  transition: var(--motion-reveal), visibility 0s linear var(--duration-slower);
}
.tour.is-open > .tour-card {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: var(--motion-reveal);
}
.tour-end > .tour-card {
  inset-inline-start: auto;
  inset-inline-end: 0;
}
.tour-top > .tour-card {
  inset-block-start: auto;
  inset-block-end: calc(100% + var(--space-8));
}
/* The notch is the popover arrow with the card's own surface and border. */
.tour-arrow {
  position: absolute;
  inset-block-start: calc(var(--space-2) * -1);
  inset-inline-start: var(--space-8);
  width: 0.875rem;
  height: 0.875rem;
  translate: 0 -50%;
  rotate: 45deg;
  background: var(--bg-surface);
  border-inline-start: 1px solid var(--hairline);
  border-block-start: 1px solid var(--hairline);
}
.tour-end .tour-arrow {
  inset-inline-start: auto;
  inset-inline-end: var(--space-8);
}
.tour-top .tour-arrow {
  inset-block-start: auto;
  inset-block-end: calc(var(--space-2) * -1);
  translate: 0 50%;
  rotate: 225deg;
}
.tour-step {
  margin: 0 0 var(--space-2);
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--text-tertiary);
  font-variant-numeric: tabular-nums;
}
.tour-title {
  margin: 0 0 var(--space-2);
  font-size: var(--text-lg);
  font-weight: var(--font-semibold);
  letter-spacing: var(--tracking-tight);
  color: var(--text-primary);
}
.tour-body {
  margin: 0 0 var(--space-4);
  font-size: var(--text-sm);
  line-height: var(--leading-relaxed);
  color: var(--text-secondary);
}
.tour-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}
.tour-dots {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin-inline-end: var(--space-2);
}
.tour-dots .dot {
  width: 6px;
  height: 6px;
  background: var(--bg-surface-active);
}
.tour-dots .is-current {
  width: 14px;
  background: var(--primary-bg);
}
/* FloatButton: 44px, circular, and the group is the dock - stacking is just
   that column, so two buttons never need a new position. */
.float-btn {
  display: inline-grid;
  place-items: center;
  inline-size: var(--control-h);
  block-size: var(--control-h);
  padding: 0;
  font: inherit;
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  color: var(--text-primary);
  background: var(--bg-surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-full);
  box-shadow: var(--shadow-md);
  cursor: pointer;
  text-decoration: none;
  transition: var(--motion-lift);
}
.float-btn:hover {
  color: var(--text-link);
  box-shadow: var(--shadow-lg);
  transform: translateY(var(--lift-hover));
}
.float-btn:active {
  transform: translateY(var(--press-depth));
}
.float-btn:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
  box-shadow: var(--ring-focus);
}
.float-btn svg {
  width: 1.25rem;
  height: 1.25rem;
  flex: none;
}
.float-btn-primary {
  background: var(--primary-bg);
  border-color: transparent;
  color: var(--primary-fg);
}
.float-btn-primary:hover {
  background: var(--primary-hover);
  color: var(--primary-fg);
}
/* Label beside the glyph - the shape that needs a tooltip-free explanation. */
.float-btn-label {
  inline-size: auto;
  grid-auto-flow: column;
  gap: var(--space-2);
  padding: 0 var(--space-4);
}
.float-btn-group {
  position: fixed;
  z-index: 45;
  inset-inline-end: var(--space-6);
  inset-block-end: var(--space-6);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  opacity: 0;
  visibility: hidden;
  transform: translateY(var(--reveal-shift-lg));
  transition: var(--motion-reveal), visibility 0s linear var(--duration-slower);
}
.float-btn-group.is-visible {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: var(--motion-reveal);
}
@media (max-width: 640px) {
  .float-btn-group {
    inset-inline-end: var(--space-4);
    inset-block-end: var(--space-4);
  }
}
/* #endregion guidance */
