/* --- tokens.css --- */
/* ============================================================
   SEMÁFORO — portable design tokens (ds-portable, 2026-08-26)
   The shipped "technical dopamine" system, exported flat at :root
   (no page-class scope needed): a six-step technical gray ladder
   does the depth (NO drop shadows), the primary action is INK, and
   five saturated accents each own a JOB. Doctrine:
     - Vivid fills carry INK on top (white only on deep tones).
     - No pastel tints: a surface is fully saturated or technical gray.
     - Secondary buttons are FILLED gray, never outline-only.
     - Borders: rest B1 · hover B3 · focus = 2px ink ring.
     - Inputs REST on the page gray (--color-field), wake white on focus.
   Two levels:
     1. Primitives: raw palette and scales. Never used by components.
     2. Semantic: what components consume. Retheme HERE only.
   Breakpoints (custom properties don't work in media queries):
     480px (sm) · 768px (md) · 1024px (lg) · 1280px (xl)
   ============================================================ */

:root {
  /* ---------- 1. PRIMITIVES ---------- */

  /* Accents with JOBS (rotation by section, never at random):
     naranja = CTA/energía (spend it where money or the main ask lives)
     amarillo = destacar/ofertas/"Nuevo"/bandas de aviso
     verde = éxito/positivo/canal de venta
     azul = información/enlaces/estados neutrales-positivos
     bermellón = destructivo (vivo, no el rojo de librería)
     lila = "editado"/marcas de trabajo en curso */
  --accent-orange: #FF5000;
  --accent-yellow: #FFCC00;
  --accent-green:  #37AA65;
  --accent-blue:   #508EDC;
  --accent-verm:   #EC5011;
  --accent-lilac:  #B680D2;

  /* Technical grays (pure, no warm cast) */
  --neutral-0:   #FFFFFF;
  --neutral-50:  #F8F8F8;
  --neutral-100: #F4F4F4;
  --neutral-200: #ECECEC;
  --neutral-300: #DDDDDD;
  --neutral-400: #B3B3B3;
  --neutral-500: #6E6E6E;
  --neutral-600: #555555;
  --neutral-700: #3C3C3C;
  --neutral-800: #2E2E2E;
  --neutral-900: #282828;
  --neutral-950: #111111;

  /* Green ramp (success / selling channel) */
  --green-50:  #E4F3EA;
  --green-100: #C9E7D4;
  --green-200: #9AD4B2;
  --green-500: #37AA65;
  --green-600: #2E9155;
  --green-700: #27793F;
  --green-800: #1F6434;

  /* Red ramp (danger = vivid vermilion, not library red) */
  --red-50:  #FDE9E0;
  --red-100: #FAD4C3;
  --red-600: #EC5011;
  --red-700: #C9430E;

  /* Amber ramp (warning / offers = the yellow family) */
  --amber-50:  #FFF6CC;
  --amber-100: #FFF3C4;
  --amber-500: #FFCC00;
  --amber-800: #7A5A00;

  /* Purple ramp (edited / bulk-changed marks) */
  --purple-50:  #F7F0FB;
  --purple-100: #EFE2F7;
  --purple-200: #E2CCF0;
  --purple-300: #D0ACE4;
  --purple-400: #C094DB;
  --purple-600: #B680D2;
  --purple-700: #7A4E96;
  --purple-800: #5F3A77;

  /* Typography */
  --font-sans: "Geist", system-ui, -apple-system, "Segoe UI", sans-serif;
  /* El kit consumia --font-mono con fallback y nunca lo definia, y varios
     componentes escribian `ui-monospace, monospace` a mano. Se define. */
  --font-mono: "Geist Mono", ui-monospace, "SF Mono", Consolas, monospace;
  /* Una sola familia por ahora. Cuando un evento suba la suya (fase 6), lo
     que cambia es esta ficha, no los componentes. */
  --font-display: var(--font-sans);

  --text-xs:  0.75rem;    /* 12px */
  --text-sm:  0.875rem;   /* 14px */
  --text-md:  1rem;       /* 16px — base */
  --text-lg:  1.125rem;   /* 18px */
  --text-xl:  1.25rem;    /* 20px */
  --text-2xl: 1.5rem;     /* 24px */
  --text-3xl: 1.875rem;   /* 30px */
  --text-4xl: 2.25rem;    /* 36px */
  --text-5xl: 3rem;       /* 48px */

  --leading-tight:   1.15; /* large headings */
  --leading-snug:    1.3;  /* small headings, labels */
  --leading-normal:  1.5;  /* body */
  --leading-relaxed: 1.65; /* long paragraphs */

  --weight-regular:  400;
  --weight-medium:   500;
  --weight-semibold: 600;
  --weight-bold:     700;

  --tracking-tight: -0.02em; /* headings ≥ 2xl */
  --tracking-snug:  -0.01em; /* small headings */

  /* Spacing — 4px base scale */
  --space-1:  0.25rem;  /*  4px */
  --space-2:  0.5rem;   /*  8px */
  --space-3:  0.75rem;  /* 12px */
  --space-4:  1rem;     /* 16px */
  --space-5:  1.25rem;  /* 20px */
  --space-6:  1.5rem;   /* 24px */
  --space-8:  2rem;     /* 32px */
  --space-10: 2.5rem;   /* 40px */
  --space-12: 3rem;     /* 48px */
  --space-16: 4rem;     /* 64px */
  --space-20: 5rem;     /* 80px */
  --space-24: 6rem;     /* 96px */

  /* Radii — official scale: 4, 6, 8, 12, 16, 20, 24, 32. */
  --radius-xs:   4px;
  --radius-sm:   6px;
  --radius-md:   8px;
  --radius-lg:   12px;
  --radius-xl:   16px;
  --radius-2xl:  20px;
  --radius-3xl:  24px;
  --radius-4xl:  32px;
  --radius-full: 9999px;

  /* Radius ROLES: chrome consumes these, not the raw scale. Standalone
     cards / section containers / floating panels = card (16); media
     thumbnails >= 6rem = thumb (12); tiny thumbs and controls keep
     --radius-md (8); chips inside a padded card = container minus padding. */
  --radius-card:  var(--radius-xl);
  --radius-thumb: var(--radius-lg);

  /* Shadows: OFF by doctrine — depth comes from the gray ladder and
     borders. The tokens stay so components keep compiling; re-enable per
     project if you must (you probably must not). */
  --shadow-xs: none;
  --shadow-sm: none;
  --shadow-md: none;
  --shadow-lg: none;

  /* Layers */
  --z-dropdown: 100;
  --z-sticky:   200;
  --z-modal:    400;
  --z-toast:    500;

  /* Motion */
  --duration-fast:   120ms;
  --duration-base:   200ms;
  --duration-slow:   320ms;
  --ease-out: cubic-bezier(0.2, 0, 0, 1);

  /* ---------- 2. SEMANTIC (components consume ONLY these) ---------- */

  /* The gray ladder: L0 page · L1 card · L2 sunken tile · B1/B2/B3 borders */
  --color-bg:            var(--neutral-100);
  --color-surface:       var(--neutral-0);
  --color-surface-muted: var(--neutral-200);
  --color-border:        var(--neutral-300);
  --color-border-strong: #C7C7C7;
  --color-border-hover:  var(--neutral-400);
  --color-border-accent: var(--neutral-400);
  /* Modal/lightbox veil */
  --color-backdrop:      rgba(40, 40, 40, 0.55);

  --color-text:        var(--neutral-900);
  --color-text-muted:  var(--neutral-500);
  --color-text-subtle: #A9A9A9;

  /* Primary action: poster INK */
  --color-action:       var(--neutral-900);
  --color-action-hover: var(--neutral-950);
  --color-on-action:    var(--neutral-0);

  /* Success / selling-channel green. Vivid green fills take INK on top;
     the strong/hover steps are deep enough for white if a component
     insists (buttons use strong). */
  --color-accent:        var(--green-500);
  --color-accent-strong: var(--green-700);
  --color-accent-hover:  var(--green-800);
  --color-accent-soft:   var(--green-50);
  --color-on-accent:     var(--neutral-0);

  /* Danger: vivid vermilion with ink on top */
  --color-danger:       var(--red-600);
  --color-danger-hover: #D64509;
  --color-danger-soft:  var(--red-50);
  --color-on-danger:    var(--neutral-900);

  /* Marketing CTA orange: spend it ONLY where the main ask lives */
  --color-cta:       var(--accent-orange);
  --color-cta-hover: #D64300;
  --color-on-cta:    var(--neutral-900);

  /* Info / links blue (white ink on top — it is the one deep accent) */
  --color-info: var(--accent-blue);

  /* Highlight yellow: offers, "new", plan bands. Solid chips take ink
     directly (deep = the yellow itself). */
  --color-highlight:        var(--amber-500);
  --color-highlight-soft:   var(--amber-100);
  --color-highlight-border: #EFD24D;
  --color-highlight-text:   var(--amber-800);
  --color-highlight-deep:   var(--amber-500);
  --color-on-highlight:     var(--neutral-900);

  --color-warning:      var(--amber-500);
  --color-warning-soft: var(--amber-50);
  --color-warning-text: var(--amber-800);

  --color-focus: var(--neutral-900);

  /* Inputs REST on the page gray so they read layered inside white cards
     (they wake to --color-surface + an ink ring on focus). */
  --color-field: var(--neutral-100);
}

/* --- base.css --- */
/* ============================================================
   base — reset, tipografia y @font-face. Necesita tokens.css.

   Portado de ds-portable-semaforo. Se tomaron el reset y la
   jerarquia tipografica; se descarto la maquinaria de otro
   producto (cc-boot, cc-scroll-lock, cc-admin), que dependia de
   un i18n y de un flujo de sesion que aca no existen.

   Las fuentes son LOCALES, no de Google Fonts. En un salon con
   mal internet un host externo mas es una cosa mas que puede
   fallar delante de 150 personas.
   ============================================================ */

@font-face {
  font-family: "Geist";
  src: url("fuentes/Geist-Variable.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

/* El kit trae el archivo pero nunca lo declara: los componentes que
   piden mono caen a la del sistema. Se declara aca. */
@font-face {
  font-family: "Geist Mono";
  src: url("fuentes/GeistMono-Variable.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
/* ---------- Reset ---------- */

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

* {
  margin: 0;
}

/* The hidden attribute must win over any component display value
   (e.g. .field { display: flex }), so conditional fields stay hidden. */
[hidden] {
  display: none !important;
}

html {
  -webkit-text-size-adjust: 100%;
  tab-size: 4;
}

body {
  font-family: var(--font-sans);
  font-size: var(--text-md);
  line-height: var(--leading-normal);
  color: var(--color-text);
  background: var(--color-bg);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

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

input,
button,
textarea,
select {
  font: inherit;
  color: inherit;
}

/* ---------- Type hierarchy ---------- */

h1,
h2,
h3,
h4 {
  font-weight: var(--weight-semibold);
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-snug);
  text-wrap: balance;
}

h1 {
  font-size: var(--text-4xl);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
}

h2 {
  font-size: var(--text-2xl);
  letter-spacing: var(--tracking-tight);
}

h3 {
  font-size: var(--text-xl);
}

h4 {
  font-size: var(--text-md);
}

p {
  max-width: 65ch;
}

small {
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

a {
  color: inherit;
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}

::selection {
  background: var(--color-accent-soft, var(--green-100));
}

/* ---------- Focus & interaction ---------- */

:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 2px;
  border-radius: var(--radius-xs);
}

button {
  cursor: pointer;
}

button:disabled {
  cursor: not-allowed;
  opacity: 0.5;
}

/* Full-screen dialogs lock the page behind them (any viewport). */
html.cc-scroll-lock,
html.cc-scroll-lock body { overflow: hidden; }

/* ---------- Accessibility ---------- */

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ---------- Skeleton loading placeholder ---------- */
/* A moving sheen instead of a spinner. Use on a block sized by the caller:
   <div class="skeleton" style="height: 1rem"></div> */
.skeleton {
  position: relative;
  overflow: hidden;
  background: var(--color-surface-muted);
  border-radius: var(--radius-sm);
}
.skeleton::after {
  content: "";
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.7), transparent);
  animation: skeleton-shimmer 1.4s ease-in-out infinite;
}
@keyframes skeleton-shimmer { 100% { transform: translateX(100%); } }

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

/* --- componentes/button.css --- */
/* Button — variants: primary (neutral action), accent (WhatsApp/positive),
   secondary, ghost, danger. Sizes: sm, md (default), lg. */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: 0 var(--space-4);
  height: 2.5rem; /* 40px */
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  transition: background var(--duration-fast) var(--ease-out),
    border-color var(--duration-fast) var(--ease-out),
    color var(--duration-fast) var(--ease-out),
    transform var(--duration-fast) var(--ease-out);
}

/* Press: a tiny dip confirms the tap. */
.btn:active { transform: scale(0.97); }
.btn:disabled { transform: none; }

.btn svg {
  width: 1rem;
  height: 1rem;
  flex-shrink: 0;
}

.btn--primary {
  background: var(--color-action);
  color: var(--color-on-action);
}

.btn--primary:hover {
  background: var(--color-action-hover);
}

.btn--accent {
  background: var(--color-accent-strong);
  color: var(--color-on-accent);
}

.btn--accent:hover {
  background: var(--color-accent-hover);
}

.btn--secondary {
  background: var(--color-surface);
  border-color: var(--color-border-strong);
  color: var(--color-text);
}

.btn--secondary:hover {
  border-color: var(--color-border-accent);
  background: var(--color-surface-muted);
}

.btn--ghost {
  background: transparent;
  color: var(--color-text-muted);
}

.btn--ghost:hover {
  background: var(--color-surface-muted);
  color: var(--color-text);
}

.btn--danger {
  background: var(--color-danger);
  color: var(--color-on-danger, var(--color-on-action));
}

.btn--danger:hover {
  background: var(--color-danger-hover);
}

.btn--sm {
  height: 2rem;
  padding: 0 var(--space-3);
  border-radius: var(--radius-sm);
  font-size: var(--text-xs);
}

.btn--lg {
  height: 3rem;
  padding: 0 var(--space-6);
  border-radius: var(--radius-lg);
  font-size: var(--text-md);
}

.btn--block {
  width: 100%;
}

/* --- componentes/field.css --- */
/* Form field — label + control + hint/error.
   Structure:
   <div class="field">
     <label class="field__label" for="x">…</label>
     <input class="field__control" id="x">
     <p class="field__hint">…</p>   |   <p class="field__error">…</p>
   </div> */

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

.field__label {
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  line-height: var(--leading-snug);
}

.field__label small {
  font-weight: var(--weight-regular);
}

.field__control {
  width: 100%;
  height: 2.5rem;
  padding: 0 var(--space-3);
  /* Themed checkouts fill with --color-field (the page bg) so inputs read
     against their surface card; unthemed keeps the surface fill. */
  background: var(--color-field, var(--color-surface));
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-md);
  font-size: var(--text-sm);
  transition: border-color var(--duration-fast) var(--ease-out);
}

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

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

/* Focus: border goes ink, crisp inset edge, no floating outline ring. */
.field__control:focus-visible {
  outline: none;
  border-color: var(--color-action);
  box-shadow: inset 0 0 0 1px var(--color-action);
  background: var(--color-surface); /* rests gray (--color-field), wakes white */
}

textarea.field__control {
  height: auto;
  min-height: 5.5rem;
  padding: var(--space-3);
  resize: vertical;
  line-height: var(--leading-normal);
}

select.field__control {
  appearance: none;
  padding-right: var(--space-8);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='none' stroke='%2378716C' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m4 6 4 4 4-4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--space-3) center;
}

.field__hint {
  font-size: var(--text-xs);
  color: var(--color-text-muted);
}

.field__error {
  font-size: var(--text-xs);
  color: var(--color-danger);
}

.field--invalid .field__control {
  border-color: var(--color-danger);
}

/* Error takes precedence: hover and focus keep the danger color, they never
   override it with ink. Focus just intensifies the red with a crisp inset edge. */
.field--invalid .field__control:hover {
  border-color: var(--color-danger);
}

.field--invalid .field__control:focus-visible {
  border-color: var(--color-danger);
  box-shadow: inset 0 0 0 1px var(--color-danger);
}

/* Fixed prefix (e.g. compra.chat/ + username) */
.field__group {
  display: flex;
  align-items: stretch;
}

.field__group .field__prefix {
  display: flex;
  align-items: center;
  padding: 0 var(--space-3);
  background: var(--color-surface-muted);
  border: 1px solid var(--color-border-strong);
  border-right: 0;
  border-radius: var(--radius-md) 0 0 var(--radius-md);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  white-space: nowrap;
}

.field__group .field__control {
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
}

/* --- componentes/card.css --- */
/* Card — generic container surface for panels and lists. */

.card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-xs);
}

.card__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--color-border);
}

.card__title {
  font-size: var(--text-md);
  font-weight: var(--weight-semibold);
}

.card__body {
  padding: var(--space-5);
}

.card__footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  border-top: 1px solid var(--color-border);
  background: var(--color-surface-muted);
  border-radius: 0 0 var(--radius-card) var(--radius-card);
}

.card--interactive {
  transition: border-color var(--duration-fast) var(--ease-out),
    box-shadow var(--duration-fast) var(--ease-out);
}

.card--interactive:hover {
  border-color: var(--color-border-strong);
  box-shadow: var(--shadow-sm);
}

/* --- componentes/badge.css --- */
/* Badge — statuses and short labels (plan, offer, draft…). */

.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 2px var(--space-2);
  border-radius: var(--radius-full);
  border: 1px solid transparent;
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  line-height: var(--leading-snug);
  white-space: nowrap;
}

.badge--neutral {
  background: var(--color-surface-muted);
  border-color: var(--color-border);
  color: var(--color-text-muted);
}

.badge--accent {
  background: var(--color-accent-soft);
  border-color: var(--green-200);
  color: var(--green-800);
}

.badge--warning {
  background: var(--color-warning-soft);
  border-color: var(--amber-100);
  color: var(--color-warning-text);
}

.badge--danger {
  background: var(--color-danger-soft);
  border-color: var(--red-100);
  color: var(--red-700);
}

/* Solido y no pastel: una superficie esta saturada del todo o es gris tecnico.
   El kit tenia esta version detras de `.cc-admin` y la pastel como base; aca
   la solida es la base, que es la que aguanta los 27 temas oscuros. */
.badge--accent {
  background: var(--color-accent);
  border-color: transparent;
  color: var(--color-on-accent);
}
.badge--warning {
  background: var(--color-highlight-deep);
  border-color: transparent;
  color: var(--color-on-highlight);
}
.badge--danger {
  background: var(--color-danger);
  border-color: transparent;
  color: var(--color-on-danger);
}

/* --- componentes/switch.css --- */
/* Switch — enable/disable optional modules and sections.
   <label class="switch">
     <input type="checkbox" role="switch">
     <span class="switch__track" aria-hidden="true"></span>
     <span class="switch__label">…</span>
   </label> */

.switch {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  cursor: pointer;
  user-select: none;
}

.switch input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}

/* DEFAULT = the rounded, non-growing model (user pick 2026-08-22: the old
   squared/stretching knob was retired site-wide; .switch--m3 stays as an
   inert alias so existing markup needs no edits). On-state wears the brand
   action color. */
.switch__track {
  position: relative;
  width: 2.875rem;
  height: 1.625rem;
  flex-shrink: 0;
  background: var(--color-border-strong);
  border-radius: var(--radius-full);
  transition: background var(--duration-base) var(--ease-out);
}

.switch__track::after {
  content: "";
  position: absolute;
  top: 4px;
  left: 4px;
  width: 1.125rem;
  height: 1.125rem;
  background: var(--color-surface);
  border-radius: var(--radius-full);
  box-shadow: var(--shadow-xs);
  transition: translate var(--duration-base) var(--ease-out);
}

.switch input:checked + .switch__track {
  background: var(--color-action);
}

.switch input:checked + .switch__track::after {
  translate: 1.25rem 0;
}

.switch input:focus-visible + .switch__track {
  outline: 2px solid var(--color-focus);
  outline-offset: 2px;
}

.switch__label {
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
}

/* --- componentes/table.css --- */
/* Table — panel lists (inventory, catalogs).
   Wrap in .table-wrap for horizontal scroll on small screens. */

.table-wrap {
  overflow-x: auto;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  background: var(--color-surface);
}

.table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
}

.table th {
  padding: var(--space-3) var(--space-4);
  text-align: left;
  font-weight: var(--weight-semibold);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  background: var(--color-surface-muted);
  border-bottom: 1px solid var(--color-border);
  white-space: nowrap;
}

.table td {
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--color-border);
  vertical-align: middle;
}

.table tbody tr:last-child td {
  border-bottom: 0;
}

.table tbody tr:hover {
  background: var(--neutral-50);
}

.table__num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.table th.table__num {
  text-align: right;
}

/* --- componentes/menu.css --- */
/* Dropdown menu — for the topnav avatar and contextual actions.
   Structure:
   <div class="menu">
     <button …trigger…>
     <div class="menu__list" role="menu">
       <div class="menu__header">…</div>
       <a class="menu__item">…</a>
       <button class="menu__item menu__item--danger">…</button>
     </div>
   </div>
   JS: toggles .is-open on .menu; closes on outside click and Escape. */

.menu {
  position: relative;
}

.menu__list {
  position: absolute;
  right: 0;
  top: calc(100% + var(--space-2));
  min-width: 13rem;
  padding: var(--space-2);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-md);
  z-index: var(--z-dropdown);
  transform-origin: top;
  display: none;
}

.menu.is-open .menu__list {
  display: block;
  animation: menu-in var(--duration-fast) var(--ease-out);
}

@keyframes menu-in {
  from {
    opacity: 0;
    translate: 0 -6px;
    scale: 0.98;
  }
}

.menu__header {
  padding: var(--space-2) var(--space-3) var(--space-3);
  margin-bottom: var(--space-2);
  border-bottom: 1px solid var(--color-border);
}

.menu__header b {
  display: block;
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
}

.menu__header span {
  font-size: var(--text-xs);
  color: var(--color-text-muted);
}

.menu__item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
  padding: var(--space-2) var(--space-3);
  border: 0;
  border-radius: var(--radius-md); /* container (16) minus its padding (8) */
  background: none;
  font-size: var(--text-sm);
  color: var(--color-text);
  text-decoration: none;
  text-align: left;
  transition: background var(--duration-fast) var(--ease-out);
}

.menu__item:hover {
  background: var(--color-surface-muted);
}

.menu__item[aria-current="page"] {
  background: var(--color-surface-muted);
  color: var(--color-text);
  font-weight: var(--weight-medium);
}

.menu__item svg,
.menu__item .ic {
  width: 1rem;
  height: 1rem;
  color: var(--color-text-muted);
  flex-shrink: 0;
}

.menu__item--danger,
.menu__item--danger svg,
.menu__item--danger .ic {
  color: var(--color-danger);
}

.menu__item--danger:hover {
  background: var(--color-danger-soft);
}

/* --- componentes/modal.css --- */
/* Modal — built on native <dialog> (focus, Escape and backdrop for free).
   <dialog class="modal">
     <div class="modal__header">…<button class="modal__close">…</div>
     <div class="modal__body">…</div>
     <div class="modal__footer">…</div>
   </dialog>
   JS: ui/js/modal.js */

.modal {
  width: min(34rem, calc(100vw - var(--space-8)));
  max-height: calc(100dvh - var(--space-16));
  /* Native <dialog> centers a modal via margin:auto; base.css resets all
     margins to 0, so we restore it here or the dialog pins to the top-left. */
  margin: auto;
  padding: 0;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-xl);
  background: var(--color-surface);
  box-shadow: var(--shadow-lg);
  color: inherit;
}

.modal--wide {
  width: min(52rem, calc(100vw - var(--space-8)));
}

.modal::backdrop {
  background: rgba(12, 10, 9, 0.45);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}

/* Mobile: modals become bottom sheets (matches the store-picker pattern). */
@media (max-width: 640px) {
  .modal {
    width: 100%;
    max-width: none;
    margin: auto 0 0;
    max-height: 92dvh;
    border-radius: var(--radius-xl) var(--radius-xl) 0 0;
    border-bottom: 0;
  }
  .modal[open] { animation: sheet-in var(--duration-base) var(--ease-out); }
}

@keyframes sheet-in {
  from { translate: 0 100%; }
}

.modal[open] {
  animation: modal-in var(--duration-base) var(--ease-out);
}

@keyframes modal-in {
  from {
    opacity: 0;
    translate: 0 var(--space-2);
  }
}

.modal__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--color-border);
}

.modal__title {
  font-size: var(--text-md);
  font-weight: var(--weight-semibold);
}

.modal__close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--color-text-muted);
}

.modal__close:hover {
  background: var(--color-surface-muted);
  color: var(--color-text);
}

.modal__body {
  padding: var(--space-5);
  overflow-y: auto;
}

.modal__footer {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  border-top: 1px solid var(--color-border);
}

/* --- componentes/toast.css --- */
/* Toast — aviso que no bloquea. Comportamiento: componentes/toast.js
   (el kit lo referenciaba y no lo traia; esta escrito aca).

   Portado de ds-portable-semaforo, con una decision resuelta: el kit traia dos
   aspectos, uno oscuro con sombra para vidrieras y otro solido sin sombra bajo
   `.cc-admin`. Queda el solido, que es el que respeta la doctrina de que la
   profundidad la dan la escalera de grises y los bordes, no un drop shadow. */

.toast-region {
  position: fixed;
  bottom: var(--space-6);
  right: var(--space-6);
  z-index: var(--z-toast);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  max-width: min(22rem, calc(100vw - var(--space-8)));
}

/* En un telefono va abajo y a lo ancho: la esquina inferior derecha de una
   pantalla de 6 pulgadas es justo donde esta el pulgar. */
@media (max-width: 480px) {
  .toast-region {
    left: var(--space-3);
    right: var(--space-3);
    bottom: var(--space-3);
    max-width: none;
  }
}

.toast {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--color-accent);
  color: var(--color-on-accent);
  /* Borde de tinta: toda superficie pintada lleva su filo. */
  border: 1.5px solid var(--neutral-900);
  border-radius: var(--radius-lg);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  animation: toast-in var(--duration-base) var(--ease-out);
}

@keyframes toast-in {
  from {
    opacity: 0;
    translate: 0 var(--space-2);
  }
}

.toast--leaving {
  opacity: 0;
  transition: opacity var(--duration-base) var(--ease-out);
}

/* El icono ES el svg. Va en una pastilla apenas marcada: la forma del icono
   carga el estado, no un color fuerte. */
.toast__icon {
  flex-shrink: 0;
  box-sizing: border-box;
  width: 1.25rem;
  height: 1.25rem;
  padding: 0.22rem;
  border-radius: var(--radius-full);
  background: rgba(0, 0, 0, 0.14);
  color: inherit;
}

.toast--error {
  background: var(--color-danger);
  color: var(--color-on-danger);
}

/* --- componentes/accordion.css --- */
/* ============================================================
   Accordion — two versions kept on purpose:
     A) Native <details>/<summary> — semantic, works with no JS, instant.
     B) Animated (.accordion--anim) — nav.js toggles .is-open for a smooth
        height transition. Same look; pick per context.
   ============================================================ */

.accordion {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--color-surface);
}
.accordion + .accordion { margin-top: var(--space-2); }

.accordion__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  width: 100%;
  padding: var(--space-3) var(--space-4);
  background: none;
  border: 0;
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  text-align: left;
  color: var(--color-text);
  cursor: pointer;
  list-style: none; /* hides the default <summary> triangle */
}
.accordion__head::-webkit-details-marker { display: none; }
.accordion__head::marker { content: ""; }
.accordion__head:hover { background: var(--color-surface-muted); }
.accordion__head:focus-visible { outline: 2px solid var(--color-focus); outline-offset: -2px; }

.accordion__chevron {
  width: 1rem;
  height: 1rem;
  flex: none;
  color: var(--color-text-muted);
  transition: rotate var(--duration-base) var(--ease-out);
}

.accordion__body p,
.accordion__inner p {
  padding: 0 var(--space-4) var(--space-3);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  line-height: var(--leading-normal);
}

/* ---------- A) Native <details> ---------- */
details.accordion[open] .accordion__chevron { rotate: 180deg; }

/* ---------- B) Animated ---------- */
.accordion--anim .accordion__body {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--duration-base) var(--ease-out);
}
.accordion--anim.is-open .accordion__body { grid-template-rows: 1fr; }
.accordion--anim .accordion__inner { overflow: hidden; }
.accordion--anim.is-open .accordion__chevron { rotate: 180deg; }

/* --- componentes/icon.css --- */
/* Iconos — SVG monocromo dibujado con una mascara CSS, para que el glifo tome
   `currentColor` y se adapte solo: tinta sobre superficie clara, blanco sobre
   un boton oscuro, rojo dentro de una accion destructiva.

   Portado de ds-portable-semaforo. El set original traia ~75 iconos de
   comercio (carrito, mercadopago, tienda, pedidos); aca quedan los treinta que
   este producto usa, con nombres nuestros. Agregar uno es copiar el SVG a
   `iconos/` y sumar una linea.

   Uso: <i class="ic ic--foto" aria-hidden="true"></i>        (16px)
        <i class="ic ic--24 ic--foto" aria-hidden="true"></i> (24px)

   Siempre `aria-hidden`: es decoracion. Si el icono es la unica etiqueta de un
   control, el control lleva `aria-label`. */

.ic {
  display: inline-block;
  width: 1rem;
  height: 1rem;
  flex: none;
  vertical-align: -0.15em;
  background-color: currentColor;
  -webkit-mask: var(--ic) center / contain no-repeat;
  mask: var(--ic) center / contain no-repeat;
}

.ic--24 { width: 1.5rem; height: 1.5rem; }

/* --- acciones --- */
.ic--check     { --ic: url(../iconos/n-check.svg); }
.ic--cerrar    { --ic: url(../iconos/n-close.svg); }
.ic--copiar    { --ic: url(../iconos/n-copy.svg); }
.ic--borrar    { --ic: url(../iconos/n-delete.svg); }
.ic--editar    { --ic: url(../iconos/n-edit.svg); }
.ic--nuevo     { --ic: url(../iconos/n-new.svg); }
.ic--mas       { --ic: url(../iconos/n-plus.svg); }
.ic--buscar    { --ic: url(../iconos/n-search.svg); }
.ic--descargar { --ic: url(../iconos/n-export.svg); }
.ic--escribir  { --ic: url(../iconos/n-write.svg); }
.ic--cambiar   { --ic: url(../iconos/n-switch.svg); }

/* --- objetos del producto --- */
.ic--foto      { --ic: url(../iconos/n-add-photo.svg); }
.ic--video     { --ic: url(../iconos/n-video.svg); }
.ic--qr        { --ic: url(../iconos/qr.svg); }
.ic--link      { --ic: url(../iconos/link.svg); }
.ic--evento    { --ic: url(../iconos/celebrate.svg); }
.ic--tema      { --ic: url(../iconos/n-tema.svg); }
.ic--grilla    { --ic: url(../iconos/n-grid.svg); }
.ic--lista     { --ic: url(../iconos/n-list.svg); }
.ic--vistazo   { --ic: url(../iconos/n-vistazo.svg); }

/* --- las tres acciones del invitado ---
   Van al doble de tamano dentro de `.ds-accion__icono`, asi que el trazo tiene
   que aguantar 24px sin verse liviano: son glifos macizos, no de contorno. */
.ic--camara    { --ic: url(../iconos/n-camara.svg); }
.ic--galeria   { --ic: url(../iconos/n-galeria.svg); }
.ic--mensaje   { --ic: url(../iconos/n-mensaje.svg); }

/* --- personas y cuenta --- */
.ic--persona   { --ic: url(../iconos/user.svg); }
.ic--cuenta    { --ic: url(../iconos/n-cuenta.svg); }
.ic--equipo    { --ic: url(../iconos/n-team.svg); }
.ic--invitar   { --ic: url(../iconos/n-add-team.svg); }
.ic--salir     { --ic: url(../iconos/n-signout.svg); }
.ic--mail      { --ic: url(../iconos/mail.svg); }

/* --- estado --- */
.ic--ojo       { --ic: url(../iconos/n-eye.svg); }
.ic--ajustes   { --ic: url(../iconos/n-settings.svg); }
.ic--ayuda     { --ic: url(../iconos/n-question.svg); }
.ic--ok        { --ic: url(../iconos/check-circle.svg); }
.ic--sonrisa   { --ic: url(../iconos/n-smile.svg); }

/* --- componentes/ds-select.css --- */
/* ============================================================
   select.css — SEL / HOV
   A custom dropdown that enhances a native <select> (progressive
   enhancement — the real <select> stays in the DOM as the source of
   truth and form value). Styled trigger with a rotating chevron, a
   panel of options, and a check on the selected one. Used e.g. for the
   catalog-editor "Hover effect" field.

   Portable: depends only on the design tokens in tokens.css. Behaviour
   comes from select.js, which wraps every <select data-ds-select>.
   ============================================================ */

.ds-select { position: relative; }
.ds-select__native { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }

.ds-select__btn {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  width: 100%;
  height: 2.5rem;
  padding: 0 var(--space-3);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  font: inherit;
  font-size: var(--text-sm);
  color: var(--color-text);
  cursor: pointer;
}
.ds-select__btn:hover { border-color: var(--color-border-accent); }
.ds-select__btn svg { color: var(--color-text-muted); transition: rotate var(--duration-fast) var(--ease-out); }
.ds-select.is-open .ds-select__btn { border-color: var(--color-action); box-shadow: inset 0 0 0 1px var(--color-action); }
.ds-select.is-open .ds-select__btn svg { rotate: 180deg; }

.ds-select__list {
  position: absolute;
  top: calc(100% + var(--space-1));
  left: 0;
  right: 0;
  z-index: var(--z-dropdown);
  padding: var(--space-1);
  border: 1px solid var(--color-border-strong); /* shadows off: the border separates */
  border-radius: var(--radius-md);
  background: var(--color-surface);
  display: none;
  max-height: 15rem;
  overflow-y: auto;
}
.ds-select.is-open .ds-select__list { display: block; }

.ds-select__opt {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  cursor: pointer;
}
.ds-select__opt:hover { background: var(--color-surface-muted); }
/* Storefront: option hover carries the theme's accent wash (unthemed stores
   alias accent-soft to surface-muted in store.css, so nothing changes). */
body.storefront .ds-select__opt:hover { background: var(--color-accent-soft); }
.ds-select__opt[aria-selected="true"] { font-weight: var(--weight-medium); }
/* Selected check — same glyph as the DDL-01 dropdowns (masked so it themes) */
.ds-select__opt[aria-selected="true"]::after {
  content: "";
  width: 0.9rem;
  height: 0.9rem;
  flex: none;
  background-color: var(--color-accent);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 12 4.5 4.5L19 7'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 12 4.5 4.5L19 7'/%3E%3C/svg%3E") center / contain no-repeat;
}

/* --- componentes/ds-segmented.css --- */
/* ============================================================
   segmented.css — COL (and any mutually-exclusive preset row)
   Segmented control backed by real radio inputs (accessible). A sliding
   thumb glides to the checked option; without JS the per-option
   background is the fallback. Used for grid columns (2/3/4), etc.

   Portable: depends only on the design tokens in tokens.css. The sliding
   thumb comes from segmented.js (optional — the control works without it).
   Markup:
     <fieldset class="ds-seg" role="radiogroup">
       <label class="ds-seg__option">
         <input type="radio" name="cols" class="ds-visually-hidden" checked><span>2</span>
       </label> …
     </fieldset>
   ============================================================ */

.ds-seg {
  position: relative;
  display: inline-flex;
  margin: 0;
  padding: var(--space-1);
  gap: var(--space-1);
  background: var(--color-surface-muted);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
}

.ds-seg__thumb {
  position: absolute;
  z-index: 0;
  background: var(--color-surface);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-xs);
  transition: left var(--duration-base) var(--ease-out), top var(--duration-base) var(--ease-out),
    width var(--duration-base) var(--ease-out), height var(--duration-base) var(--ease-out);
}
.ds-seg.has-thumb .ds-seg__option:has(input:checked) { background: none; box-shadow: none; }

.ds-seg__option {
  position: relative;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-width: 2.25rem;
  height: 2rem;
  padding: 0 var(--space-3);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--color-text-muted);
  cursor: pointer;
  user-select: none;
  transition: color var(--duration-fast) var(--ease-out), background var(--duration-fast) var(--ease-out);
}
.ds-seg__option:hover { color: var(--color-text); }
.ds-seg__option:has(input:checked) { background: var(--color-surface); color: var(--color-text); box-shadow: var(--shadow-xs); }
.ds-seg__option:has(input:focus-visible) { outline: 2px solid var(--color-focus); outline-offset: 1px; }

/* visually-hidden helper (in case the host page has none) */
.ds-visually-hidden { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* --- componentes/ds-radius-slider.css --- */
/* ============================================================
   radius-slider.css — RAD
   Corner-radius control: a live preview square + a custom range (thin
   filled track, crisp thumb, no native chrome) with stepped ticks + a
   px readout. Snaps through the design-system radius scale.

   Portable: depends only on the design tokens in tokens.css. The live
   sync (fill %, preview radius, readout) comes from radius-slider.js.
   Markup: see design-system.html RAD-01.
   ============================================================ */

.ds-rslider { display: flex; align-items: center; gap: var(--space-4); }

.ds-rslider__square {
  width: 2.75rem;
  height: 2.75rem;
  flex-shrink: 0;
  background: var(--color-surface-muted);
  border: 1.5px solid var(--color-border-strong);
  transition: border-radius var(--duration-fast) var(--ease-out);
}

.ds-rslider__val { min-width: 2.75rem; text-align: right; font-size: var(--text-sm); font-variant-numeric: tabular-nums; color: var(--color-text-muted); }

/* custom range: JS sets --fill: <percent> */
.ds-rslider__range {
  -webkit-appearance: none;
  appearance: none;
  flex: 1;
  height: 4px;
  border-radius: var(--radius-full);
  /* Fichas semanticas y no primitivas: `--neutral-900` es tinta sobre el tema
     claro y queda invisible sobre los oscuros, que son veintisiete de los
     veintiocho. La parte llena usa el acento del evento, que es lo que el
     control esta ajustando. */
  background:
    linear-gradient(var(--color-accent) 0 0) 0 / var(--fill, 50%) 100% no-repeat,
    var(--color-surface-muted);
  cursor: pointer;
}
.ds-rslider__range::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 16px;
  height: 16px;
  border-radius: var(--radius-full);
  background: var(--color-surface);
  border: 2px solid var(--color-accent);
}
.ds-rslider__range::-moz-range-thumb {
  width: 16px;
  height: 16px;
  border-radius: var(--radius-full);
  background: var(--color-surface);
  border: 2px solid var(--color-accent);
}
.ds-rslider__range:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 4px; }

.ds-rslider__stepwrap { flex: 1; max-width: 13rem; }
.ds-rslider__stepwrap .ds-rslider__range { max-width: 100%; }
.ds-rslider__ticks { display: flex; justify-content: space-between; margin-top: 6px; padding: 0 9px; }
.ds-rslider__ticks span { width: 1px; height: 5px; background: var(--color-border); }

/* Sin vista previa: para medidas que un cuadradito no sabe mostrar, como el
   ancho de un marco. El numero de la derecha alcanza. */
.ds-rslider--sin-previa .ds-rslider__square { display: none; }

/* En una fila de ajustes el deslizador ocupa lo que sobra y el valor queda
   alineado a la derecha con los de arriba y abajo. */
.ds-rslider--fila { width: 100%; }
.ds-rslider--fila .ds-rslider__stepwrap { max-width: none; }

/* --- componentes/ds-theme-picker.css --- */
/* ============================================================
   theme-picker.css — THM
   A palette picker: a wrapping row of two-tone 24px tiles (base + accent)
   as radio options with a selected ring. Custom (saved) themes get
   edit/delete affordances on hover; a dashed "create your own" tile ends
   the row.

   Portable: depends only on the design tokens in tokens.css. Selection is
   pure CSS (radio :checked). theme-picker.js only wires the delete action.
   Markup: see design-system.html THM-01.
   ============================================================ */

/* Fixed grid (2026-08-26): flex-wrap sized each tile to its NAME, so the
   gaps looked ragged. Every cell now gets the same track; long names clip. */
.ds-theme { display: grid; grid-template-columns: repeat(auto-fill, minmax(4.75rem, 1fr)); gap: var(--space-3); }
.ds-theme__mark { display: flex; flex-direction: column; align-items: center; gap: var(--space-1); }
.ds-theme__name { display: block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: center; }
.ds-theme__wrap { position: relative; }

.ds-theme__opt { position: relative; display: block; cursor: pointer; }
.ds-theme__opt input { position: absolute; inset: 0; opacity: 0; margin: 0; cursor: pointer; }
.ds-theme__mark { display: flex; flex-direction: column; align-items: center; gap: var(--space-2); }
.ds-theme__tile {
  width: 24px;
  height: 24px;
  border-radius: var(--radius-sm);
  border: 1px solid rgba(0, 0, 0, 0.12);
  overflow: hidden;
  display: flex;
  transition: box-shadow var(--duration-fast) var(--ease-out);
}
.ds-theme__tile span { flex: 1; }
.ds-theme__opt input:checked + .ds-theme__mark .ds-theme__tile,
.ds-theme__opt input:focus-visible + .ds-theme__mark .ds-theme__tile {
  box-shadow: 0 0 0 2px var(--color-surface), 0 0 0 4px var(--neutral-900);
}
.ds-theme__name { font-size: 10px; color: var(--color-text-muted); }
.ds-theme__opt input:checked + .ds-theme__mark .ds-theme__name { color: var(--color-text); font-weight: var(--weight-medium); }

/* custom (saved) themes: edit / delete on hover */
.ds-theme__acts { position: absolute; top: -7px; right: -7px; display: flex; gap: 3px; opacity: 0; transition: opacity var(--duration-fast) var(--ease-out); }
.ds-theme__wrap--custom:hover .ds-theme__acts,
.ds-theme__wrap--custom:focus-within .ds-theme__acts { opacity: 1; }
.ds-theme__act {
  display: grid;
  place-items: center;
  width: 17px;
  height: 17px;
  padding: 0;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-full);
  background: var(--color-surface);
  color: var(--color-text-muted);
  cursor: pointer;
}
.ds-theme__act svg { width: 9px; height: 9px; }
.ds-theme__act:hover { color: var(--color-text); border-color: var(--neutral-400); }
.ds-theme__act--del:hover { color: var(--color-danger); border-color: var(--color-danger); }

/* "create your own" tile */
.ds-theme__new { display: flex; flex-direction: column; align-items: center; gap: var(--space-2); text-decoration: none; }
.ds-theme__new-tile {
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: var(--radius-sm);
  border: 1.5px dashed var(--color-border-strong);
  color: var(--color-text-subtle);
  transition: border-color var(--duration-fast) var(--ease-out), color var(--duration-fast) var(--ease-out);
}
.ds-theme__new:hover .ds-theme__new-tile { border-color: var(--color-accent); color: var(--color-text); }
.ds-theme__new .ds-theme__name { color: var(--color-text-muted); }
.ds-theme__new:hover .ds-theme__name { color: var(--color-text); }

/* --- tira horizontal ---
   Veintiocho temas en la grilla del kit son cinco filas y media pantalla de
   panel. En una tira que se scrollea entran todos en el alto de uno, y elegir
   un tema es mirar colores, no leer una lista. */

.ds-temas {
  display: flex;
  gap: var(--space-2);
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximate;
  padding: var(--space-1) 0 var(--space-2);
  /* Con mouse se arrastra: la rueda no hace scroll horizontal sin Shift, y
     nadie descubre eso. Lo agrega ds-temas.js; el cursor lo anticipa. */
  cursor: grab;
  /* La barra, con el tema. Sutil pero presente: sin ninguna barra no hay forma
     de saber que hay mas temas a la derecha. */
  scrollbar-width: thin;
  scrollbar-color: var(--color-border-strong) transparent;
}

.ds-temas.is-arrastrando { cursor: grabbing; scroll-snap-type: none; }
/* Mientras se arrastra, el click no tiene que elegir un tema por accidente. */
.ds-temas.is-arrastrando .ds-theme__opt { pointer-events: none; }

.ds-temas::-webkit-scrollbar { height: 6px; }
.ds-temas::-webkit-scrollbar-track { background: transparent; }
.ds-temas::-webkit-scrollbar-thumb {
  background: var(--color-border-strong);
  border-radius: var(--radius-full);
}
.ds-temas::-webkit-scrollbar-thumb:hover { background: var(--color-border-hover); }

.ds-temas .ds-theme__wrap {
  flex: 0 0 auto;
  scroll-snap-align: center;
  width: 2.5rem;
}

/* Chicas: son una muestra de color, no una tarjeta. A 2rem entran once en el
   ancho del panel, que es lo que hace que la tira se lea como una paleta. */
.ds-temas .ds-theme__tile {
  width: 2rem;
  height: 2rem;
  border-radius: var(--radius-sm);
}

.ds-temas .ds-theme__name { font-size: 9px; }

/* --- componentes/ds-section-nav.css --- */
/* ============================================================
   section-nav.css — SEC
   The editor's right-column "section summary": a titled column of pill
   links, each with an optional count/status meta. In the real editors it
   scroll-spies the form sections and jumps on click; the active pill fills
   with ink.

   Portable: depends only on the design tokens in tokens.css. Behaviour
   (scroll-spy / jump, or click-to-activate) comes from section-nav.js.
   Markup: see design-system.html SEC-01.
   ============================================================ */

.ds-snav { display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-1); }
.ds-snav__title { padding: 0 var(--space-2) var(--space-1); font-size: var(--text-xs); font-weight: var(--weight-medium); color: var(--color-text-muted); }
.ds-snav__list { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; }
.ds-snav__pill {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  height: 2rem;
  padding: 0 var(--space-3);
  border: 0;
  border-radius: var(--radius-full);
  background: none;
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--color-text-muted);
  text-decoration: none;
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease-out), color var(--duration-fast) var(--ease-out);
}
.ds-snav__pill:hover { background: var(--color-surface-muted); color: var(--color-text); }
.ds-snav__pill.is-active { background: var(--neutral-900); color: var(--neutral-0); }
.ds-snav__name { white-space: nowrap; }
.ds-snav__meta { font-size: var(--text-xs); color: var(--color-text-subtle); font-variant-numeric: tabular-nums; }
.ds-snav__meta:empty { display: none; }
.ds-snav__pill.is-active .ds-snav__meta { color: rgba(255, 255, 255, 0.7); }

/* --- componentes/ds-chips.css --- */
/* ============================================================
   ds-chips.css — seleccion MULTIPLE

   Componente nuevo, escrito con las reglas del kit. No estaba: el kit resuelve
   la eleccion excluyente (`ds-seg`) y la lista larga (`ds-select`), pero no
   "marca todas las que quieras", que es la pregunta central de este producto.
   La pregunta util no es "que layout quiero" sino "entre cuales quiero que
   varie": ver dos alternando es lo unico que dice si la variedad funciona con
   el material real del evento.

   Debajo hay casillas de verdad. Sin JS el control ya funciona y ya se ve
   marcado, porque la seleccion la pinta `:has(input:checked)`.

   Portable: depende solo de las fichas de tokens.css.

   Markup:
     <div class="ds-chips" role="group" aria-label="Layouts">
       <label class="ds-chips__chip">
         <input type="checkbox" class="ds-visually-hidden" checked>
         <span class="ds-chips__label">Collage</span>
         <small class="ds-chips__nota">2-4</small>
       </label>
     </div>
   ============================================================ */

.ds-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.ds-chips__chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  height: 2rem;
  padding: 0 var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  cursor: pointer;
  user-select: none;
  transition: border-color var(--duration-fast) var(--ease-out),
              color var(--duration-fast) var(--ease-out),
              background var(--duration-fast) var(--ease-out);
}

.ds-chips__chip:hover { border-color: var(--color-border-hover); color: var(--color-text); }
.ds-chips__chip:active { transform: scale(0.97); }
.ds-chips__chip:has(input:focus-visible) { outline: 2px solid var(--color-focus); outline-offset: 2px; }

/* Marcado: superficie pintada con su filo de tinta, como el resto de las
   superficies pintadas del sistema. */
.ds-chips__chip:has(input:checked) {
  background: var(--color-accent-soft);
  border-color: var(--color-border-accent);
  color: var(--color-text);
}

/* Sin punto ni casilla dibujada: la superficie pintada del chip marcado ya
   dice cual esta puesto, y un circulo por chip come ancho en una fila de
   siete. Que se pueda marcar mas de uno se aprende marcando el segundo. */

.ds-chips__nota {
  color: var(--color-text-subtle);
  font-size: var(--text-xs);
  font-weight: var(--weight-regular);
  font-variant-numeric: tabular-nums;
}

/* Compacto: para filas de muchas opciones cortas, como las relaciones de
   aspecto. */
.ds-chips--compacto .ds-chips__chip {
  height: 1.75rem;
  padding: 0 var(--space-2);
  gap: var(--space-1);
  font-size: var(--text-xs);
}

/* --- componentes/ds-layout.css --- */
/* ============================================================
   ds-layout.css — piezas de composicion que el kit no traia

   Tres cosas que aparecen en cada pantalla de este producto y que no valia la
   pena repetir en cada hoja: la fila de etiqueta y control, el contenido de un
   grupo plegable, y la barra de acciones.

   Portable: depende solo de las fichas de tokens.css.
   ============================================================ */

/* Etiqueta a la izquierda, control a la derecha. Debajo de 26rem se apila:
   en el panel de un telefono, un select de 12rem al lado de una etiqueta de
   10rem no deja leer ninguno de los dos. */
.ds-fila {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  min-height: 2.75rem;
}

.ds-fila__label {
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  /* Se encoge antes que el control: una etiqueta cortada se sigue entendiendo,
     un desplegable cortado no se puede usar. */
  flex: 0 1 auto;
  min-width: 0;
}

/*
 * El control de una fila NO ocupa el 100%.
 *
 * `.field__control` del kit es `width: 100%`, pensado para un campo apilado
 * bajo su etiqueta. Metido en una fila que ademas tiene la etiqueta al lado,
 * el 100% se suma al ancho de la etiqueta y el total se pasa del panel: el
 * desplegable quedaba debajo de la barra de scroll, los textos de ayuda se
 * metian por atras, y el panel entero ganaba una barra horizontal que no
 * deberia existir.
 */
.ds-fila > :not(.ds-fila__label) {
  flex: 0 1 auto;
  min-width: 0;
  max-width: 62%;
  width: auto;
}

/* Los que si quieren todo el ancho que sobra lo piden. */
.ds-fila > .ds-rslider { flex: 1 1 auto; max-width: none; }

/* Varias acciones a la derecha de una fila: una etiqueta larga (el nombre de
   un miembro, un link) y dos o tres botones chicos. Se envuelve porque en un
   telefono tres botones al lado de un nombre no entran, y cortarlos deja la
   accion inalcanzable. */
.ds-fila__acciones {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
  justify-content: flex-end;
}

@media (max-width: 26rem) {
  .ds-fila { flex-direction: column; align-items: stretch; gap: var(--space-2); }
  .ds-fila__label { font-size: var(--text-sm); }
}

/* --- jerarquia de un panel de ajustes ---
   Dos niveles y no mas. Con tres, el tercero deja de leerse como nivel y
   empieza a leerse como ruido.

     BLOQUE   separa lo que se guarda de lo que no. Es la unica distincion que
              el operador necesita tener siempre presente.
     SECCION  agrupa controles que se tocan juntos.
*/

.ds-bloque {
  display: grid;
  /* El aire ENTRE secciones es el que hace legible la jerarquia. Apretadas, un
     panel de doce controles se lee como una lista de doce cosas iguales. */
  gap: var(--space-8);
  /* Y el aire ANTES del bloque tiene que ser mayor que el de adentro, o el
     corte no se lee como corte. */
  margin-top: var(--space-16);
}
.ds-bloque:first-child { margin-top: 0; }

.ds-bloque__cabeza {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  padding-bottom: var(--space-3);
  border-bottom: 1px solid var(--color-border-strong);
  /* Pegada a su primera seccion: la cabeza pertenece a lo que viene abajo, no
     flota entre dos bloques. */
  margin-bottom: calc(var(--space-4) * -1);
}

.ds-bloque__titulo {
  margin: 0;
  font-size: var(--text-md);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-snug);
}

.ds-bloque__nota {
  font-size: var(--text-xs);
  color: var(--color-text-subtle);
  text-align: right;
  flex: 1;
}

.ds-seccion { display: grid; gap: var(--space-3); }

.ds-seccion__titulo {
  margin: 0;
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  color: var(--color-text);
  letter-spacing: var(--tracking-snug);
}

/* La nota se pega a su titulo, no al control de abajo: explica el titulo. */
.ds-seccion__nota {
  margin: calc(var(--space-2) * -1) 0 0;
  font-size: var(--text-xs);
  color: var(--color-text-subtle);
  line-height: var(--leading-snug);
  max-width: 34ch;
}

/* Un titulo seguido de su nota y despues los controles: el salto al primer
   control es mayor que el del titulo a la nota. */
.ds-seccion__nota + * { margin-top: var(--space-1); }

/* Las filas de una seccion respiran entre si sin necesitar separadores: en un
   panel angosto, una linea cada tres controles se lee como una reja. */
.ds-seccion .ds-fila + .ds-fila { margin-top: calc(var(--space-1) * -1); }

.ds-barra { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.ds-barra .btn { flex: 1 1 auto; }

/* Un boton que esta "puesto": el modo activo de una herramienta, no una
   accion que se dispara. */
.btn.is-on {
  background: var(--color-accent-soft);
  border-color: var(--color-border-accent);
  color: var(--color-text);
}

/* Etiqueta de un grupo de opciones dentro de una seccion. No es un `<label>`
   de un control: rotula una fila de chips, que no tiene un solo control al que
   apuntar. */
.ds-etiqueta {
  margin: var(--space-2) 0 0;
  font-size: var(--text-xs);
  color: var(--color-text-muted);
}
.ds-etiqueta:first-child { margin-top: 0; }

/* --- selector de color ---
   La muestra, el valor a la vista, y la salida al automatico. Un
   `<input type=color>` solo es un rectangulo que no dice que color tiene ni
   permite desactivarlo. */

.ds-color {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  flex: none;
}

.ds-color__entrada {
  width: 2.25rem;
  height: 2rem;
  flex: none;
  padding: 0;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  cursor: pointer;
}
.ds-color__entrada::-webkit-color-swatch-wrapper { padding: 3px; }
.ds-color__entrada::-webkit-color-swatch { border: none; border-radius: var(--radius-xs); }
.ds-color__entrada::-moz-color-swatch { border: none; border-radius: var(--radius-xs); }

.ds-color__valor {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.ds-color .btn { padding: 0 var(--space-2); }

/* Muestras de una paleta derivada: permite juzgar una armonia sin aplicarla y
   esperar al proximo slide. */
.ds-paleta { display: flex; gap: var(--space-1); }
.ds-paleta i {
  flex: 1;
  height: 1.5rem;
  border-radius: var(--radius-xs);
  border: 1px solid var(--color-border);
}

/* --- barra de guardado ---
   Fija abajo del panel y solo cuando hay algo pendiente. Una barra siempre
   presente se vuelve parte del fondo y deja de avisar nada. */

.lab-guardar {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-5);
  background: var(--color-surface);
  border-top: 1px solid var(--color-border-strong);
  animation: lab-guardar-entra var(--duration-base) var(--ease-out);
}

@keyframes lab-guardar-entra { from { transform: translateY(100%); } }

.lab-guardar__cuenta {
  flex: 1;
  min-width: 0;
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

.lab-guardar .btn { flex: none; }

/* Con la barra puesta, el cuerpo del panel deja lugar para no quedar tapado
   en la ultima seccion. */
body.hay-cambios .lab-panel-cuerpo { padding-bottom: var(--space-20); }

/* --- componentes/ds-drawer.css --- */
/* ============================================================
   ds-drawer.css — panel lateral en escritorio, cajon en el telefono

   Componente nuevo, escrito con las reglas del kit. El mismo markup y el mismo
   contenido; lo que cambia es de donde entra y cuanto ocupa.

   La razon es concreta: en la consola, el panel de la derecha ocupa 27.5rem.
   En un telefono eso es la pantalla entera, y la vista previa —que es la razon
   de ser de esa pagina— queda tapada. Ajustar sin ver lo que se ajusta no
   sirve. Desde abajo, el cajon deja el cuadro a la vista y se puede subir para
   trabajar y bajar para mirar.

   Tres alturas y no dos: cerrado, asomado —lo justo para tocar un control sin
   perder el cuadro de vista— y completo.

   Portable: depende solo de las fichas de tokens.css. El arrastre lo agrega
   ds-drawer.js y es opcional: sin el, el tirador alterna entre asomado y
   completo con un toque.
   ============================================================ */

.ds-drawer {
  position: fixed;
  z-index: 300;
  display: flex;
  flex-direction: column;
  background: color-mix(in oklab, var(--color-bg) 96%, transparent);
  backdrop-filter: blur(20px);
}

.ds-drawer[hidden] { display: none; }

.ds-drawer__cab {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-5) var(--space-5) var(--space-4);
  border-bottom: 1px solid var(--color-border);
  flex: none;
}

.ds-drawer__cuerpo {
  flex: 1;
  overflow-y: auto;
  /* Nada se desborda a los lados. Si algo lo hace, es un bug del contenido y
     no algo que arreglar con una barra horizontal. */
  overflow-x: hidden;
  overscroll-behavior: contain;
  /* El hueco de la barra vertical se reserva SIEMPRE, haya o no scroll. Sin
     esto el contenido se corre unos pixeles cuando aparece, y los controles
     de la derecha quedan medio tapados. */
  scrollbar-gutter: stable;
  padding: var(--space-6) var(--space-5) var(--space-16);
  -webkit-overflow-scrolling: touch;
}

/*
 * La barra de scroll, con el tema.
 *
 * La del sistema es gris de Windows sobre cualquiera de los 28 temas, y en los
 * oscuros se ve como una franja clara pegada al borde. Se pinta con las mismas
 * fichas que el resto.
 */
.ds-drawer__cuerpo {
  scrollbar-width: thin;
  scrollbar-color: var(--color-border-hover) transparent;
}

.ds-drawer__cuerpo::-webkit-scrollbar { width: 10px; }
.ds-drawer__cuerpo::-webkit-scrollbar-track { background: transparent; }

.ds-drawer__cuerpo::-webkit-scrollbar-thumb {
  background: var(--color-border-strong);
  border-radius: var(--radius-full);
  /* El borde transparente adelgaza el pulgar sin achicar el area que se puede
     agarrar con el mouse. */
  border: 3px solid transparent;
  background-clip: content-box;
}

.ds-drawer__cuerpo::-webkit-scrollbar-thumb:hover { background: var(--color-border-hover); background-clip: content-box; }

/* El tirador de arrastre. Solo existe en el telefono: con mouse no se arrastra
   un panel, se lo abre y se lo cierra. */
.ds-drawer__agarre { display: none; }

/* --- escritorio: panel a la derecha ------------------------------------- */

@media (min-width: 48rem) {
  .ds-drawer {
    right: 0;
    top: 0;
    bottom: 0;
    width: min(27.5rem, 100vw);
    border-left: 1px solid var(--color-border);
    animation: ds-drawer-lateral var(--duration-slow) cubic-bezier(0.16, 1, 0.3, 1);
  }
}

@keyframes ds-drawer-lateral {
  from { transform: translateX(100%); }
}

/* --- telefono: cajon desde abajo ----------------------------------------- */

@media (max-width: 47.99rem) {
  .ds-drawer {
    left: 0;
    right: 0;
    bottom: 0;
    /* El alto lo fija `--alto`, que escribe el JS al arrastrar. El valor por
       defecto es el asomado. */
    height: var(--alto, 52dvh);
    max-height: 92dvh;
    border-top: 1px solid var(--color-border-strong);
    border-radius: var(--radius-2xl) var(--radius-2xl) 0 0;
    /* Sin transicion mientras el dedo esta apoyado: la agrega el JS al soltar,
       para que el cajon acompane al dedo y despues encaje solo. */
    animation: ds-drawer-abajo var(--duration-base) var(--ease-out);
  }

  .ds-drawer.is-animado {
    transition: height var(--duration-base) var(--ease-out);
  }

  .ds-drawer__agarre {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: none;
    /* Alto generoso: es el objetivo tactil que se busca sin mirar. */
    height: 1.75rem;
    padding-top: var(--space-2);
    cursor: grab;
    touch-action: none;
    background: none;
    border: 0;
    width: 100%;
  }

  .ds-drawer__agarre::before {
    content: "";
    width: 2.5rem;
    height: 4px;
    border-radius: var(--radius-full);
    background: var(--color-border-hover);
  }

  .ds-drawer__agarre:active { cursor: grabbing; }
  .ds-drawer__agarre:active::before { background: var(--color-text-muted); }

  .ds-drawer__cab {
    padding: var(--space-2) var(--space-4) var(--space-3);
  }

  .ds-drawer__cuerpo {
    padding: var(--space-5) var(--space-4) var(--space-20);
  }
}

@keyframes ds-drawer-abajo {
  from { transform: translateY(100%); }
}

/* --- componentes/ds-tactil.css --- */
/* ============================================================
   ds-tactil.css — componentes para una mano, de pie, con poca luz

   Componentes nuevos, escritos con las reglas del kit. El kit esta escalado
   para escritorio: un `.btn` mide 2.5rem, que en un mouse sobra y en un pulgar
   a media luz despues de un par de copas es un objetivo chico.

   Son tres, y los tres los usan la pagina del invitado y —cuando llegue— la de
   moderacion, que se opera igual: de pie, con una mano, sin mirar mucho.

     .ds-accion    la fila alta de accion principal
     .ds-progreso  una fila de estado con icono, nombre y avance
     .ds-miniaturas la grilla de lo propio, para ver y borrar

   Portable: depende solo de las fichas de tokens.css.
   ============================================================ */

/* --- accion grande -----------------------------------------------------------
   Icono en pastilla, titulo, y una linea de detalle opcional. 4.6rem son casi
   80px: muy por encima del minimo tactil, y suficiente para apretar sin mirar.

   Markup:
     <button class="ds-accion ds-accion--principal">
       <span class="ds-accion__icono"><svg/></span>
       <span class="ds-accion__texto">
         <span class="ds-accion__titulo">Sacar foto</span>
         <small class="ds-accion__nota">Se abre la camara</small>
       </span>
     </button>
*/

.ds-accion {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  width: 100%;
  min-height: 4.6rem;
  padding: var(--space-4) var(--space-5);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  background: var(--color-surface);
  color: var(--color-text);
  text-align: left;
  cursor: pointer;
  transition: transform var(--duration-fast) var(--ease-out),
              border-color var(--duration-base) var(--ease-out),
              background var(--duration-base) var(--ease-out);
}

/* El hundido al tocar es la unica confirmacion que da un telefono: no hay
   hover, y sin esto no se sabe si el toque entro. */
.ds-accion:active { transform: scale(0.98); }
.ds-accion:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }

/* La accion que queremos que pase. Una sola por pantalla. */
.ds-accion--principal {
  background: var(--color-accent-soft);
  border-color: var(--color-border-accent);
}

.ds-accion__icono {
  display: grid;
  place-items: center;
  width: 3rem;
  height: 3rem;
  flex: none;
  border-radius: var(--radius-full);
  background: var(--color-surface-muted);
  color: var(--color-accent-strong);
}

.ds-accion--principal .ds-accion__icono {
  background: var(--color-accent);
  color: var(--color-on-accent);
}

/* El glifo va a 1.5rem venga como `svg` inline o como `.ic` enmascarado. Los
   dos toman `currentColor`, que es lo que hace que el mismo icono sirva sobre
   el acento y sobre la superficie apagada. */
.ds-accion__icono svg { width: 1.5rem; height: 1.5rem; fill: currentColor; }
.ds-accion__icono .ic { width: 1.5rem; height: 1.5rem; vertical-align: 0; }

.ds-accion__texto { display: grid; gap: 2px; min-width: 0; }

.ds-accion__titulo {
  font-size: var(--text-lg);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-snug);
}

.ds-accion__nota {
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

/* --- fila de estado ----------------------------------------------------------
   Una subida en curso: pastilla de icono, nombre, estado, y avance a la
   derecha. Los estados son `is-ok`, `is-error`, `is-espera`.
*/

.ds-progreso {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-lg);
  background: var(--color-surface-muted);
}

.ds-progreso__icono {
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  flex: none;
  border-radius: var(--radius-full);
  background: var(--color-surface);
  color: var(--color-text-muted);
  font-size: var(--text-md);
  line-height: 1;
}

.ds-progreso__cuerpo { display: grid; gap: 2px; min-width: 0; flex: 1; }

.ds-progreso__nombre {
  font-size: var(--text-sm);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ds-progreso__estado { font-size: var(--text-xs); color: var(--color-text-muted); }

.ds-progreso__pct {
  font-variant-numeric: tabular-nums;
  color: var(--color-accent-strong);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
}

.ds-progreso.is-ok .ds-progreso__icono {
  background: var(--color-accent-soft);
  color: var(--color-accent-strong);
}
.ds-progreso.is-ok .ds-progreso__estado { color: var(--color-accent-strong); }

.ds-progreso.is-error .ds-progreso__icono {
  background: var(--color-danger-soft);
  color: var(--color-danger);
}
.ds-progreso.is-error .ds-progreso__estado { color: var(--color-danger); }

/* "Esperando senal" late despacio: comunica que sigue vivo sin la ansiedad de
   un spinner rapido. El brief lo pide explicito — nunca un spinner infinito. */
.ds-progreso.is-espera .ds-progreso__icono { animation: ds-latir 2s ease-in-out infinite; }

@keyframes ds-latir {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.4; }
}

/* --- grilla de miniaturas ----------------------------------------------------
   Lo propio, para mirarlo y borrarlo. Se llena sola: sin media queries, la
   grilla decide cuantas columnas entran.
*/

.ds-miniaturas {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(8.5rem, 1fr));
  gap: var(--space-2);
}

.ds-miniatura {
  position: relative;
  margin: 0;
  aspect-ratio: 4 / 5;
  border-radius: var(--radius-thumb);
  overflow: hidden;
  background: var(--color-surface-muted);
  border: 1px solid var(--color-border);
}

.ds-miniatura img { width: 100%; height: 100%; object-fit: cover; }

/* Cuando la pieza es un mensaje no hay imagen: se muestra el texto. */
.ds-miniatura__texto {
  padding: var(--space-3);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  overflow: hidden;
  line-height: var(--leading-snug);
}

.ds-miniatura__estado {
  position: absolute;
  inset: auto 0 0 0;
  padding: var(--space-1) var(--space-2);
  /* Velo neutro y no una ficha del tema: debajo hay una foto que no
     controlamos y puede ser de cualquier color. */
  background: rgba(0, 0, 0, 0.72);
  font-size: var(--text-xs);
  color: rgba(255, 255, 255, 0.85);
}

.ds-miniatura__borrar {
  position: absolute;
  top: var(--space-1);
  right: var(--space-1);
  display: grid;
  place-items: center;
  /* 2.5rem son 40px: el minimo que se acierta con el pulgar sobre una
     miniatura de 8.5rem sin borrar la de al lado. */
  width: 2.5rem;
  height: 2.5rem;
  border: none;
  border-radius: var(--radius-full);
  background: rgba(0, 0, 0, 0.6);
  color: rgba(255, 255, 255, 0.92);
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease-out);
}

.ds-miniatura__borrar:hover { background: var(--color-danger); }
.ds-miniatura__borrar:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }
.ds-miniatura__borrar .ic { width: 1rem; height: 1rem; }

/* --- la cabecera de la pagina del invitado -----------------------------------
   Marca del evento arriba, centrada. Es lo primero que se ve al escanear, y
   tiene que decir "estas en la fiesta de fulano" antes que "esta es una
   herramienta para subir fotos". */

.ds-bienvenida {
  display: grid;
  justify-items: center;
  gap: var(--space-3);
  text-align: center;
  padding: var(--space-6) 0 var(--space-2);
}

/* La foto de los anfitriones. Grande: es la cara de la fiesta. */
.ds-bienvenida__foto {
  width: 5.5rem;
  height: 5.5rem;
  border-radius: var(--radius-full);
  object-fit: cover;
  border: 2px solid var(--color-border-accent);
}

.ds-bienvenida__titulo {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-3xl);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
  text-wrap: balance;
}

.ds-bienvenida__sub {
  margin: 0;
  color: var(--color-text-muted);
  font-size: var(--text-md);
  line-height: var(--leading-snug);
  text-wrap: balance;
  max-width: 26ch;
}

/* --- el sello de portals -----------------------------------------------------
   Abajo del todo y discreto. El evento manda arriba; esto dice de que producto
   es sin competir con la fiesta. Es lo que hace que alguien que vio la pagina
   en un casamiento sepa que pedir para el suyo. */

.ds-sello {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-6) 0 var(--space-2);
  color: var(--color-text-subtle);
  font-size: var(--text-xs);
  text-decoration: none;
}

.ds-sello strong {
  color: var(--color-text-muted);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-snug);
}

.ds-sello__punto {
  width: 5px;
  height: 5px;
  border-radius: var(--radius-full);
  background: var(--color-accent);
  flex: none;
}

/* --- el perfil del invitado --------------------------------------------------
   La foto y el nombre con los que van a salir sus fotos en la pantalla. */

.ds-perfil {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}

.ds-perfil__foto {
  position: relative;
  width: 4.5rem;
  height: 4.5rem;
  flex: none;
  border-radius: var(--radius-full);
  overflow: hidden;
  background: var(--color-surface-muted);
  border: 1px solid var(--color-border-strong);
  cursor: pointer;
  display: grid;
  place-items: center;
  padding: 0;
}

.ds-perfil__foto img { width: 100%; height: 100%; object-fit: cover; }

.ds-perfil__foto .ic {
  width: 1.5rem;
  height: 1.5rem;
  color: var(--color-text-muted);
}

.ds-perfil__cuerpo { display: grid; gap: var(--space-1); min-width: 0; flex: 1; }

.ds-perfil__nota { font-size: var(--text-xs); color: var(--color-text-subtle); }

/* --- componentes/ds-gallery.css --- */
/* ============================================================
   gallery.css — GAL
   Horizontal image carousel (work-strip): drag-to-scroll with snap,
   a thin scrollbar, and tiles that open the lightbox. Tile width is a
   local var (--ds-gallery-w); crop via the thumb aspect-ratio.

   Portable: depends on the design tokens in tokens.css. Behaviour +
   lightbox wiring come from gallery.js (+ lightbox.js).
   Markup:
     <div class="ds-gallery">
       <button class="ds-gallery__item" type="button">
         <div class="ds-gallery__thumb"><img src="…" alt="…"></div>
       </button>
     </div>
   ============================================================ */

.ds-gallery {
  --ds-gallery-w: 16rem;
  display: flex;
  gap: var(--space-3);
  margin: 0 -2px;
  padding-bottom: var(--space-2);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  cursor: grab;
  scrollbar-width: thin;
  scrollbar-color: var(--color-border-strong) transparent;
  -webkit-overflow-scrolling: touch;
}
.ds-gallery::-webkit-scrollbar { height: 7px; }
.ds-gallery::-webkit-scrollbar-track { background: transparent; }
.ds-gallery::-webkit-scrollbar-thumb { background: var(--color-border-strong); border-radius: var(--radius-full); }
.ds-gallery::-webkit-scrollbar-thumb:hover { background: var(--color-text-subtle); }
.ds-gallery.is-dragging { cursor: grabbing; scroll-snap-type: none; user-select: none; }
.ds-gallery.is-snapping { scroll-snap-type: none; }

.ds-gallery__item {
  flex: none;
  width: var(--ds-gallery-w);
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  scroll-snap-align: start;
  -webkit-user-drag: none;
}
.ds-gallery__thumb {
  width: 100%;
  aspect-ratio: 4 / 5;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--color-surface-muted);
}
.ds-gallery__thumb img { width: 100%; height: 100%; object-fit: cover; display: block; -webkit-user-drag: none; }

/* --- componentes/ds-lightbox.css --- */
/* ============================================================
   lightbox.css — LBX
   Full-screen media overlay: a blurred scrim, an inset "canvas" that
   fits the image, a fixed close button and a bottom counter. Behaviour
   (click-halves, swipe, keyboard, video embeds) lives in lightbox.js.

   Portable: depends on the design tokens in tokens.css + lightbox.js.
   The scrim/text sit above a dark backdrop, so foreground text is
   neutral-0 regardless of theme.
   ============================================================ */

.ds-lightbox { position: fixed; inset: 0; z-index: var(--z-modal); }
.ds-lightbox[hidden] { display: none; }

.ds-lightbox__backdrop {
  position: absolute;
  inset: 0;
  background: color-mix(in srgb, var(--neutral-950) 72%, transparent);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
}

.ds-lightbox__inner { position: fixed; inset: var(--space-6); display: grid; place-items: center; }
@media (min-width: 1024px) { .ds-lightbox__inner { inset: var(--space-16); } }

.ds-lightbox__media {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-4);
}
.ds-lightbox__media picture { max-width: 100%; max-height: 100%; display: flex; align-items: center; justify-content: center; }
.ds-lightbox__media img {
  max-width: 100%;
  max-height: calc(100vh - 48px - 90px);
  object-fit: contain;
  display: block;
  user-select: none;
  -webkit-user-drag: none;
}
@media (min-width: 1024px) { .ds-lightbox__media img { max-height: calc(100vh - 128px - 90px); } }

.ds-lightbox__caption {
  width: min(900px, 100%);
  padding: 0 var(--space-2);
  text-align: center;
  font-size: var(--text-sm);
  line-height: var(--leading-snug);
  color: var(--neutral-0);
  user-select: none;
}

.ds-lightbox__video { width: 100%; height: auto; max-width: 1200px; aspect-ratio: 16 / 9; }
.ds-lightbox__video iframe { width: 100%; height: 100%; border: 0; display: block; }

.ds-lightbox__close {
  position: fixed;
  top: var(--space-8);
  right: var(--space-8);
  width: 2.5rem;
  height: 2.5rem;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--neutral-0);
  cursor: pointer;
  display: grid;
  place-items: center;
  z-index: 2;
}
.ds-lightbox__close svg { width: 1.5rem; height: 1.5rem; display: block; }

.ds-lightbox__counter {
  position: fixed;
  left: 50%;
  bottom: var(--space-8);
  transform: translateX(-50%);
  font-size: var(--text-sm);
  line-height: 1;
  letter-spacing: 0.08em;
  color: var(--neutral-0);
  font-variant-numeric: tabular-nums;
  user-select: none;
  z-index: 2;
}
.ds-lightbox__error { color: var(--neutral-300); font-size: var(--text-sm); text-align: center; padding: var(--space-6); }

/* --- componentes/ds-aspect-ratio.css --- */
/* ============================================================
   aspect-ratio.css — ASP
   A segmented-style picker of aspect ratios: each option is a scaled
   rectangle silhouette (drawn with a border, sized inline per ratio)
   above its label, inside a soft inset track. Selected option lifts to
   a white chip.

   Portable: depends only on the design tokens in tokens.css. Selection
   is pure CSS (radio :checked). No JS — silhouettes are sized inline.
   Markup: see design-system.html ASP-01.
   ============================================================ */

.ds-ratios {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
  padding: var(--space-1);
  background: var(--color-surface-muted);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  width: fit-content;
  max-width: 100%;
}
.ds-ratios__opt { position: relative; cursor: pointer; }
.ds-ratios__opt input { position: absolute; inset: 0; opacity: 0; margin: 0; cursor: pointer; }
.ds-ratios__box {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
  width: 2.75rem;
  padding: var(--space-2) 0;
  border-radius: var(--radius-md);
  color: var(--color-text-muted);
  transition: background var(--duration-fast) var(--ease-out), color var(--duration-fast) var(--ease-out);
}
.ds-ratios__opt input:checked + .ds-ratios__box { background: var(--color-surface); color: var(--color-text); box-shadow: var(--shadow-xs); }
.ds-ratios__opt input:focus-visible + .ds-ratios__box { outline: 2px solid var(--neutral-900); outline-offset: 1px; }
.ds-ratios__sil { display: grid; place-items: center; height: 1.6rem; }
.ds-ratios__sil span { border: 1.5px solid currentColor; border-radius: 2px; /* width/height set inline per ratio */ }
.ds-ratios__label { font-size: 10px; font-weight: var(--weight-medium); font-variant-numeric: tabular-nums; }

/* --- componentes/ds-collapsible-items.css --- */
/* ============================================================
   collapsible-items.css — CIT
   The in-card collapsible order summary used on checkout: a toggle line
   (count + total, with a chevron) sitting inside the same card as the
   form, revealing the order lines below when expanded. Not a floating
   dropdown — it expands in place.

   Portable: depends only on the design tokens in tokens.css. The
   expand/collapse comes from collapsible-items.js.
   Markup:
     <div class="ds-collapse">
       <button class="ds-collapse__toggle" aria-expanded="false" aria-controls="oc">
         <span>3 items · $84,990</span><svg>chevron</svg>
       </button>
       <div class="ds-collapse__body" id="oc" hidden> … </div>
     </div>
   ============================================================ */

.ds-collapse {
  padding: var(--space-5);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-2xl);
  background: var(--color-surface);
  box-shadow: var(--shadow-sm);
}
.ds-collapse__toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  width: 100%;
  padding: 0 0 var(--space-4);
  border: 0;
  border-bottom: 1px solid var(--color-border);
  background: none;
  cursor: pointer;
  font: inherit;
  font-size: var(--text-sm);
  color: var(--color-text);
}
.ds-collapse__toggle b { font-variant-numeric: tabular-nums; }
.ds-collapse__toggle svg { width: 1rem; height: 1rem; flex-shrink: 0; color: var(--color-text-muted); transition: rotate var(--duration-fast) var(--ease-out); }
.ds-collapse__toggle[aria-expanded="true"] svg { rotate: 180deg; }
.ds-collapse__body { padding-top: var(--space-3); }
.ds-collapse__body[hidden] { display: none; }

/* --- temas.css --- */
/* ============================================================
   themes-dark.css — dark themes for the Semáforo design system (v2).
   Each block overrides ONLY the semantic tokens under
   html[data-ds-theme="<key>"]; components never change. v2: every theme
   owns its SIGNATURE action color — buttons, bands, chips and toasts
   wear the THEME, not the Semáforo accents (Grafito stays the literal
   Semáforo inversion by design). Groups: Sistema · Editores (Dracula,
   Nord, Catppuccin, Tokyo Night, Gruvbox, One Dark, GitHub, Solarized)
   · Eventos (Terciopelo, Sereno, Jardín, Quince, Neón, Vino, Aurora —
   for the events/projector app). Apply: <html data-ds-theme="quince">,
   or copy a block's body into :root to hard-adopt one.
   ============================================================ */

/* ---- Grafito · Semáforo dark ---- */
html[data-ds-theme="grafito"] {
  color-scheme: dark;
  --color-bg: #111111;
  --color-surface: #1A1A1A;
  --color-surface-muted: #222222;
  --color-border: #2E2E2E;
  --color-border-strong: #3A3A3A;
  --color-border-hover: #4A4A4A;
  --color-border-accent: #4A4A4A;
  --color-backdrop: rgba(0, 0, 0, 0.65);
  --color-text: #F4F4F4;
  --color-text-muted: #A9A9A9;
  --color-text-subtle: #6E6E6E;
  /* signature action: the theme's own color, not the system's */
  --color-action: #F4F4F4;
  --color-action-hover: color-mix(in srgb, #F4F4F4 85%, #1A1A1A);
  --color-on-action: #111111;
  --color-accent: #3FBF74;
  --color-accent-strong: #3FBF74;
  --color-accent-hover: color-mix(in srgb, #3FBF74 85%, #1A1A1A);
  --color-accent-soft: color-mix(in srgb, #3FBF74 16%, #1A1A1A);
  --color-on-accent: #111111;
  --color-danger: #F0592A;
  --color-danger-hover: color-mix(in srgb, #F0592A 85%, #1A1A1A);
  --color-danger-soft: color-mix(in srgb, #F0592A 16%, #1A1A1A);
  --color-on-danger: #111111;
  --color-cta: #FF5000;
  --color-cta-hover: color-mix(in srgb, #FF5000 85%, #1A1A1A);
  --color-on-cta: #111111;
  --color-info: #6AA2E8;
  --color-highlight: #FFCC00;
  --color-highlight-soft: color-mix(in srgb, #FFCC00 16%, #1A1A1A);
  --color-highlight-border: color-mix(in srgb, #FFCC00 45%, #1A1A1A);
  --color-highlight-text: color-mix(in srgb, #FFCC00 80%, #F4F4F4);
  --color-highlight-deep: #FFCC00;
  --color-on-highlight: #111111;
  --color-warning: #FFCC00;
  --color-warning-soft: color-mix(in srgb, #FFCC00 14%, #1A1A1A);
  --color-warning-text: color-mix(in srgb, #FFCC00 80%, #F4F4F4);
  --color-focus: #F4F4F4;
  --color-field: #111111;
  --purple-400: #C79BE0;
  --purple-600: #C79BE0;
  --purple-700: color-mix(in srgb, #C79BE0 80%, #F4F4F4);
  --purple-50: color-mix(in srgb, #C79BE0 14%, #1A1A1A);
  --purple-100: color-mix(in srgb, #C79BE0 20%, #1A1A1A);
}

/* ---- Consola · CRT ---- */
html[data-ds-theme="consola"] {
  color-scheme: dark;
  --color-bg: #0A0F0A;
  --color-surface: #101710;
  --color-surface-muted: #162016;
  --color-border: #1E2C1E;
  --color-border-strong: #2A3D2A;
  --color-border-hover: #3A523A;
  --color-border-accent: #3A523A;
  --color-backdrop: rgba(0, 0, 0, 0.65);
  --color-text: #C8F5C8;
  --color-text-muted: #7FBF7F;
  --color-text-subtle: #4E7A4E;
  /* signature action: the theme's own color, not the system's */
  --color-action: #33FF66;
  --color-action-hover: color-mix(in srgb, #33FF66 85%, #101710);
  --color-on-action: #06120A;
  --color-accent: #33FF66;
  --color-accent-strong: #33FF66;
  --color-accent-hover: color-mix(in srgb, #33FF66 85%, #101710);
  --color-accent-soft: color-mix(in srgb, #33FF66 16%, #101710);
  --color-on-accent: #06120A;
  --color-danger: #FF5F56;
  --color-danger-hover: color-mix(in srgb, #FF5F56 85%, #101710);
  --color-danger-soft: color-mix(in srgb, #FF5F56 16%, #101710);
  --color-on-danger: #06120A;
  --color-cta: #33FF66;
  --color-cta-hover: color-mix(in srgb, #33FF66 85%, #101710);
  --color-on-cta: #06120A;
  --color-info: #5FD7FF;
  --color-highlight: #FFB000;
  --color-highlight-soft: color-mix(in srgb, #FFB000 16%, #101710);
  --color-highlight-border: color-mix(in srgb, #FFB000 45%, #101710);
  --color-highlight-text: color-mix(in srgb, #FFB000 80%, #C8F5C8);
  --color-highlight-deep: #FFB000;
  --color-on-highlight: #06120A;
  --color-warning: #FFB000;
  --color-warning-soft: color-mix(in srgb, #FFB000 14%, #101710);
  --color-warning-text: color-mix(in srgb, #FFB000 80%, #C8F5C8);
  --color-focus: #C8F5C8;
  --color-field: #0A0F0A;
  --purple-400: #B58FE0;
  --purple-600: #B58FE0;
  --purple-700: color-mix(in srgb, #B58FE0 80%, #C8F5C8);
  --purple-50: color-mix(in srgb, #B58FE0 14%, #101710);
  --purple-100: color-mix(in srgb, #B58FE0 20%, #101710);
}

/* ---- Drácula ---- */
html[data-ds-theme="dracula"] {
  color-scheme: dark;
  --color-bg: #1E1F29;
  --color-surface: #282A36;
  --color-surface-muted: #343746;
  --color-border: #3C3F51;
  --color-border-strong: #44475A;
  --color-border-hover: #5A5E78;
  --color-border-accent: #5A5E78;
  --color-backdrop: rgba(0, 0, 0, 0.65);
  --color-text: #F8F8F2;
  --color-text-muted: #9DA3C8;
  --color-text-subtle: #6272A4;
  /* signature action: the theme's own color, not the system's */
  --color-action: #BD93F9;
  --color-action-hover: color-mix(in srgb, #BD93F9 85%, #282A36);
  --color-on-action: #1E1F29;
  --color-accent: #50FA7B;
  --color-accent-strong: #50FA7B;
  --color-accent-hover: color-mix(in srgb, #50FA7B 85%, #282A36);
  --color-accent-soft: color-mix(in srgb, #50FA7B 16%, #282A36);
  --color-on-accent: #1E1F29;
  --color-danger: #FF5555;
  --color-danger-hover: color-mix(in srgb, #FF5555 85%, #282A36);
  --color-danger-soft: color-mix(in srgb, #FF5555 16%, #282A36);
  --color-on-danger: #1E1F29;
  --color-cta: #FF79C6;
  --color-cta-hover: color-mix(in srgb, #FF79C6 85%, #282A36);
  --color-on-cta: #1E1F29;
  --color-info: #8BE9FD;
  --color-highlight: #F1FA8C;
  --color-highlight-soft: color-mix(in srgb, #F1FA8C 16%, #282A36);
  --color-highlight-border: color-mix(in srgb, #F1FA8C 45%, #282A36);
  --color-highlight-text: color-mix(in srgb, #F1FA8C 80%, #F8F8F2);
  --color-highlight-deep: #F1FA8C;
  --color-on-highlight: #1E1F29;
  --color-warning: #F1FA8C;
  --color-warning-soft: color-mix(in srgb, #F1FA8C 14%, #282A36);
  --color-warning-text: color-mix(in srgb, #F1FA8C 80%, #F8F8F2);
  --color-focus: #F8F8F2;
  --color-field: #1E1F29;
  --purple-400: #BD93F9;
  --purple-600: #BD93F9;
  --purple-700: color-mix(in srgb, #BD93F9 80%, #F8F8F2);
  --purple-50: color-mix(in srgb, #BD93F9 14%, #282A36);
  --purple-100: color-mix(in srgb, #BD93F9 20%, #282A36);
}

/* ---- Nord ---- */
html[data-ds-theme="nord"] {
  color-scheme: dark;
  --color-bg: #242933;
  --color-surface: #2E3440;
  --color-surface-muted: #3B4252;
  --color-border: #434C5E;
  --color-border-strong: #4C566A;
  --color-border-hover: #616E88;
  --color-border-accent: #616E88;
  --color-backdrop: rgba(0, 0, 0, 0.65);
  --color-text: #ECEFF4;
  --color-text-muted: #AEB8CC;
  --color-text-subtle: #7B88A1;
  /* signature action: the theme's own color, not the system's */
  --color-action: #88C0D0;
  --color-action-hover: color-mix(in srgb, #88C0D0 85%, #2E3440);
  --color-on-action: #242933;
  --color-accent: #A3BE8C;
  --color-accent-strong: #A3BE8C;
  --color-accent-hover: color-mix(in srgb, #A3BE8C 85%, #2E3440);
  --color-accent-soft: color-mix(in srgb, #A3BE8C 16%, #2E3440);
  --color-on-accent: #242933;
  --color-danger: #BF616A;
  --color-danger-hover: color-mix(in srgb, #BF616A 85%, #2E3440);
  --color-danger-soft: color-mix(in srgb, #BF616A 16%, #2E3440);
  --color-on-danger: #ECEFF4;
  --color-cta: #D08770;
  --color-cta-hover: color-mix(in srgb, #D08770 85%, #2E3440);
  --color-on-cta: #242933;
  --color-info: #81A1C1;
  --color-highlight: #EBCB8B;
  --color-highlight-soft: color-mix(in srgb, #EBCB8B 16%, #2E3440);
  --color-highlight-border: color-mix(in srgb, #EBCB8B 45%, #2E3440);
  --color-highlight-text: color-mix(in srgb, #EBCB8B 80%, #ECEFF4);
  --color-highlight-deep: #EBCB8B;
  --color-on-highlight: #242933;
  --color-warning: #EBCB8B;
  --color-warning-soft: color-mix(in srgb, #EBCB8B 14%, #2E3440);
  --color-warning-text: color-mix(in srgb, #EBCB8B 80%, #ECEFF4);
  --color-focus: #ECEFF4;
  --color-field: #242933;
  --purple-400: #B48EAD;
  --purple-600: #B48EAD;
  --purple-700: color-mix(in srgb, #B48EAD 80%, #ECEFF4);
  --purple-50: color-mix(in srgb, #B48EAD 14%, #2E3440);
  --purple-100: color-mix(in srgb, #B48EAD 20%, #2E3440);
}

/* ---- Catppuccin Mocha ---- */
html[data-ds-theme="catppuccin"] {
  color-scheme: dark;
  --color-bg: #181825;
  --color-surface: #1E1E2E;
  --color-surface-muted: #2A2A3C;
  --color-border: #313244;
  --color-border-strong: #45475A;
  --color-border-hover: #585B70;
  --color-border-accent: #585B70;
  --color-backdrop: rgba(0, 0, 0, 0.65);
  --color-text: #CDD6F4;
  --color-text-muted: #A6ADC8;
  --color-text-subtle: #6C7086;
  /* signature action: the theme's own color, not the system's */
  --color-action: #CBA6F7;
  --color-action-hover: color-mix(in srgb, #CBA6F7 85%, #1E1E2E);
  --color-on-action: #181825;
  --color-accent: #A6E3A1;
  --color-accent-strong: #A6E3A1;
  --color-accent-hover: color-mix(in srgb, #A6E3A1 85%, #1E1E2E);
  --color-accent-soft: color-mix(in srgb, #A6E3A1 16%, #1E1E2E);
  --color-on-accent: #181825;
  --color-danger: #F38BA8;
  --color-danger-hover: color-mix(in srgb, #F38BA8 85%, #1E1E2E);
  --color-danger-soft: color-mix(in srgb, #F38BA8 16%, #1E1E2E);
  --color-on-danger: #181825;
  --color-cta: #FAB387;
  --color-cta-hover: color-mix(in srgb, #FAB387 85%, #1E1E2E);
  --color-on-cta: #181825;
  --color-info: #89B4FA;
  --color-highlight: #F9E2AF;
  --color-highlight-soft: color-mix(in srgb, #F9E2AF 16%, #1E1E2E);
  --color-highlight-border: color-mix(in srgb, #F9E2AF 45%, #1E1E2E);
  --color-highlight-text: color-mix(in srgb, #F9E2AF 80%, #CDD6F4);
  --color-highlight-deep: #F9E2AF;
  --color-on-highlight: #181825;
  --color-warning: #F9E2AF;
  --color-warning-soft: color-mix(in srgb, #F9E2AF 14%, #1E1E2E);
  --color-warning-text: color-mix(in srgb, #F9E2AF 80%, #CDD6F4);
  --color-focus: #CDD6F4;
  --color-field: #181825;
  --purple-400: #CBA6F7;
  --purple-600: #CBA6F7;
  --purple-700: color-mix(in srgb, #CBA6F7 80%, #CDD6F4);
  --purple-50: color-mix(in srgb, #CBA6F7 14%, #1E1E2E);
  --purple-100: color-mix(in srgb, #CBA6F7 20%, #1E1E2E);
}

/* ---- Tokyo Night ---- */
html[data-ds-theme="tokyo"] {
  color-scheme: dark;
  --color-bg: #16161E;
  --color-surface: #1A1B26;
  --color-surface-muted: #24283B;
  --color-border: #2F3549;
  --color-border-strong: #3B4261;
  --color-border-hover: #545C7E;
  --color-border-accent: #545C7E;
  --color-backdrop: rgba(0, 0, 0, 0.65);
  --color-text: #C0CAF5;
  --color-text-muted: #9AA5CE;
  --color-text-subtle: #565F89;
  /* signature action: the theme's own color, not the system's */
  --color-action: #7AA2F7;
  --color-action-hover: color-mix(in srgb, #7AA2F7 85%, #1A1B26);
  --color-on-action: #16161E;
  --color-accent: #9ECE6A;
  --color-accent-strong: #9ECE6A;
  --color-accent-hover: color-mix(in srgb, #9ECE6A 85%, #1A1B26);
  --color-accent-soft: color-mix(in srgb, #9ECE6A 16%, #1A1B26);
  --color-on-accent: #16161E;
  --color-danger: #F7768E;
  --color-danger-hover: color-mix(in srgb, #F7768E 85%, #1A1B26);
  --color-danger-soft: color-mix(in srgb, #F7768E 16%, #1A1B26);
  --color-on-danger: #16161E;
  --color-cta: #FF9E64;
  --color-cta-hover: color-mix(in srgb, #FF9E64 85%, #1A1B26);
  --color-on-cta: #16161E;
  --color-info: #7AA2F7;
  --color-highlight: #E0AF68;
  --color-highlight-soft: color-mix(in srgb, #E0AF68 16%, #1A1B26);
  --color-highlight-border: color-mix(in srgb, #E0AF68 45%, #1A1B26);
  --color-highlight-text: color-mix(in srgb, #E0AF68 80%, #C0CAF5);
  --color-highlight-deep: #E0AF68;
  --color-on-highlight: #16161E;
  --color-warning: #E0AF68;
  --color-warning-soft: color-mix(in srgb, #E0AF68 14%, #1A1B26);
  --color-warning-text: color-mix(in srgb, #E0AF68 80%, #C0CAF5);
  --color-focus: #C0CAF5;
  --color-field: #16161E;
  --purple-400: #BB9AF7;
  --purple-600: #BB9AF7;
  --purple-700: color-mix(in srgb, #BB9AF7 80%, #C0CAF5);
  --purple-50: color-mix(in srgb, #BB9AF7 14%, #1A1B26);
  --purple-100: color-mix(in srgb, #BB9AF7 20%, #1A1B26);
}

/* ---- Gruvbox ---- */
html[data-ds-theme="gruvbox"] {
  color-scheme: dark;
  --color-bg: #1D2021;
  --color-surface: #282828;
  --color-surface-muted: #32302F;
  --color-border: #3C3836;
  --color-border-strong: #504945;
  --color-border-hover: #665C54;
  --color-border-accent: #665C54;
  --color-backdrop: rgba(0, 0, 0, 0.65);
  --color-text: #EBDBB2;
  --color-text-muted: #BDAE93;
  --color-text-subtle: #928374;
  /* signature action: the theme's own color, not the system's */
  --color-action: #FABD2F;
  --color-action-hover: color-mix(in srgb, #FABD2F 85%, #282828);
  --color-on-action: #1D2021;
  --color-accent: #B8BB26;
  --color-accent-strong: #B8BB26;
  --color-accent-hover: color-mix(in srgb, #B8BB26 85%, #282828);
  --color-accent-soft: color-mix(in srgb, #B8BB26 16%, #282828);
  --color-on-accent: #1D2021;
  --color-danger: #FB4934;
  --color-danger-hover: color-mix(in srgb, #FB4934 85%, #282828);
  --color-danger-soft: color-mix(in srgb, #FB4934 16%, #282828);
  --color-on-danger: #1D2021;
  --color-cta: #FE8019;
  --color-cta-hover: color-mix(in srgb, #FE8019 85%, #282828);
  --color-on-cta: #1D2021;
  --color-info: #83A598;
  --color-highlight: #FABD2F;
  --color-highlight-soft: color-mix(in srgb, #FABD2F 16%, #282828);
  --color-highlight-border: color-mix(in srgb, #FABD2F 45%, #282828);
  --color-highlight-text: color-mix(in srgb, #FABD2F 80%, #EBDBB2);
  --color-highlight-deep: #FABD2F;
  --color-on-highlight: #1D2021;
  --color-warning: #FABD2F;
  --color-warning-soft: color-mix(in srgb, #FABD2F 14%, #282828);
  --color-warning-text: color-mix(in srgb, #FABD2F 80%, #EBDBB2);
  --color-focus: #EBDBB2;
  --color-field: #1D2021;
  --purple-400: #D3869B;
  --purple-600: #D3869B;
  --purple-700: color-mix(in srgb, #D3869B 80%, #EBDBB2);
  --purple-50: color-mix(in srgb, #D3869B 14%, #282828);
  --purple-100: color-mix(in srgb, #D3869B 20%, #282828);
}

/* ---- One Dark ---- */
html[data-ds-theme="onedark"] {
  color-scheme: dark;
  --color-bg: #21252B;
  --color-surface: #282C34;
  --color-surface-muted: #2F343E;
  --color-border: #3A3F4B;
  --color-border-strong: #4B5263;
  --color-border-hover: #5C6370;
  --color-border-accent: #5C6370;
  --color-backdrop: rgba(0, 0, 0, 0.65);
  --color-text: #ABB2BF;
  --color-text-muted: #828997;
  --color-text-subtle: #5C6370;
  /* signature action: the theme's own color, not the system's */
  --color-action: #61AFEF;
  --color-action-hover: color-mix(in srgb, #61AFEF 85%, #282C34);
  --color-on-action: #21252B;
  --color-accent: #98C379;
  --color-accent-strong: #98C379;
  --color-accent-hover: color-mix(in srgb, #98C379 85%, #282C34);
  --color-accent-soft: color-mix(in srgb, #98C379 16%, #282C34);
  --color-on-accent: #21252B;
  --color-danger: #E06C75;
  --color-danger-hover: color-mix(in srgb, #E06C75 85%, #282C34);
  --color-danger-soft: color-mix(in srgb, #E06C75 16%, #282C34);
  --color-on-danger: #21252B;
  --color-cta: #D19A66;
  --color-cta-hover: color-mix(in srgb, #D19A66 85%, #282C34);
  --color-on-cta: #21252B;
  --color-info: #61AFEF;
  --color-highlight: #E5C07B;
  --color-highlight-soft: color-mix(in srgb, #E5C07B 16%, #282C34);
  --color-highlight-border: color-mix(in srgb, #E5C07B 45%, #282C34);
  --color-highlight-text: color-mix(in srgb, #E5C07B 80%, #ABB2BF);
  --color-highlight-deep: #E5C07B;
  --color-on-highlight: #21252B;
  --color-warning: #E5C07B;
  --color-warning-soft: color-mix(in srgb, #E5C07B 14%, #282C34);
  --color-warning-text: color-mix(in srgb, #E5C07B 80%, #ABB2BF);
  --color-focus: #ABB2BF;
  --color-field: #21252B;
  --purple-400: #C678DD;
  --purple-600: #C678DD;
  --purple-700: color-mix(in srgb, #C678DD 80%, #ABB2BF);
  --purple-50: color-mix(in srgb, #C678DD 14%, #282C34);
  --purple-100: color-mix(in srgb, #C678DD 20%, #282C34);
}

/* ---- GitHub Dark ---- */
html[data-ds-theme="github"] {
  color-scheme: dark;
  --color-bg: #0D1117;
  --color-surface: #161B22;
  --color-surface-muted: #21262D;
  --color-border: #30363D;
  --color-border-strong: #3D444D;
  --color-border-hover: #4D565F;
  --color-border-accent: #4D565F;
  --color-backdrop: rgba(0, 0, 0, 0.65);
  --color-text: #E6EDF3;
  --color-text-muted: #9198A1;
  --color-text-subtle: #656C76;
  /* signature action: the theme's own color, not the system's */
  --color-action: #3FB950;
  --color-action-hover: color-mix(in srgb, #3FB950 85%, #161B22);
  --color-on-action: #0D1117;
  --color-accent: #3FB950;
  --color-accent-strong: #3FB950;
  --color-accent-hover: color-mix(in srgb, #3FB950 85%, #161B22);
  --color-accent-soft: color-mix(in srgb, #3FB950 16%, #161B22);
  --color-on-accent: #0D1117;
  --color-danger: #F85149;
  --color-danger-hover: color-mix(in srgb, #F85149 85%, #161B22);
  --color-danger-soft: color-mix(in srgb, #F85149 16%, #161B22);
  --color-on-danger: #0D1117;
  --color-cta: #DB6D28;
  --color-cta-hover: color-mix(in srgb, #DB6D28 85%, #161B22);
  --color-on-cta: #0D1117;
  --color-info: #58A6FF;
  --color-highlight: #D29922;
  --color-highlight-soft: color-mix(in srgb, #D29922 16%, #161B22);
  --color-highlight-border: color-mix(in srgb, #D29922 45%, #161B22);
  --color-highlight-text: color-mix(in srgb, #D29922 80%, #E6EDF3);
  --color-highlight-deep: #D29922;
  --color-on-highlight: #0D1117;
  --color-warning: #D29922;
  --color-warning-soft: color-mix(in srgb, #D29922 14%, #161B22);
  --color-warning-text: color-mix(in srgb, #D29922 80%, #E6EDF3);
  --color-focus: #E6EDF3;
  --color-field: #0D1117;
  --purple-400: #BC8CFF;
  --purple-600: #BC8CFF;
  --purple-700: color-mix(in srgb, #BC8CFF 80%, #E6EDF3);
  --purple-50: color-mix(in srgb, #BC8CFF 14%, #161B22);
  --purple-100: color-mix(in srgb, #BC8CFF 20%, #161B22);
}

/* ---- Solarized Dark ---- */
html[data-ds-theme="solarized"] {
  color-scheme: dark;
  --color-bg: #00212B;
  --color-surface: #002B36;
  --color-surface-muted: #073642;
  --color-border: #0E4250;
  --color-border-strong: #586E75;
  --color-border-hover: #657B83;
  --color-border-accent: #657B83;
  --color-backdrop: rgba(0, 0, 0, 0.65);
  --color-text: #EEE8D5;
  --color-text-muted: #93A1A1;
  --color-text-subtle: #657B83;
  /* signature action: the theme's own color, not the system's */
  --color-action: #268BD2;
  --color-action-hover: color-mix(in srgb, #268BD2 85%, #002B36);
  --color-on-action: #FDF6E3;
  --color-accent: #859900;
  --color-accent-strong: #859900;
  --color-accent-hover: color-mix(in srgb, #859900 85%, #002B36);
  --color-accent-soft: color-mix(in srgb, #859900 16%, #002B36);
  --color-on-accent: #FDF6E3;
  --color-danger: #DC322F;
  --color-danger-hover: color-mix(in srgb, #DC322F 85%, #002B36);
  --color-danger-soft: color-mix(in srgb, #DC322F 16%, #002B36);
  --color-on-danger: #FDF6E3;
  --color-cta: #CB4B16;
  --color-cta-hover: color-mix(in srgb, #CB4B16 85%, #002B36);
  --color-on-cta: #FDF6E3;
  --color-info: #2AA198;
  --color-highlight: #B58900;
  --color-highlight-soft: color-mix(in srgb, #B58900 16%, #002B36);
  --color-highlight-border: color-mix(in srgb, #B58900 45%, #002B36);
  --color-highlight-text: color-mix(in srgb, #B58900 80%, #EEE8D5);
  --color-highlight-deep: #B58900;
  --color-on-highlight: #FDF6E3;
  --color-warning: #B58900;
  --color-warning-soft: color-mix(in srgb, #B58900 14%, #002B36);
  --color-warning-text: color-mix(in srgb, #B58900 80%, #EEE8D5);
  --color-focus: #EEE8D5;
  --color-field: #00212B;
  --purple-400: #6C71C4;
  --purple-600: #6C71C4;
  --purple-700: color-mix(in srgb, #6C71C4 80%, #EEE8D5);
  --purple-50: color-mix(in srgb, #6C71C4 14%, #002B36);
  --purple-100: color-mix(in srgb, #6C71C4 20%, #002B36);
}

/* ---- Terciopelo · boda champagne ---- */
html[data-ds-theme="terciopelo"] {
  color-scheme: dark;
  --color-bg: #120E0B;
  --color-surface: #1A1511;
  --color-surface-muted: #241D16;
  --color-border: #322A20;
  --color-border-strong: #453A2C;
  --color-border-hover: #5C4E3A;
  --color-border-accent: #5C4E3A;
  --color-backdrop: rgba(0, 0, 0, 0.65);
  --color-text: #F3EBDC;
  --color-text-muted: #C4B49A;
  --color-text-subtle: #8A7A60;
  /* signature action: the theme's own color, not the system's */
  --color-action: #D4B573;
  --color-action-hover: color-mix(in srgb, #D4B573 85%, #1A1511);
  --color-on-action: #120E0B;
  --color-accent: #A8C5A0;
  --color-accent-strong: #A8C5A0;
  --color-accent-hover: color-mix(in srgb, #A8C5A0 85%, #1A1511);
  --color-accent-soft: color-mix(in srgb, #A8C5A0 16%, #1A1511);
  --color-on-accent: #120E0B;
  --color-danger: #D98A7E;
  --color-danger-hover: color-mix(in srgb, #D98A7E 85%, #1A1511);
  --color-danger-soft: color-mix(in srgb, #D98A7E 16%, #1A1511);
  --color-on-danger: #120E0B;
  --color-cta: #D4B573;
  --color-cta-hover: color-mix(in srgb, #D4B573 85%, #1A1511);
  --color-on-cta: #120E0B;
  --color-info: #9DB8E8;
  --color-highlight: #E8CF9E;
  --color-highlight-soft: color-mix(in srgb, #E8CF9E 16%, #1A1511);
  --color-highlight-border: color-mix(in srgb, #E8CF9E 45%, #1A1511);
  --color-highlight-text: color-mix(in srgb, #E8CF9E 80%, #F3EBDC);
  --color-highlight-deep: #E8CF9E;
  --color-on-highlight: #120E0B;
  --color-warning: #E8CF9E;
  --color-warning-soft: color-mix(in srgb, #E8CF9E 14%, #1A1511);
  --color-warning-text: color-mix(in srgb, #E8CF9E 80%, #F3EBDC);
  --color-focus: #F3EBDC;
  --color-field: #120E0B;
  --purple-400: #C9A9C8;
  --purple-600: #C9A9C8;
  --purple-700: color-mix(in srgb, #C9A9C8 80%, #F3EBDC);
  --purple-50: color-mix(in srgb, #C9A9C8 14%, #1A1511);
  --purple-100: color-mix(in srgb, #C9A9C8 20%, #1A1511);
}

/* ---- Sereno · boda medianoche ---- */
html[data-ds-theme="sereno"] {
  color-scheme: dark;
  --color-bg: #0A0F1E;
  --color-surface: #101830;
  --color-surface-muted: #182342;
  --color-border: #223052;
  --color-border-strong: #2E3F69;
  --color-border-hover: #42568A;
  --color-border-accent: #42568A;
  --color-backdrop: rgba(0, 0, 0, 0.65);
  --color-text: #E8EDF7;
  --color-text-muted: #A9B6D3;
  --color-text-subtle: #6C7CA3;
  /* signature action: the theme's own color, not the system's */
  --color-action: #9DB8E8;
  --color-action-hover: color-mix(in srgb, #9DB8E8 85%, #101830);
  --color-on-action: #0A0F1E;
  --color-accent: #8FC7A8;
  --color-accent-strong: #8FC7A8;
  --color-accent-hover: color-mix(in srgb, #8FC7A8 85%, #101830);
  --color-accent-soft: color-mix(in srgb, #8FC7A8 16%, #101830);
  --color-on-accent: #0A0F1E;
  --color-danger: #E08585;
  --color-danger-hover: color-mix(in srgb, #E08585 85%, #101830);
  --color-danger-soft: color-mix(in srgb, #E08585 16%, #101830);
  --color-on-danger: #0A0F1E;
  --color-cta: #9DB8E8;
  --color-cta-hover: color-mix(in srgb, #9DB8E8 85%, #101830);
  --color-on-cta: #0A0F1E;
  --color-info: #9DB8E8;
  --color-highlight: #D9C08A;
  --color-highlight-soft: color-mix(in srgb, #D9C08A 16%, #101830);
  --color-highlight-border: color-mix(in srgb, #D9C08A 45%, #101830);
  --color-highlight-text: color-mix(in srgb, #D9C08A 80%, #E8EDF7);
  --color-highlight-deep: #D9C08A;
  --color-on-highlight: #0A0F1E;
  --color-warning: #D9C08A;
  --color-warning-soft: color-mix(in srgb, #D9C08A 14%, #101830);
  --color-warning-text: color-mix(in srgb, #D9C08A 80%, #E8EDF7);
  --color-focus: #E8EDF7;
  --color-field: #0A0F1E;
  --purple-400: #B3A6E3;
  --purple-600: #B3A6E3;
  --purple-700: color-mix(in srgb, #B3A6E3 80%, #E8EDF7);
  --purple-50: color-mix(in srgb, #B3A6E3 14%, #101830);
  --purple-100: color-mix(in srgb, #B3A6E3 20%, #101830);
}

/* ---- Jardín nocturno · boda boho ---- */
html[data-ds-theme="jardin"] {
  color-scheme: dark;
  --color-bg: #0D120E;
  --color-surface: #141B15;
  --color-surface-muted: #1C261E;
  --color-border: #2A382C;
  --color-border-strong: #3A4C3D;
  --color-border-hover: #526853;
  --color-border-accent: #526853;
  --color-backdrop: rgba(0, 0, 0, 0.65);
  --color-text: #EFEEE2;
  --color-text-muted: #B7BEA8;
  --color-text-subtle: #7E8871;
  /* signature action: the theme's own color, not the system's */
  --color-action: #A8C5A0;
  --color-action-hover: color-mix(in srgb, #A8C5A0 85%, #141B15);
  --color-on-action: #0D120E;
  --color-accent: #A8C5A0;
  --color-accent-strong: #A8C5A0;
  --color-accent-hover: color-mix(in srgb, #A8C5A0 85%, #141B15);
  --color-accent-soft: color-mix(in srgb, #A8C5A0 16%, #141B15);
  --color-on-accent: #0D120E;
  --color-danger: #D98A7E;
  --color-danger-hover: color-mix(in srgb, #D98A7E 85%, #141B15);
  --color-danger-soft: color-mix(in srgb, #D98A7E 16%, #141B15);
  --color-on-danger: #0D120E;
  --color-cta: #A8C5A0;
  --color-cta-hover: color-mix(in srgb, #A8C5A0 85%, #141B15);
  --color-on-cta: #0D120E;
  --color-info: #8FB8C9;
  --color-highlight: #E3C889;
  --color-highlight-soft: color-mix(in srgb, #E3C889 16%, #141B15);
  --color-highlight-border: color-mix(in srgb, #E3C889 45%, #141B15);
  --color-highlight-text: color-mix(in srgb, #E3C889 80%, #EFEEE2);
  --color-highlight-deep: #E3C889;
  --color-on-highlight: #0D120E;
  --color-warning: #E3C889;
  --color-warning-soft: color-mix(in srgb, #E3C889 14%, #141B15);
  --color-warning-text: color-mix(in srgb, #E3C889 80%, #EFEEE2);
  --color-focus: #EFEEE2;
  --color-field: #0D120E;
  --purple-400: #B8A9C9;
  --purple-600: #B8A9C9;
  --purple-700: color-mix(in srgb, #B8A9C9 80%, #EFEEE2);
  --purple-50: color-mix(in srgb, #B8A9C9 14%, #141B15);
  --purple-100: color-mix(in srgb, #B8A9C9 20%, #141B15);
}

/* ---- Quince · rosa y oro ---- */
html[data-ds-theme="quince"] {
  color-scheme: dark;
  --color-bg: #170F16;
  --color-surface: #201621;
  --color-surface-muted: #2C1E2E;
  --color-border: #3C2A3E;
  --color-border-strong: #523A54;
  --color-border-hover: #6E4E70;
  --color-border-accent: #6E4E70;
  --color-backdrop: rgba(0, 0, 0, 0.65);
  --color-text: #F7EBF2;
  --color-text-muted: #CFAEC4;
  --color-text-subtle: #96718B;
  /* signature action: the theme's own color, not the system's */
  --color-action: #F27BA6;
  --color-action-hover: color-mix(in srgb, #F27BA6 85%, #201621);
  --color-on-action: #170F16;
  --color-accent: #A8C9A8;
  --color-accent-strong: #A8C9A8;
  --color-accent-hover: color-mix(in srgb, #A8C9A8 85%, #201621);
  --color-accent-soft: color-mix(in srgb, #A8C9A8 16%, #201621);
  --color-on-accent: #170F16;
  --color-danger: #E85C5C;
  --color-danger-hover: color-mix(in srgb, #E85C5C 85%, #201621);
  --color-danger-soft: color-mix(in srgb, #E85C5C 16%, #201621);
  --color-on-danger: #170F16;
  --color-cta: #F27BA6;
  --color-cta-hover: color-mix(in srgb, #F27BA6 85%, #201621);
  --color-on-cta: #170F16;
  --color-info: #A9B8E8;
  --color-highlight: #E8B4A0;
  --color-highlight-soft: color-mix(in srgb, #E8B4A0 16%, #201621);
  --color-highlight-border: color-mix(in srgb, #E8B4A0 45%, #201621);
  --color-highlight-text: color-mix(in srgb, #E8B4A0 80%, #F7EBF2);
  --color-highlight-deep: #E8B4A0;
  --color-on-highlight: #170F16;
  --color-warning: #E8B4A0;
  --color-warning-soft: color-mix(in srgb, #E8B4A0 14%, #201621);
  --color-warning-text: color-mix(in srgb, #E8B4A0 80%, #F7EBF2);
  --color-focus: #F7EBF2;
  --color-field: #170F16;
  --purple-400: #C9A0E8;
  --purple-600: #C9A0E8;
  --purple-700: color-mix(in srgb, #C9A0E8 80%, #F7EBF2);
  --purple-50: color-mix(in srgb, #C9A0E8 14%, #201621);
  --purple-100: color-mix(in srgb, #C9A0E8 20%, #201621);
}

/* ---- Neón · fiesta ---- */
html[data-ds-theme="neon"] {
  color-scheme: dark;
  --color-bg: #0B0913;
  --color-surface: #131020;
  --color-surface-muted: #1C1730;
  --color-border: #2A2347;
  --color-border-strong: #3A3060;
  --color-border-hover: #524482;
  --color-border-accent: #524482;
  --color-backdrop: rgba(0, 0, 0, 0.65);
  --color-text: #F2EFFF;
  --color-text-muted: #B5ACD9;
  --color-text-subtle: #7C71A8;
  /* signature action: the theme's own color, not the system's */
  --color-action: #FF4FD8;
  --color-action-hover: color-mix(in srgb, #FF4FD8 85%, #131020);
  --color-on-action: #0B0913;
  --color-accent: #3EFFB2;
  --color-accent-strong: #3EFFB2;
  --color-accent-hover: color-mix(in srgb, #3EFFB2 85%, #131020);
  --color-accent-soft: color-mix(in srgb, #3EFFB2 16%, #131020);
  --color-on-accent: #0B0913;
  --color-danger: #FF5F56;
  --color-danger-hover: color-mix(in srgb, #FF5F56 85%, #131020);
  --color-danger-soft: color-mix(in srgb, #FF5F56 16%, #131020);
  --color-on-danger: #0B0913;
  --color-cta: #3EE8FF;
  --color-cta-hover: color-mix(in srgb, #3EE8FF 85%, #131020);
  --color-on-cta: #0B0913;
  --color-info: #3EE8FF;
  --color-highlight: #FFE14F;
  --color-highlight-soft: color-mix(in srgb, #FFE14F 16%, #131020);
  --color-highlight-border: color-mix(in srgb, #FFE14F 45%, #131020);
  --color-highlight-text: color-mix(in srgb, #FFE14F 80%, #F2EFFF);
  --color-highlight-deep: #FFE14F;
  --color-on-highlight: #0B0913;
  --color-warning: #FFE14F;
  --color-warning-soft: color-mix(in srgb, #FFE14F 14%, #131020);
  --color-warning-text: color-mix(in srgb, #FFE14F 80%, #F2EFFF);
  --color-focus: #F2EFFF;
  --color-field: #0B0913;
  --purple-400: #9D8CFF;
  --purple-600: #9D8CFF;
  --purple-700: color-mix(in srgb, #9D8CFF 80%, #F2EFFF);
  --purple-50: color-mix(in srgb, #9D8CFF 14%, #131020);
  --purple-100: color-mix(in srgb, #9D8CFF 20%, #131020);
}

/* ---- Vino · cena borgoña ---- */
html[data-ds-theme="vino"] {
  color-scheme: dark;
  --color-bg: #150C0F;
  --color-surface: #1E1216;
  --color-surface-muted: #2A1A1F;
  --color-border: #3A252C;
  --color-border-strong: #50333C;
  --color-border-hover: #6B4550;
  --color-border-accent: #6B4550;
  --color-backdrop: rgba(0, 0, 0, 0.65);
  --color-text: #F5E9E6;
  --color-text-muted: #CBA9A6;
  --color-text-subtle: #91706E;
  /* signature action: the theme's own color, not the system's */
  --color-action: #CE6E85;
  --color-action-hover: color-mix(in srgb, #CE6E85 85%, #1E1216);
  --color-on-action: #150C0F;
  --color-accent: #A0BFA0;
  --color-accent-strong: #A0BFA0;
  --color-accent-hover: color-mix(in srgb, #A0BFA0 85%, #1E1216);
  --color-accent-soft: color-mix(in srgb, #A0BFA0 16%, #1E1216);
  --color-on-accent: #150C0F;
  --color-danger: #E06060;
  --color-danger-hover: color-mix(in srgb, #E06060 85%, #1E1216);
  --color-danger-soft: color-mix(in srgb, #E06060 16%, #1E1216);
  --color-on-danger: #150C0F;
  --color-cta: #CE6E85;
  --color-cta-hover: color-mix(in srgb, #CE6E85 85%, #1E1216);
  --color-on-cta: #150C0F;
  --color-info: #A0A8D9;
  --color-highlight: #D9AE6E;
  --color-highlight-soft: color-mix(in srgb, #D9AE6E 16%, #1E1216);
  --color-highlight-border: color-mix(in srgb, #D9AE6E 45%, #1E1216);
  --color-highlight-text: color-mix(in srgb, #D9AE6E 80%, #F5E9E6);
  --color-highlight-deep: #D9AE6E;
  --color-on-highlight: #150C0F;
  --color-warning: #D9AE6E;
  --color-warning-soft: color-mix(in srgb, #D9AE6E 14%, #1E1216);
  --color-warning-text: color-mix(in srgb, #D9AE6E 80%, #F5E9E6);
  --color-focus: #F5E9E6;
  --color-field: #150C0F;
  --purple-400: #C293C2;
  --purple-600: #C293C2;
  --purple-700: color-mix(in srgb, #C293C2 80%, #F5E9E6);
  --purple-50: color-mix(in srgb, #C293C2 14%, #1E1216);
  --purple-100: color-mix(in srgb, #C293C2 20%, #1E1216);
}

/* ---- Aurora · celestial ---- */
html[data-ds-theme="aurora"] {
  color-scheme: dark;
  --color-bg: #070B18;
  --color-surface: #0E1428;
  --color-surface-muted: #151E3A;
  --color-border: #20294D;
  --color-border-strong: #2C3866;
  --color-border-hover: #404E88;
  --color-border-accent: #404E88;
  --color-backdrop: rgba(0, 0, 0, 0.65);
  --color-text: #EAF0FA;
  --color-text-muted: #A6B4D6;
  --color-text-subtle: #6A79A3;
  /* signature action: the theme's own color, not the system's */
  --color-action: #7FE8C1;
  --color-action-hover: color-mix(in srgb, #7FE8C1 85%, #0E1428);
  --color-on-action: #070B18;
  --color-accent: #7FE8C1;
  --color-accent-strong: #7FE8C1;
  --color-accent-hover: color-mix(in srgb, #7FE8C1 85%, #0E1428);
  --color-accent-soft: color-mix(in srgb, #7FE8C1 16%, #0E1428);
  --color-on-accent: #070B18;
  --color-danger: #FF7A8A;
  --color-danger-hover: color-mix(in srgb, #FF7A8A 85%, #0E1428);
  --color-danger-soft: color-mix(in srgb, #FF7A8A 16%, #0E1428);
  --color-on-danger: #070B18;
  --color-cta: #7FE8C1;
  --color-cta-hover: color-mix(in srgb, #7FE8C1 85%, #0E1428);
  --color-on-cta: #070B18;
  --color-info: #8CB8FF;
  --color-highlight: #FFD98A;
  --color-highlight-soft: color-mix(in srgb, #FFD98A 16%, #0E1428);
  --color-highlight-border: color-mix(in srgb, #FFD98A 45%, #0E1428);
  --color-highlight-text: color-mix(in srgb, #FFD98A 80%, #EAF0FA);
  --color-highlight-deep: #FFD98A;
  --color-on-highlight: #070B18;
  --color-warning: #FFD98A;
  --color-warning-soft: color-mix(in srgb, #FFD98A 14%, #0E1428);
  --color-warning-text: color-mix(in srgb, #FFD98A 80%, #EAF0FA);
  --color-focus: #EAF0FA;
  --color-field: #070B18;
  --purple-400: #9D8CFF;
  --purple-600: #9D8CFF;
  --purple-700: color-mix(in srgb, #9D8CFF 80%, #EAF0FA);
  --purple-50: color-mix(in srgb, #9D8CFF 14%, #0E1428);
  --purple-100: color-mix(in srgb, #9D8CFF 20%, #0E1428);
}

/* ---- Confeti · cumpleaños ---- */
html[data-ds-theme="confeti"] {
  color-scheme: dark;
  --color-bg: #141216;
  --color-surface: #1C1A20;
  --color-surface-muted: #26232B;
  --color-border: #34303C;
  --color-border-strong: #453F4E;
  --color-border-hover: #5C5468;
  --color-border-accent: #5C5468;
  --color-backdrop: rgba(0, 0, 0, 0.65);
  --color-text: #F5F2F7;
  --color-text-muted: #B3ACBE;
  --color-text-subtle: #7A7286;
  /* signature action: the theme's own color, not the system's */
  --color-action: #FF6B6B;
  --color-action-hover: color-mix(in srgb, #FF6B6B 85%, #1C1A20);
  --color-on-action: #141216;
  --color-accent: #6BCB77;
  --color-accent-strong: #6BCB77;
  --color-accent-hover: color-mix(in srgb, #6BCB77 85%, #1C1A20);
  --color-accent-soft: color-mix(in srgb, #6BCB77 16%, #1C1A20);
  --color-on-accent: #141216;
  --color-danger: #E84040;
  --color-danger-hover: color-mix(in srgb, #E84040 85%, #1C1A20);
  --color-danger-soft: color-mix(in srgb, #E84040 16%, #1C1A20);
  --color-on-danger: #F5F2F7;
  --color-cta: #4ECDC4;
  --color-cta-hover: color-mix(in srgb, #4ECDC4 85%, #1C1A20);
  --color-on-cta: #141216;
  --color-info: #4D96FF;
  --color-highlight: #FFD93D;
  --color-highlight-soft: color-mix(in srgb, #FFD93D 16%, #1C1A20);
  --color-highlight-border: color-mix(in srgb, #FFD93D 45%, #1C1A20);
  --color-highlight-text: color-mix(in srgb, #FFD93D 80%, #F5F2F7);
  --color-highlight-deep: #FFD93D;
  --color-on-highlight: #141216;
  --color-warning: #FFD93D;
  --color-warning-soft: color-mix(in srgb, #FFD93D 14%, #1C1A20);
  --color-warning-text: color-mix(in srgb, #FFD93D 80%, #F5F2F7);
  --color-focus: #F5F2F7;
  --color-field: #141216;
  --purple-400: #B39DDB;
  --purple-600: #B39DDB;
  --purple-700: color-mix(in srgb, #B39DDB 80%, #F5F2F7);
  --purple-50: color-mix(in srgb, #B39DDB 14%, #1C1A20);
  --purple-100: color-mix(in srgb, #B39DDB 20%, #1C1A20);
}

/* ---- Piñata · fiesta latina ---- */
html[data-ds-theme="pinata"] {
  color-scheme: dark;
  --color-bg: #1A0E14;
  --color-surface: #241219;
  --color-surface-muted: #311823;
  --color-border: #44202F;
  --color-border-strong: #5C2B40;
  --color-border-hover: #7A3A56;
  --color-border-accent: #7A3A56;
  --color-backdrop: rgba(0, 0, 0, 0.65);
  --color-text: #FBEFF2;
  --color-text-muted: #D9A8BC;
  --color-text-subtle: #A06B84;
  /* signature action: the theme's own color, not the system's */
  --color-action: #F0459C;
  --color-action-hover: color-mix(in srgb, #F0459C 85%, #241219);
  --color-on-action: #1A0E14;
  --color-accent: #8BD450;
  --color-accent-strong: #8BD450;
  --color-accent-hover: color-mix(in srgb, #8BD450 85%, #241219);
  --color-accent-soft: color-mix(in srgb, #8BD450 16%, #241219);
  --color-on-accent: #1A0E14;
  --color-danger: #FF4B3E;
  --color-danger-hover: color-mix(in srgb, #FF4B3E 85%, #241219);
  --color-danger-soft: color-mix(in srgb, #FF4B3E 16%, #241219);
  --color-on-danger: #1A0E14;
  --color-cta: #FF9F1C;
  --color-cta-hover: color-mix(in srgb, #FF9F1C 85%, #241219);
  --color-on-cta: #1A0E14;
  --color-info: #4FC3F7;
  --color-highlight: #FFD23F;
  --color-highlight-soft: color-mix(in srgb, #FFD23F 16%, #241219);
  --color-highlight-border: color-mix(in srgb, #FFD23F 45%, #241219);
  --color-highlight-text: color-mix(in srgb, #FFD23F 80%, #FBEFF2);
  --color-highlight-deep: #FFD23F;
  --color-on-highlight: #1A0E14;
  --color-warning: #FFD23F;
  --color-warning-soft: color-mix(in srgb, #FFD23F 14%, #241219);
  --color-warning-text: color-mix(in srgb, #FFD23F 80%, #FBEFF2);
  --color-focus: #FBEFF2;
  --color-field: #1A0E14;
  --purple-400: #C77DFF;
  --purple-600: #C77DFF;
  --purple-700: color-mix(in srgb, #C77DFF 80%, #FBEFF2);
  --purple-50: color-mix(in srgb, #C77DFF 14%, #241219);
  --purple-100: color-mix(in srgb, #C77DFF 20%, #241219);
}

/* ---- Caramelo · cumple dulce ---- */
html[data-ds-theme="caramelo"] {
  color-scheme: dark;
  --color-bg: #16100F;
  --color-surface: #1F1715;
  --color-surface-muted: #2B201D;
  --color-border: #3D2D28;
  --color-border-strong: #523D36;
  --color-border-hover: #6E534A;
  --color-border-accent: #6E534A;
  --color-backdrop: rgba(0, 0, 0, 0.65);
  --color-text: #FBF0EA;
  --color-text-muted: #CBB3A8;
  --color-text-subtle: #937D72;
  /* signature action: the theme's own color, not the system's */
  --color-action: #FF8FB1;
  --color-action-hover: color-mix(in srgb, #FF8FB1 85%, #1F1715);
  --color-on-action: #16100F;
  --color-accent: #7FE0C3;
  --color-accent-strong: #7FE0C3;
  --color-accent-hover: color-mix(in srgb, #7FE0C3 85%, #1F1715);
  --color-accent-soft: color-mix(in srgb, #7FE0C3 16%, #1F1715);
  --color-on-accent: #16100F;
  --color-danger: #F06262;
  --color-danger-hover: color-mix(in srgb, #F06262 85%, #1F1715);
  --color-danger-soft: color-mix(in srgb, #F06262 16%, #1F1715);
  --color-on-danger: #16100F;
  --color-cta: #7FE0C3;
  --color-cta-hover: color-mix(in srgb, #7FE0C3 85%, #1F1715);
  --color-on-cta: #16100F;
  --color-info: #90CAF9;
  --color-highlight: #FFD59E;
  --color-highlight-soft: color-mix(in srgb, #FFD59E 16%, #1F1715);
  --color-highlight-border: color-mix(in srgb, #FFD59E 45%, #1F1715);
  --color-highlight-text: color-mix(in srgb, #FFD59E 80%, #FBF0EA);
  --color-highlight-deep: #FFD59E;
  --color-on-highlight: #16100F;
  --color-warning: #FFD59E;
  --color-warning-soft: color-mix(in srgb, #FFD59E 14%, #1F1715);
  --color-warning-text: color-mix(in srgb, #FFD59E 80%, #FBF0EA);
  --color-focus: #FBF0EA;
  --color-field: #16100F;
  --purple-400: #D0A9E8;
  --purple-600: #D0A9E8;
  --purple-700: color-mix(in srgb, #D0A9E8 80%, #FBF0EA);
  --purple-50: color-mix(in srgb, #D0A9E8 14%, #1F1715);
  --purple-100: color-mix(in srgb, #D0A9E8 20%, #1F1715);
}

/* ---- Mariposa · XV lila ---- */
html[data-ds-theme="mariposa"] {
  color-scheme: dark;
  --color-bg: #120F1C;
  --color-surface: #1A1528;
  --color-surface-muted: #241D38;
  --color-border: #342A50;
  --color-border-strong: #463969;
  --color-border-hover: #604F8C;
  --color-border-accent: #604F8C;
  --color-backdrop: rgba(0, 0, 0, 0.65);
  --color-text: #F4F0FB;
  --color-text-muted: #BCAFD9;
  --color-text-subtle: #82749F;
  /* signature action: the theme's own color, not the system's */
  --color-action: #C9A0F0;
  --color-action-hover: color-mix(in srgb, #C9A0F0 85%, #1A1528);
  --color-on-action: #120F1C;
  --color-accent: #A0D9B8;
  --color-accent-strong: #A0D9B8;
  --color-accent-hover: color-mix(in srgb, #A0D9B8 85%, #1A1528);
  --color-accent-soft: color-mix(in srgb, #A0D9B8 16%, #1A1528);
  --color-on-accent: #120F1C;
  --color-danger: #E87C8C;
  --color-danger-hover: color-mix(in srgb, #E87C8C 85%, #1A1528);
  --color-danger-soft: color-mix(in srgb, #E87C8C 16%, #1A1528);
  --color-on-danger: #120F1C;
  --color-cta: #F0A0D0;
  --color-cta-hover: color-mix(in srgb, #F0A0D0 85%, #1A1528);
  --color-on-cta: #120F1C;
  --color-info: #A0B8F0;
  --color-highlight: #D9DCE8;
  --color-highlight-soft: color-mix(in srgb, #D9DCE8 16%, #1A1528);
  --color-highlight-border: color-mix(in srgb, #D9DCE8 45%, #1A1528);
  --color-highlight-text: color-mix(in srgb, #D9DCE8 80%, #F4F0FB);
  --color-highlight-deep: #D9DCE8;
  --color-on-highlight: #120F1C;
  --color-warning: #D9DCE8;
  --color-warning-soft: color-mix(in srgb, #D9DCE8 14%, #1A1528);
  --color-warning-text: color-mix(in srgb, #D9DCE8 80%, #F4F0FB);
  --color-focus: #F4F0FB;
  --color-field: #120F1C;
  --purple-400: #C9A0F0;
  --purple-600: #C9A0F0;
  --purple-700: color-mix(in srgb, #C9A0F0 80%, #F4F0FB);
  --purple-50: color-mix(in srgb, #C9A0F0 14%, #1A1528);
  --purple-100: color-mix(in srgb, #C9A0F0 20%, #1A1528);
}

/* ---- Princesa · XV azul real ---- */
html[data-ds-theme="princesa"] {
  color-scheme: dark;
  --color-bg: #0A0F22;
  --color-surface: #101838;
  --color-surface-muted: #16224E;
  --color-border: #22306A;
  --color-border-strong: #2E3F88;
  --color-border-hover: #4256AE;
  --color-border-accent: #4256AE;
  --color-backdrop: rgba(0, 0, 0, 0.65);
  --color-text: #EDF1FC;
  --color-text-muted: #A9B6DE;
  --color-text-subtle: #6C7CAF;
  /* signature action: the theme's own color, not the system's */
  --color-action: #6E8EF5;
  --color-action-hover: color-mix(in srgb, #6E8EF5 85%, #101838);
  --color-on-action: #0A0F22;
  --color-accent: #8FD9B8;
  --color-accent-strong: #8FD9B8;
  --color-accent-hover: color-mix(in srgb, #8FD9B8 85%, #101838);
  --color-accent-soft: color-mix(in srgb, #8FD9B8 16%, #101838);
  --color-on-accent: #0A0F22;
  --color-danger: #E87C8C;
  --color-danger-hover: color-mix(in srgb, #E87C8C 85%, #101838);
  --color-danger-soft: color-mix(in srgb, #E87C8C 16%, #101838);
  --color-on-danger: #0A0F22;
  --color-cta: #E8D080;
  --color-cta-hover: color-mix(in srgb, #E8D080 85%, #101838);
  --color-on-cta: #0A0F22;
  --color-info: #6E8EF5;
  --color-highlight: #E8D080;
  --color-highlight-soft: color-mix(in srgb, #E8D080 16%, #101838);
  --color-highlight-border: color-mix(in srgb, #E8D080 45%, #101838);
  --color-highlight-text: color-mix(in srgb, #E8D080 80%, #EDF1FC);
  --color-highlight-deep: #E8D080;
  --color-on-highlight: #0A0F22;
  --color-warning: #E8D080;
  --color-warning-soft: color-mix(in srgb, #E8D080 14%, #101838);
  --color-warning-text: color-mix(in srgb, #E8D080 80%, #EDF1FC);
  --color-focus: #EDF1FC;
  --color-field: #0A0F22;
  --purple-400: #B9A0F0;
  --purple-600: #B9A0F0;
  --purple-700: color-mix(in srgb, #B9A0F0 80%, #EDF1FC);
  --purple-50: color-mix(in srgb, #B9A0F0 14%, #101838);
  --purple-100: color-mix(in srgb, #B9A0F0 20%, #101838);
}

/* ---- Synthwave · retro neón ---- */
html[data-ds-theme="synthwave"] {
  color-scheme: dark;
  --color-bg: #120B22;
  --color-surface: #1A1032;
  --color-surface-muted: #241745;
  --color-border: #332059;
  --color-border-strong: #452C77;
  --color-border-hover: #5F3D9E;
  --color-border-accent: #5F3D9E;
  --color-backdrop: rgba(0, 0, 0, 0.65);
  --color-text: #F4EEFF;
  --color-text-muted: #B9A8E0;
  --color-text-subtle: #7E6BAB;
  /* signature action: the theme's own color, not the system's */
  --color-action: #FF4F9A;
  --color-action-hover: color-mix(in srgb, #FF4F9A 85%, #1A1032);
  --color-on-action: #120B22;
  --color-accent: #3EE87F;
  --color-accent-strong: #3EE87F;
  --color-accent-hover: color-mix(in srgb, #3EE87F 85%, #1A1032);
  --color-accent-soft: color-mix(in srgb, #3EE87F 16%, #1A1032);
  --color-on-accent: #120B22;
  --color-danger: #FF4560;
  --color-danger-hover: color-mix(in srgb, #FF4560 85%, #1A1032);
  --color-danger-soft: color-mix(in srgb, #FF4560 16%, #1A1032);
  --color-on-danger: #120B22;
  --color-cta: #2DE2E6;
  --color-cta-hover: color-mix(in srgb, #2DE2E6 85%, #1A1032);
  --color-on-cta: #120B22;
  --color-info: #2DE2E6;
  --color-highlight: #FFB84D;
  --color-highlight-soft: color-mix(in srgb, #FFB84D 16%, #1A1032);
  --color-highlight-border: color-mix(in srgb, #FFB84D 45%, #1A1032);
  --color-highlight-text: color-mix(in srgb, #FFB84D 80%, #F4EEFF);
  --color-highlight-deep: #FFB84D;
  --color-on-highlight: #120B22;
  --color-warning: #FFB84D;
  --color-warning-soft: color-mix(in srgb, #FFB84D 14%, #1A1032);
  --color-warning-text: color-mix(in srgb, #FFB84D 80%, #F4EEFF);
  --color-focus: #F4EEFF;
  --color-field: #120B22;
  --purple-400: #B388FF;
  --purple-600: #B388FF;
  --purple-700: color-mix(in srgb, #B388FF 80%, #F4EEFF);
  --purple-50: color-mix(in srgb, #B388FF 14%, #1A1032);
  --purple-100: color-mix(in srgb, #B388FF 20%, #1A1032);
}

/* ---- UV · blacklight ---- */
html[data-ds-theme="uv"] {
  color-scheme: dark;
  --color-bg: #0C0716;
  --color-surface: #140C24;
  --color-surface-muted: #1D1234;
  --color-border: #2C1C4E;
  --color-border-strong: #3D2868;
  --color-border-hover: #553A8E;
  --color-border-accent: #553A8E;
  --color-backdrop: rgba(0, 0, 0, 0.65);
  --color-text: #F0EAFF;
  --color-text-muted: #B4A3E0;
  --color-text-subtle: #7A68A8;
  /* signature action: the theme's own color, not the system's */
  --color-action: #B266FF;
  --color-action-hover: color-mix(in srgb, #B266FF 85%, #140C24);
  --color-on-action: #0C0716;
  --color-accent: #7CFF66;
  --color-accent-strong: #7CFF66;
  --color-accent-hover: color-mix(in srgb, #7CFF66 85%, #140C24);
  --color-accent-soft: color-mix(in srgb, #7CFF66 16%, #140C24);
  --color-on-accent: #0C0716;
  --color-danger: #FF5566;
  --color-danger-hover: color-mix(in srgb, #FF5566 85%, #140C24);
  --color-danger-soft: color-mix(in srgb, #FF5566 16%, #140C24);
  --color-on-danger: #0C0716;
  --color-cta: #C6FF4D;
  --color-cta-hover: color-mix(in srgb, #C6FF4D 85%, #140C24);
  --color-on-cta: #0C0716;
  --color-info: #66C6FF;
  --color-highlight: #FF66E0;
  --color-highlight-soft: color-mix(in srgb, #FF66E0 16%, #140C24);
  --color-highlight-border: color-mix(in srgb, #FF66E0 45%, #140C24);
  --color-highlight-text: color-mix(in srgb, #FF66E0 80%, #F0EAFF);
  --color-highlight-deep: #FF66E0;
  --color-on-highlight: #0C0716;
  --color-warning: #FF66E0;
  --color-warning-soft: color-mix(in srgb, #FF66E0 14%, #140C24);
  --color-warning-text: color-mix(in srgb, #FF66E0 80%, #F0EAFF);
  --color-focus: #F0EAFF;
  --color-field: #0C0716;
  --purple-400: #B266FF;
  --purple-600: #B266FF;
  --purple-700: color-mix(in srgb, #B266FF 80%, #F0EAFF);
  --purple-50: color-mix(in srgb, #B266FF 14%, #140C24);
  --purple-100: color-mix(in srgb, #B266FF 20%, #140C24);
}

/* ---- Estrobo · boliche láser ---- */
html[data-ds-theme="estrobo"] {
  color-scheme: dark;
  --color-bg: #060608;
  --color-surface: #0E0E12;
  --color-surface-muted: #16161C;
  --color-border: #232330;
  --color-border-strong: #303044;
  --color-border-hover: #44445E;
  --color-border-accent: #44445E;
  --color-backdrop: rgba(0, 0, 0, 0.65);
  --color-text: #F2F2F8;
  --color-text-muted: #A8A8C0;
  --color-text-subtle: #6E6E88;
  /* signature action: the theme's own color, not the system's */
  --color-action: #00E5FF;
  --color-action-hover: color-mix(in srgb, #00E5FF 85%, #0E0E12);
  --color-on-action: #060608;
  --color-accent: #39FF88;
  --color-accent-strong: #39FF88;
  --color-accent-hover: color-mix(in srgb, #39FF88 85%, #0E0E12);
  --color-accent-soft: color-mix(in srgb, #39FF88 16%, #0E0E12);
  --color-on-accent: #060608;
  --color-danger: #FF3355;
  --color-danger-hover: color-mix(in srgb, #FF3355 85%, #0E0E12);
  --color-danger-soft: color-mix(in srgb, #FF3355 16%, #0E0E12);
  --color-on-danger: #060608;
  --color-cta: #FF2FB0;
  --color-cta-hover: color-mix(in srgb, #FF2FB0 85%, #0E0E12);
  --color-on-cta: #060608;
  --color-info: #00E5FF;
  --color-highlight: #FFEB3B;
  --color-highlight-soft: color-mix(in srgb, #FFEB3B 16%, #0E0E12);
  --color-highlight-border: color-mix(in srgb, #FFEB3B 45%, #0E0E12);
  --color-highlight-text: color-mix(in srgb, #FFEB3B 80%, #F2F2F8);
  --color-highlight-deep: #FFEB3B;
  --color-on-highlight: #060608;
  --color-warning: #FFEB3B;
  --color-warning-soft: color-mix(in srgb, #FFEB3B 14%, #0E0E12);
  --color-warning-text: color-mix(in srgb, #FFEB3B 80%, #F2F2F8);
  --color-focus: #F2F2F8;
  --color-field: #060608;
  --purple-400: #A64DFF;
  --purple-600: #A64DFF;
  --purple-700: color-mix(in srgb, #A64DFF 80%, #F2F2F8);
  --purple-50: color-mix(in srgb, #A64DFF 14%, #0E0E12);
  --purple-100: color-mix(in srgb, #A64DFF 20%, #0E0E12);
}

/* ---- Tropical · fiesta playa ---- */
html[data-ds-theme="tropical"] {
  color-scheme: dark;
  --color-bg: #071614;
  --color-surface: #0D211E;
  --color-surface-muted: #142E2A;
  --color-border: #1F423C;
  --color-border-strong: #2C584F;
  --color-border-hover: #3E786C;
  --color-border-accent: #3E786C;
  --color-backdrop: rgba(0, 0, 0, 0.65);
  --color-text: #EDFAF5;
  --color-text-muted: #A3CCC0;
  --color-text-subtle: #6A968A;
  /* signature action: the theme's own color, not the system's */
  --color-action: #FF7059;
  --color-action-hover: color-mix(in srgb, #FF7059 85%, #0D211E);
  --color-on-action: #071614;
  --color-accent: #4FE0A3;
  --color-accent-strong: #4FE0A3;
  --color-accent-hover: color-mix(in srgb, #4FE0A3 85%, #0D211E);
  --color-accent-soft: color-mix(in srgb, #4FE0A3 16%, #0D211E);
  --color-on-accent: #071614;
  --color-danger: #FF5252;
  --color-danger-hover: color-mix(in srgb, #FF5252 85%, #0D211E);
  --color-danger-soft: color-mix(in srgb, #FF5252 16%, #0D211E);
  --color-on-danger: #071614;
  --color-cta: #A3E84D;
  --color-cta-hover: color-mix(in srgb, #A3E84D 85%, #0D211E);
  --color-on-cta: #071614;
  --color-info: #4FC9E0;
  --color-highlight: #FFD166;
  --color-highlight-soft: color-mix(in srgb, #FFD166 16%, #0D211E);
  --color-highlight-border: color-mix(in srgb, #FFD166 45%, #0D211E);
  --color-highlight-text: color-mix(in srgb, #FFD166 80%, #EDFAF5);
  --color-highlight-deep: #FFD166;
  --color-on-highlight: #071614;
  --color-warning: #FFD166;
  --color-warning-soft: color-mix(in srgb, #FFD166 14%, #0D211E);
  --color-warning-text: color-mix(in srgb, #FFD166 80%, #EDFAF5);
  --color-focus: #EDFAF5;
  --color-field: #071614;
  --purple-400: #C990E0;
  --purple-600: #C990E0;
  --purple-700: color-mix(in srgb, #C990E0 80%, #EDFAF5);
  --purple-50: color-mix(in srgb, #C990E0 14%, #0D211E);
  --purple-100: color-mix(in srgb, #C990E0 20%, #0D211E);
}

/* ---- Dorado · gala / año nuevo ---- */
html[data-ds-theme="dorado"] {
  color-scheme: dark;
  --color-bg: #0B0B0C;
  --color-surface: #131314;
  --color-surface-muted: #1C1C1E;
  --color-border: #2B2B2E;
  --color-border-strong: #3C3C40;
  --color-border-hover: #545458;
  --color-border-accent: #545458;
  --color-backdrop: rgba(0, 0, 0, 0.65);
  --color-text: #F5F1E6;
  --color-text-muted: #C2BAA3;
  --color-text-subtle: #878068;
  /* signature action: the theme's own color, not the system's */
  --color-action: #F0C75E;
  --color-action-hover: color-mix(in srgb, #F0C75E 85%, #131314);
  --color-on-action: #0B0B0C;
  --color-accent: #A8C5A0;
  --color-accent-strong: #A8C5A0;
  --color-accent-hover: color-mix(in srgb, #A8C5A0 85%, #131314);
  --color-accent-soft: color-mix(in srgb, #A8C5A0 16%, #131314);
  --color-on-accent: #0B0B0C;
  --color-danger: #D98A7E;
  --color-danger-hover: color-mix(in srgb, #D98A7E 85%, #131314);
  --color-danger-soft: color-mix(in srgb, #D98A7E 16%, #131314);
  --color-on-danger: #0B0B0C;
  --color-cta: #F0C75E;
  --color-cta-hover: color-mix(in srgb, #F0C75E 85%, #131314);
  --color-on-cta: #0B0B0C;
  --color-info: #C9D0DC;
  --color-highlight: #F0DFA0;
  --color-highlight-soft: color-mix(in srgb, #F0DFA0 16%, #131314);
  --color-highlight-border: color-mix(in srgb, #F0DFA0 45%, #131314);
  --color-highlight-text: color-mix(in srgb, #F0DFA0 80%, #F5F1E6);
  --color-highlight-deep: #F0DFA0;
  --color-on-highlight: #0B0B0C;
  --color-warning: #F0DFA0;
  --color-warning-soft: color-mix(in srgb, #F0DFA0 14%, #131314);
  --color-warning-text: color-mix(in srgb, #F0DFA0 80%, #F5F1E6);
  --color-focus: #F5F1E6;
  --color-field: #0B0B0C;
  --purple-400: #C9A9C8;
  --purple-600: #C9A9C8;
  --purple-700: color-mix(in srgb, #C9A9C8 80%, #F5F1E6);
  --purple-50: color-mix(in srgb, #C9A9C8 14%, #131314);
  --purple-100: color-mix(in srgb, #C9A9C8 20%, #131314);
}

/* --- fundamentos.css --- */
/* ============================================================
   fundamentos.css — la base del rediseno

   Se monta ENCIMA de /ds/bundle.css. El kit trae los tokens; esto
   fija las decisiones que el kit deja abiertas y que en el codigo
   anterior nunca se fijaron, que es de donde salio la incoherencia:
   cada pantalla elegia su propio espaciado y su propio tamano.

   Tres decisiones y nada mas:
     1. El ritmo es de 8. Sin excepciones fuera de un control.
     2. Los tamanos de texto son SIETE y cada uno tiene un oficio.
     3. La pantalla mide 1200 y esta centrada.

   Ademas parcha tres fugas del kit: hay componentes que consumen
   PRIMITIVAS (--neutral-50, --green-200) en vez de fichas semanticas,
   asi que bajo un tema oscuro salen casi blancos. Estan marcadas.
   ============================================================ */

:root {
  /* --- 1. RITMO ---------------------------------------------------------
     Multiplos de 8, y el nombre ES la medida: si no lo podes nombrar, no
     lo podes usar. Es lo que impide que aparezcan 13px "porque quedaba
     mejor". El kit trae 4, 12 y 20 en su escala; aca no se usan.

       e8    dentro de un grupo         (icono y su texto, chip y su numero)
       e16   entre controles hermanos   (un campo y el siguiente)
       e24   entre grupos               (un grupo de campos y el proximo)
       e32   entre secciones            (relleno de una tarjeta)
       e48   entre bloques              (una seccion y la que sigue)
       e64   respiro de pantalla        (cabecera y contenido)
       e96   aire de portada            (solo login y estados vacios)
  */
  --e4:  4px;   /* SOLO dentro de un control: el hueco de un icono. */
  --e8:  8px;
  --e16: 16px;
  --e24: 24px;
  --e32: 32px;
  --e40: 40px;
  --e48: 48px;
  --e64: 64px;
  --e80: 80px;
  --e96: 96px;

  /* --- 2. TEXTO ---------------------------------------------------------
     Siete tamanos con oficio. Geist en todo; la variable del kit ya la
     resuelve local, sin Google Fonts.

     Cada rol trae su interlineado y su tracking porque van juntos: un 48
     con interlineado 1.5 se desarma, y un 14 con -0.02em se cierra.
  */
  --t-display: 48px;  /* la promesa del login. Una sola por producto.   */
  --t-titulo:  36px;  /* el nombre de la pantalla.                      */
  --t-seccion: 24px;  /* el nombre de una seccion dentro de la pantalla.*/
  --t-tarjeta: 18px;  /* el titulo de una tarjeta o de una fila.        */
  --t-cuerpo:  16px;  /* lectura normal.                                */
  --t-apoyo:   14px;  /* lo secundario: fechas, notas, metadatos.       */
  --t-etiqueta: 12px; /* rotulos de campo y chips.                      */

  /* --- 3. ANCHO ---------------------------------------------------------
     1200 y centrado. Por encima, una fila de etiqueta y control deja los
     dos extremos separados por medio metro de nada.
  */
  --ancho: 1200px;
  --margen-lateral: var(--e32);
}

/* --- la pagina --------------------------------------------------------- */

html { -webkit-text-size-adjust: 100%; }

body {
  min-height: 100dvh;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-sans);
  font-size: var(--t-cuerpo);
  line-height: var(--leading-normal);
}

.marco {
  width: 100%;
  max-width: var(--ancho);
  margin: 0 auto;
  padding-left: max(var(--margen-lateral), env(safe-area-inset-left));
  padding-right: max(var(--margen-lateral), env(safe-area-inset-right));
}

@media (max-width: 47.99rem) {
  :root { --margen-lateral: var(--e16); }
}

/* --- la escala tipografica --------------------------------------------- */

.display {
  font-size: var(--t-display);
  line-height: 1.05;
  letter-spacing: -0.03em;
  font-weight: var(--weight-semibold);
  margin: 0;
  text-wrap: balance;
}

.titulo {
  font-size: var(--t-titulo);
  line-height: 1.1;
  letter-spacing: -0.025em;
  font-weight: var(--weight-semibold);
  margin: 0;
  text-wrap: balance;
}

.seccion {
  font-size: var(--t-seccion);
  line-height: 1.2;
  letter-spacing: -0.02em;
  font-weight: var(--weight-semibold);
  margin: 0;
}

.tarjeta-titulo {
  font-size: var(--t-tarjeta);
  line-height: 1.3;
  letter-spacing: -0.01em;
  font-weight: var(--weight-medium);
  margin: 0;
}

.cuerpo { font-size: var(--t-cuerpo); line-height: 1.5; margin: 0; }

.apoyo {
  font-size: var(--t-apoyo);
  line-height: 1.45;
  color: var(--color-text-muted);
  margin: 0;
}

.etiqueta {
  font-size: var(--t-etiqueta);
  line-height: 1.35;
  font-weight: var(--weight-medium);
  color: var(--color-text-muted);
  margin: 0;
}

/* Numeros que se comparan de una columna a otra. Sin esto, un 148 y un 311
   no alinean y la lista se lee torcida. */
.dato { font-variant-numeric: tabular-nums; }

/* En un telefono el display de 48 no entra: 34 es el maximo que deja la
   promesa en dos lineas sin partir una palabra. */
@media (max-width: 34rem) {
  :root { --t-display: 34px; --t-titulo: 27px; --t-seccion: 20px; }
}

/* --- utilidades de ritmo ------------------------------------------------
   Pocas y explicitas. No es un framework: son los cinco huecos que se
   repiten en todas las pantallas. */

.pila     { display: flex; flex-direction: column; }
.pila-8   { gap: var(--e8); }
.pila-16  { gap: var(--e16); }
.pila-24  { gap: var(--e24); }
.pila-32  { gap: var(--e32); }
.pila-48  { gap: var(--e48); }

.fila     { display: flex; align-items: center; }
.fila-8   { gap: var(--e8); }
.fila-16  { gap: var(--e16); }
.fila-24  { gap: var(--e24); }

.crece { flex: 1; min-width: 0; }

/* --- parches al kit -----------------------------------------------------
   Tres componentes consumen PRIMITIVAS en vez de fichas semanticas. Las
   primitivas son del sistema claro, asi que bajo cualquiera de los 27 temas
   oscuros salen casi blancas. Es un error del kit, no una eleccion. */

/* Salia un gris casi blanco encima de la fila oscura. */
.table tbody tr:hover { background: var(--color-surface-muted); }

/* El borde de un badge solido no puede ser un verde/ambar/rojo claros. */
.badge--accent,
.badge--warning,
.badge--danger { border-color: transparent; }

/* La pastilla activa se pintaba con --neutral-900, que sobre un tema oscuro
   es invisible. Va con la ficha de accion, que cada tema define. */
.ds-snav__pill.is-active {
  background: var(--color-action);
  color: var(--color-on-action);
}
.ds-snav__pill.is-active .ds-snav__meta { color: var(--color-on-action); opacity: 0.65; }

/* --- foco ---------------------------------------------------------------
   Un anillo, el mismo en todo. El kit lo declara por componente y algunos se
   lo olvidan.

   Va en el color de ACCION del tema y no en `--color-focus`, que en los temas
   oscuros es casi blanco: un anillo blanco sobre una superficie oscura
   contrasta tanto que el elemento enfocado grita. El de accion se nota igual
   y pertenece a la paleta. */
:where(a, button, [tabindex]):focus-visible {
  outline: 2px solid var(--color-action);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}
