/* theme.css — carpeta independiente del tenant «latriguena».
   Generado 2026-09-13T22:49:16Z desde latriguena: hojas de diseño del kernel
   copiadas en su orden de carga + CSS propio entre los marcadores.
   Este archivo es del tenant: editá lo que quieras. Para saber qué cambió
   en el kernel desde entonces: storefront_theme_drift --theme latriguena */

/* ── storefront/css/_design_tokens.css ── */
/* ============================================================
   STOREFRONT V2 — DESIGN TOKENS  (Sprint UX-1, §4 design doc)
   ------------------------------------------------------------
   Single source of truth de variables CSS del storefront
   cross-vertical. Las tokens del config por tenant
   (StorefrontConfig.color_primario / color_secundario) se
   exponen como vars `--tenant-color-*` desde base_storefront.html
   y se mapean aqui como `--sf-color-primary`.

   Naming: kebab-case con prefijo `--sf-` para distinguir del
   resto del proyecto (core/ui usa `--cu-`, design-system usa
   `--ds-`).  Convencion estable: NO renombrar variables ya
   referenciadas por templates.

   Dark mode: activa via `.dark` class en <html> (anti-FOUC init
   en base_storefront.html lee localStorage `sf-theme`) o via
   `prefers-color-scheme: dark` (fallback OS).
   ============================================================ */

:root {
  /* === Brand colors (sobrescribibles por StorefrontConfig) === */
  /* --tenant-color-primary lo inyecta base_storefront.html
     desde storefront_cfg.color_primario. Fallback al brand
     default del storefront (sky-600). */
  --sf-color-primary: var(--tenant-color-primary, #0ea5e9);
  /* T-14: la tinta del primario la decide la luminancia del color de marca
     (base_storefront.html inyecta --tenant-color-primary-fg desde el kernel
     color_contrast). Sin inyección: blanco, como siempre. */
  --sf-color-primary-fg: var(--tenant-color-primary-fg, #ffffff);
  /* Alias del nombre corto que usa la capa de componentes de Tailwind
     (`.sf-btn-primary` en tailwind.src.css hace
     `background: var(--sf-primary, #0ea5e9)`). La variable NUNCA se
     habia definido: el fallback ganaba siempre, asi que los ~20
     templates con `.sf-btn-primary` (POS, CRM, configuracion,
     comunicaciones, delivery) pintaban un celeste fijo que ignoraba
     la marca del tenant y el tema — y quedaban al lado de un
     `.sf-btn--ghost` que si respeta los tokens. Un `var()` fantasma
     no es un token: es un hex cableado con disfraz. */
  --sf-primary: var(--sf-color-primary);
  --sf-color-primary-50: #f0f9ff;
  --sf-color-primary-500: #0ea5e9;
  --sf-color-primary-600: #0284c7;
  --sf-color-primary-700: #0369a1;

  --sf-color-accent: #f59e0b;

  /* === Semantic colors === */
  --sf-color-success: #16a34a;
  --sf-color-warning: #f59e0b;
  --sf-color-danger: #e11d48;
  --sf-color-info: #2563eb;
  /* IT264: la escala semantica tenia CUATRO tonos, pero los tableros de
     estado del producto usan SEIS. Los dos que faltaban (un estado
     "en proceso/mantenimiento" y un estado "inactivo") se venian
     resolviendo con hex fijos dentro del <style> de cada vertical
     (restaurante/sala: #a855f7 y #64748b) — o sea, tokens inventados
     por pantalla, justo lo que S25 prohibe. Al existir aca, el tono
     entra por `.sf-tone--secondary` / `--muted` y adapta solo.
     `muted` SI flipea por tema: gris slate-500 sobre fondo oscuro se
     hunde (2.6:1) y es el tono de "fuera de servicio", que tiene que
     seguir siendo legible. */
  --sf-color-secondary: #8b5cf6;
  --sf-color-muted: #64748b;

  /* === Surface (light) === */
  --sf-color-bg: #ffffff;
  --sf-color-bg-elevated: #f8fafc;
  --sf-color-bg-subtle: #f1f5f9;
  --sf-color-text: #0f172a;
  --sf-color-text-muted: #475569;
  /* IT70: tinta TERCIARIA — decorativa (iconos de estado vacío, glifos
     de fondo). NO es texto: no le aplica el 4.5:1 de AA, debe quedar
     tenue pero visible. Para texto usar --sf-color-text-muted. */
  --sf-color-text-subtle: #94a3b8;
  --sf-color-border: #e2e8f0;
  /* IT261: bordes NO-base con consumidor real. `soft` es el separador
     interno translucido (filas de tabla del storefront); `strong` es el
     borde de foco/hover de un input. Antes vivian como fallback de un
     `var()` fantasma, es decir congelados en su valor light. */
  --sf-color-border-soft: rgb(148 163 184 / 0.18);
  --sf-color-border-strong: #94a3b8;

  /* === Typography family === */
  --sf-font-sans: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --sf-font-display: "Poppins", var(--sf-font-sans);
  --sf-font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  /* === Typography scale (Display / H1-H6 / Body L-M-S / Caption / Overline) === */
  --sf-font-display-size: 3rem;       /* 48px */
  --sf-font-h1: 2.25rem;               /* 36px */
  --sf-font-h3: 1.5rem;                /* 24px */
  --sf-font-h4: 1.25rem;               /* 20px */
  --sf-font-h5: 1.125rem;              /* 18px */
  --sf-font-h6: 1rem;                  /* 16px */
  --sf-font-body-lg: 1.125rem;         /* 18px */
  --sf-font-body: 1rem;                /* 16px */
  --sf-font-body-sm: 0.875rem;         /* 14px */
  --sf-font-caption: 0.75rem;          /* 12px */
  --sf-font-overline: 0.625rem;        /* 10px */

  /* === Line-height === */
  --sf-leading-tight: 1.1;
  --sf-leading-snug: 1.25;
  --sf-leading-normal: 1.5;
  --sf-leading-relaxed: 1.65;

  /* === Letter-spacing === */
  --sf-tracking-tight: -0.02em;
  --sf-tracking-wide: 0.025em;
  --sf-tracking-wider: 0.12em;

  /* === Spacing (4-base) === */
  --sf-space-1: 0.25rem;   /* 4px */
  --sf-space-2: 0.5rem;    /* 8px */
  --sf-space-3: 0.75rem;   /* 12px */
  --sf-space-4: 1rem;      /* 16px */
  --sf-space-5: 1.25rem;   /* 20px — consumidor: dashboard_shell.css (padding
                              de paneles). Era un hueco de la escala. */
  --sf-space-6: 1.5rem;    /* 24px */
  --sf-space-8: 2rem;      /* 32px */
  --sf-space-12: 3rem;     /* 48px */
  --sf-space-16: 4rem;     /* 64px */

  /* === Radius === */
  --sf-radius-sm: 0.25rem;     /* 4px */
  --sf-radius-md: 0.5rem;      /* 8px */
  --sf-radius-lg: 0.75rem;     /* 12px */
  --sf-radius-xl: 1rem;        /* 16px */
  --sf-radius-2xl: 1.5rem;     /* 24px */
  --sf-radius-full: 9999px;

  /* === Shadows === */
  --sf-shadow-xs: 0 1px 2px rgb(15 23 42 / 0.04);   /* consumidor: search.css */
  --sf-shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
  --sf-shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
  --sf-shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
  --sf-shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
  --sf-shadow-focus: 0 0 0 3px rgb(14 165 233 / 0.25);

  /* === Motion === */
  --sf-motion-fast: 150ms;
  --sf-motion-standard: 300ms;
  --sf-motion-slow: 500ms;
  --sf-ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --sf-ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);

  /* === Data-viz (IT66) ===================================================
   * Paleta CANÓNICA de visualización. Antes cada dashboard inventaba sus
   * hex (POS + 10 dashboards de vet) — y la que usaba POS FALLABA las
   * pruebas de daltonismo: `#6366f1` vs `#3b82f6` daban ΔE 7.2 con visión
   * NORMAL (piso 15), o sea "Transferencia" y "Tarjeta" se veían iguales.
   *
   * CATEGÓRICA (identidad: series, métodos de pago, categorías). Se asigna
   * en ORDEN FIJO, nunca ciclada: la serie 9 va a "Otros", no a un hue
   * generado. Ambos modos están SELECCIONADOS (dark no es un flip
   * automático: son los mismos 8 hues re-escalonados para fondo oscuro).
   * Validado con el validador de la skill dataviz contra las superficies
   * reales del proyecto (#ffffff / #0f172a): pasa banda de lightness,
   * piso de croma, separación CVD (peor par adyacente ΔE 9.1 light /
   * 8.4 dark, objetivo ≥8) y piso de visión normal (19.6 / 19.3, ≥15).
   * En light, 3 slots quedan bajo 3:1 vs el fondo → REGLA DE RELIEVE:
   * esos marks necesitan label visible o vista de tabla (no color solo). */
  --sf-viz-1: #2a78d6;   /* blue    */
  --sf-viz-2: #eb6834;   /* orange  */
  --sf-viz-3: #1baf7a;   /* aqua    */
  --sf-viz-4: #eda100;   /* yellow  */
  --sf-viz-5: #e87ba4;   /* magenta */
  --sf-viz-6: #008300;   /* green   */
  --sf-viz-7: #4a3aa7;   /* violet  */
  --sf-viz-8: #e34948;   /* red     */

  /* SECUENCIAL (magnitud: heatmaps, choropleths). UNA sola hue de claro a
   * oscuro — nunca un arcoíris. Monotónica en lightness OKLab
   * (0.968→0.438) y `l0` se distingue del fondo (contraste 1.10) para que
   * la grilla siga leyéndose donde el valor es cero. */
  --sf-viz-seq-0: #f1f5f9;
  --sf-viz-seq-1: #cfe3fb;
  --sf-viz-seq-2: #9ec7f7;
  --sf-viz-seq-3: #5fa5ee;
  --sf-viz-seq-4: #2a78d6;
  --sf-viz-seq-5: #17509a;

  /* ORDINAL DE SEVERIDAD (antiguedad de saldos, mora, riesgo, SLA). UNA sola
   * hue calida de claro a oscuro: la severidad se lee en el COLOR, no solo en
   * el rotulo. No es la categorica (swapear dos pasos cambiaria el
   * significado: "corriente" y "+90 dias" no son intercambiables) ni la
   * secuencial azul (esa codifica magnitud neutra, sin valencia).
   * Validada con el validador de la skill dataviz en modo `--ordinal`:
   * L monotonica, dL >= 0.06 entre pasos adyacentes, extremo claro >= 2:1
   * sobre la superficie y spread de hue < 40deg. Light: 2.44:1 el paso 1.
   * El paso 1 NO es #f97316 a proposito — ese hex esta en la lista prohibida
   * del guard (paleta vieja del POS que fallaba CVD). */
  --sf-viz-sev-1: #fb8324;
  --sf-viz-sev-2: #e2540b;
  --sf-viz-sev-3: #c2410c;
  --sf-viz-sev-4: #9a3412;
  --sf-viz-sev-5: #6b2410;

  /* Superficie del chart y ejes/grilla: recesivos, nunca compiten con los
   * marks. El texto de un chart usa tokens de TEXTO (--sf-color-text*),
   * jamás el color de la serie. */
  --sf-viz-surface: var(--sf-color-bg);
  --sf-viz-grid: color-mix(in srgb, var(--sf-color-border) 60%, transparent);

  /* === Z-index (solo los pasos con consumidores; la escala completa y
     los breakpoints muertos se eliminaron 2026-08-09 — re-agregar un paso
     SOLO junto con su consumidor) === */
  --sf-z-dropdown: 1000;
  --sf-z-sticky: 1020;

  /* === Ancho del shell de la tienda (S29.3 · monitores grandes) ==========
   * El storefront cablea su contenedor a `max-w-7xl` (1280px) en los ~100
   * lugares donde abre una seccion. En un notebook eso llena la pantalla; en
   * un monitor de 2560px deja el 50% del ancho en blanco y la tienda queda
   * como una columna perdida en el medio.
   *
   * El valor no es nuevo: `home.html` del kernel ya lo habia resuelto con
   * este mismo clamp, pero enterrado en un `<style>` del template — asi que
   * ninguna otra pagina ni ninguna de las 15 carpetas independientes podia
   * consumirlo. Aca vive como token: el ancho de la tienda es UNA decision
   * de diseno, no una linea suelta de cada template.
   *
   * Fluido con topes, no escalonado: crece con la pantalla y frena a 2400px,
   * porque una tienda a 2560px corridos tiene renglones ilegibles. El piso
   * de 80rem deja notebook (efectivo 1200-1400px) y mobile EXACTAMENTE como
   * estan: por debajo de ~1640px el clamp devuelve 1280px y no cambia nada. */
  --sf-shell-max: clamp(80rem, 78vw, 150rem);   /* 1280px → 2400px */

  /* Radio de la barra de busqueda. Lo comparten las DOS capas del control:
   * el wrapper `.sf-searchbox` y el `.sf-searchbox-input` que va adentro.
   *
   * El kernel dejo el wrapper como estructura pura (position + width) y le dio
   * la apariencia al input (pill, borde, fondo). Un tema que decore el wrapper
   * —fondo, sombra— sin darle el MISMO radio deja un rectangulo asomando en
   * las cuatro esquinas del pill: la terminacion sucia que reporto el dueno
   * (2026-09-13). Pasaba en restaurante (wrapper 0px) y, mas sutil, en
   * puntoventa (wrapper 6px contra un input de 9999px).
   *
   * Con un token las dos capas no pueden separarse: un tema que quiera
   * esquinas rectas cambia ESTE valor y las dos lo siguen. */
  --sf-searchbox-radius: 9999px;

  /* Trazo de la barra de busqueda. El campo va sobre el header y en varios
   * temas su relleno es EL MISMO tono que el header (1.0:1 medido en el tema
   * calido), asi que el limite es lo unico que dibuja el control: WCAG 1.4.11
   * pide 3:1 y `--sf-color-border` daba 1.36. `border-strong` a secas tampoco
   * alcanza en todos lados (2.56 contra el blanco de la paleta neutra), asi
   * que se corre un poco hacia la tinta. Medido en los cuatro escenarios
   * (calido y neutro x claro y oscuro): 3.76 / 4.98 / 3.43 / 4.56.
   *
   * Sale de dos tokens que ya flipean con el tema y con el modo, asi que el
   * par dark no hay que escribirlo. Un tema que quiera otro trazo redefine
   * este token, no el borde de una de las capas. */
  --sf-searchbox-border: color-mix(in srgb, var(--sf-color-border-strong) 70%, var(--sf-color-text-muted));

  /* Ancho ideal de UNA tarjeta en una grilla que suma columnas
   * (`.sf-cardgrid`). Las grillas lo sobreescriben localmente segun lo que
   * muestran: un tile de categoria pide menos que una card de producto. */
  --sf-cardgrid-min: 17rem;   /* 272px */
}

/* === Dark mode via prefers-color-scheme (cuando el usuario nunca eligio) === */
@media (prefers-color-scheme: dark) {
  :root:not(.light):not([data-theme="light"]) {
    --sf-color-bg: #0f172a;
    --sf-color-bg-elevated: #1e293b;
    --sf-color-bg-subtle: #334155;
    --sf-color-text: #f1f5f9;
    --sf-color-text-muted: #94a3b8;
    --sf-color-text-subtle: #64748b;
    --sf-color-border: #334155;
    --sf-color-border-soft: rgb(148 163 184 / 0.22);
    --sf-color-border-strong: #64748b;
    --sf-color-muted: #94a3b8;
    /* IT266: primary-50/-700 eran hex CLAROS fijos — toda superficie
       "seleccionada" (radio/payment cards del checkout, highlight PDP,
       widgets) quedaba con texto claro sobre fondo claro en dark.
       En dark se derivan del brand del tenant via color-mix: tinte
       oscuro para fondos, tinte claro para texto de acento. */
    /* IT270: el «16%, #1e293b» clavaba el slate del kernel adentro del
       token. En una tienda con paleta y tema propios (menta + chocolate)
       la card SELECCIONADA salia azul-gris dentro de una tarjeta marron:
       el tinte no pertenecia a ninguna superficie de esa tienda. Mezclar
       contra los tokens de superficie/tinta lo deja igual donde el kernel
       manda (ahi bg-elevated ES #1e293b) y correcto donde no. */
    --sf-color-primary-50: color-mix(
      in srgb, var(--sf-color-primary) 16%, var(--sf-color-bg-elevated));
    --sf-color-primary-700: color-mix(
      in srgb, var(--sf-color-primary) 55%, var(--sf-color-text));

    /* Data-viz dark (IT66): pasos SELECCIONADOS para el fondo oscuro
       (#0f172a), no un flip del set light. Categórica validada como
       conjunto; secuencial invertida en luminancia (oscuro→claro) y
       monotónica ascendente (L 0.279→0.753). */
    --sf-viz-1: #3987e5;
    --sf-viz-2: #d95926;
    --sf-viz-3: #199e70;
    --sf-viz-4: #c98500;
    --sf-viz-5: #d55181;
    --sf-viz-6: #008300;
    --sf-viz-7: #9085e9;
    --sf-viz-8: #e66767;
    --sf-viz-seq-0: #1e293b;
    --sf-viz-seq-1: #1e3a5f;
    --sf-viz-seq-2: #24568f;
    --sf-viz-seq-3: #2f74c0;
    --sf-viz-seq-4: #3987e5;
    --sf-viz-seq-5: #7db3f0;

    /* Severidad dark: pasos SELECCIONADOS, invertidos en luminancia. Sobre
       fondo oscuro el paso mas severo es el mas BRILLANTE (13.2:1 vs
       #0f172a) — el mas grave tiene que pesar mas, y en dark el peso lo da
       la luz, no la oscuridad. Validada con `--ordinal --mode dark`. */
    --sf-viz-sev-1: #be5b16;
    --sf-viz-sev-2: #e06a1c;
    --sf-viz-sev-3: #f9873a;
    --sf-viz-sev-4: #fcb072;
    --sf-viz-sev-5: #fed7aa;
  }
}

/* === Dark mode explicit (class `dark` sobre <html>, set por anti-FOUC init) === */
.dark,
[data-theme="dark"] {
  --sf-color-bg: #0f172a;
  --sf-color-bg-elevated: #1e293b;
  --sf-color-bg-subtle: #334155;
  --sf-color-text: #f1f5f9;
  --sf-color-text-muted: #94a3b8;
  --sf-color-text-subtle: #64748b;
  --sf-color-border: #334155;
  --sf-color-border-soft: rgb(148 163 184 / 0.22);
  --sf-color-border-strong: #64748b;
  --sf-color-muted: #94a3b8;
  --sf-shadow-focus: 0 0 0 3px rgb(56 189 248 / 0.35);
  /* IT266: ver nota en el bloque prefers-color-scheme — mismos valores. */
  /* IT270: ver la nota del bloque prefers-color-scheme — mismo cambio. */
  --sf-color-primary-50: color-mix(
    in srgb, var(--sf-color-primary) 16%, var(--sf-color-bg-elevated));
  --sf-color-primary-700: color-mix(
    in srgb, var(--sf-color-primary) 55%, var(--sf-color-text));

  /* Data-viz dark (IT66): pasos SELECCIONADOS para el fondo oscuro
     (#0f172a), no un flip del set light. Categórica validada como
     conjunto; secuencial invertida en luminancia (oscuro→claro) y
     monotónica ascendente (L 0.279→0.753). */
  --sf-viz-1: #3987e5;
  --sf-viz-2: #d95926;
  --sf-viz-3: #199e70;
  --sf-viz-4: #c98500;
  --sf-viz-5: #d55181;
  --sf-viz-6: #008300;
  --sf-viz-7: #9085e9;
  --sf-viz-8: #e66767;
  --sf-viz-seq-0: #1e293b;
  --sf-viz-seq-1: #1e3a5f;
  --sf-viz-seq-2: #24568f;
  --sf-viz-seq-3: #2f74c0;
  --sf-viz-seq-4: #3987e5;
  --sf-viz-seq-5: #7db3f0;

  /* Severidad dark: pasos SELECCIONADOS, invertidos en luminancia. Sobre
     fondo oscuro el paso mas severo es el mas BRILLANTE (13.2:1 vs
     #0f172a) — el mas grave tiene que pesar mas, y en dark el peso lo da
     la luz, no la oscuridad. Validada con `--ordinal --mode dark`. */
  --sf-viz-sev-1: #be5b16;
  --sf-viz-sev-2: #e06a1c;
  --sf-viz-sev-3: #f9873a;
  --sf-viz-sev-4: #fcb072;
  --sf-viz-sev-5: #fed7aa;

}

/* ── storefront/css/_components.css ── */
/* ============================================================
   STOREFRONT V2 — COMPONENTES REUSABLES (Sprint UX-1, §4.3)
   ------------------------------------------------------------
   Componentes nuevos / complementarios al set ya cargado por
   tailwind.css (sf-btn / sf-btn-primary / sf-card / sf-skip-link
   ya viven ahi via @apply).

   Este archivo NO redefine clases existentes — solo agrega
   variantes V2 que dependen exclusivamente de los design tokens
   de `_design_tokens.css` (CSS vars `--sf-*`).  Es seguro
   incluirlo despues de tailwind.css sin colisiones.

   Convenciones:
   - Nuevas variantes V2: sufijo descriptivo (sf-btn-danger,
     sf-badge-discount, sf-card-elevated).
   - Componentes nuevos: prefijo sf-v2- evitable solo si NO
     colisiona (sf-skeleton, sf-toast-v2, sf-modal, ...).
   - Si una clase ya esta definida en tailwind.src.css, NO se
     redefine aqui para evitar especificidad rara.
   ============================================================ */

/* ============================================================
   EL ATRIBUTO `hidden` TIENE QUE ESCONDER (2026-09-07)
   ------------------------------------------------------------
   `[hidden] { display: none }` vive en la hoja del NAVEGADOR, así
   que cualquier `display` de autor le gana — no por especificidad,
   sino porque el CSS de autor siempre pisa al del user-agent. Toda
   clase con `display` (una utilidad `inline-flex` de Tailwind, un
   `.lt-countdot`, un `.sf-*` con flex) deja el atributo INERTE: el
   template escribe `hidden`, el navegador lo ignora y el elemento
   se ve igual.

   Caso real: los badges de carrito y favoritos del storefront
   mostraban un «0» naranja sobre el ícono. El template ya hacía lo
   correcto (`{% if not cart_data.count %}hidden{% endif %}`) y el
   DOM tenía el atributo puesto — pero `.lt-countdot` declara
   `display:inline-flex` y ganaba. Se había parcheado UNA vez, caso
   por caso, en `checkout_wizard.css`; acá se cierra la causa para
   todo el kernel y los dos shells.

   `!important` es deliberado: es la única forma de que el atributo
   gane sin ir clase por clase. Si algo necesita verse, que no lleve
   `hidden`.
   ============================================================ */
[hidden] {
  display: none !important;
}

/* ============================================================
   BUTTONS — variantes V2
   ============================================================ */
.sf-btn-danger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sf-space-2);
  padding: var(--sf-space-2) var(--sf-space-4);
  border-radius: var(--sf-radius-md);
  font-weight: 600;
  font-size: var(--sf-font-body-sm);
  background: var(--sf-color-danger);
  color: #ffffff;
  border: 1px solid transparent;
  cursor: pointer;
  transition: filter var(--sf-motion-fast) var(--sf-ease-out),
              transform var(--sf-motion-fast) var(--sf-ease-out),
              box-shadow var(--sf-motion-fast) var(--sf-ease-out);
}
.sf-btn-danger:hover {
  filter: brightness(1.08);
  transform: translateY(-1px);
  box-shadow: var(--sf-shadow-md);
}
.sf-btn-danger:disabled {
  opacity: 0.5;
  cursor: not-allowed;
  transform: none;
}

.sf-btn-success {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sf-space-2);
  padding: var(--sf-space-2) var(--sf-space-4);
  border-radius: var(--sf-radius-md);
  font-weight: 600;
  font-size: var(--sf-font-body-sm);
  background: var(--sf-color-success);
  color: #ffffff;
  border: 1px solid transparent;
  cursor: pointer;
  transition: filter var(--sf-motion-fast) var(--sf-ease-out),
              transform var(--sf-motion-fast) var(--sf-ease-out),
              box-shadow var(--sf-motion-fast) var(--sf-ease-out);
}
.sf-btn-success:hover {
  filter: brightness(1.08);
  transform: translateY(-1px);
  box-shadow: var(--sf-shadow-md);
}

/* Tamano extra-small / extra-large (complementan sf-btn-lg ya existente) */
.sf-btn-xs {
  padding: var(--sf-space-1) var(--sf-space-2);
  font-size: var(--sf-font-caption);
}
.sf-btn-sm {
  padding: var(--sf-space-1) var(--sf-space-3);
  font-size: var(--sf-font-body-sm);
}
.sf-btn-xl {
  padding: var(--sf-space-4) var(--sf-space-8);
  font-size: var(--sf-font-body-lg);
}

/* ============================================================
   CARDS — variantes V2
   ============================================================ */
.sf-card-elevated {
  background: var(--sf-color-bg-elevated);
  border: 1px solid var(--sf-color-border);
  border-radius: var(--sf-radius-lg);
  padding: var(--sf-space-4);
  box-shadow: var(--sf-shadow-sm);
  transition: box-shadow var(--sf-motion-standard) var(--sf-ease-out),
              transform var(--sf-motion-standard) var(--sf-ease-out);
}
.sf-card-elevated:hover {
  box-shadow: var(--sf-shadow-lg);
  transform: translateY(-2px);
}

.sf-card-flat {
  background: var(--sf-color-bg);
  border: 1px solid var(--sf-color-border);
  border-radius: var(--sf-radius-md);
  padding: var(--sf-space-4);
}

/* ============================================================
   BADGES — variantes semanticas V2
   (sf-badge ya NO esta en tailwind.src.css, definicion completa)
   ============================================================ */
.sf-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--sf-space-1);
  padding: 0 var(--sf-space-2);
  height: 1.5rem;
  border-radius: var(--sf-radius-full);
  font-size: var(--sf-font-caption);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--sf-tracking-wide);
  white-space: nowrap;
}
.sf-badge-success {
  background: rgb(22 163 74 / 0.1);
  color: var(--sf-color-success);
}
.sf-badge-warning {
  background: rgb(245 158 11 / 0.1);
  color: var(--sf-color-warning);
}
.sf-badge-danger {
  background: rgb(225 29 72 / 0.1);
  color: var(--sf-color-danger);
}
.sf-badge-info {
  background: rgb(37 99 235 / 0.1);
  color: var(--sf-color-info);
}
.sf-badge-neutral {
  background: var(--sf-color-bg-subtle);
  color: var(--sf-color-text-muted);
}
/* IT270 — sintaxis CANONICA `--modificador`. Este archivo solo tenia la
   variante de guion simple; `_app_components.css` (app-shell) solo tenia la
   de doble guion. El componente de celda del kernel se usa en LOS DOS shells
   —las pantallas de admin de la tienda tambien montan
   `components/tables/base.html`— asi que un pill toneado del lado storefront
   salia sin color. Se aliasan aca en vez de emitir dos clases por celda
   (doctrina «doble sistema, mismo selector»). */
.sf-badge--success { background: rgb(22 163 74 / 0.1); color: var(--sf-color-success); }
.sf-badge--warning { background: rgb(245 158 11 / 0.1); color: var(--sf-color-warning); }
.sf-badge--danger  { background: rgb(225 29 72 / 0.1); color: var(--sf-color-danger); }
.sf-badge--info    { background: rgb(37 99 235 / 0.1); color: var(--sf-color-info); }
.sf-badge--primary { background: color-mix(in srgb, var(--sf-color-primary) 12%, transparent); color: var(--sf-color-primary); }
.sf-badge--neutral,
.sf-badge--muted   { background: var(--sf-color-bg-subtle); color: var(--sf-color-text-muted); }
.sf-badge-discount {
  background: var(--sf-color-danger);
  color: #ffffff;
  animation: sf-pulse 2s ease-in-out infinite;
}
.sf-badge-new {
  background: var(--sf-color-primary);
  color: var(--sf-color-primary-fg);
}

/* ============================================================
   WIZARD STEPPER — comportamiento responsive del widget kernel
   (`templates/_widgets/_wizard_stepper.html`)
   ============================================================ */

/* IT270 — a 390px el stepper del checkout medía 477px: cuatro circulos,
   cuatro rotulos y tres conectores en una fila `flex` sin `wrap`. El
   documento entero scrolleaba en horizontal, que es justo lo que S29.3
   prohibe. Envolver es mejor que scrollear el nav (no esconde en que
   paso esta el cliente) y mejor que ocultar rotulos (los deja sin
   nombre). Los conectores se retiran al envolver: una linea de 1px
   entre filas no conecta nada, solo suma ruido. */
@media (max-width: 640px) {
  .sf-widget-wizard {
    flex-wrap: wrap;
    row-gap: 0.5rem;
  }

  .sf-widget-wizard > div[aria-hidden="true"] {
    display: none;
  }
}

/* ============================================================
   FORM INPUTS — extension V2
   ============================================================ */

/* IT270 — el campo PERTENECE a su superficie.
   `.sf-input` se compila desde tailwind.src.css con blanco/slate fijos
   (`bg-white dark:bg-slate-800 border-slate-300 dark:border-slate-700`),
   o sea el OTRO sistema de tema: no ve ni la paleta que eligio el dueño
   ni el tema del local. En la tienda del restaurante eso daba una caja
   azul-gris adentro de una tarjeta chocolate — el campo no parecia
   parte del formulario. Y en claro era peor al reves: blanco sobre
   blanco, el input solo se adivinaba por un borde tenue.
   Acá los tres colores salen de tokens, asi que el campo queda hundido
   dentro de SU tarjeta, con la paleta y el tema del dueño, en los dos
   temas.

   Especificidad [0,2,1] a proposito: el bundle compila
   `.sf-input:is(.dark *)` ([0,2,0]) y un selector simple perdia en
   oscuro. Mismo criterio ya documentado para `.sf-kanban-row--*` en
   _app_components.css. `data-sf-palette` lo emite SIEMPRE
   base_storefront.html en el <html>, asi que esto cubre la tienda
   publica entera y NO toca el app-shell, que no lleva ese atributo.
   El bundle Tailwind no se recompila en este entorno: por eso el
   arreglo vive acá y no en tailwind.src.css. */
html[data-sf-palette] .sf-input {
  background: var(--sf-color-bg-subtle);
  color: var(--sf-color-text);
  border-color: var(--sf-color-border);
}

html[data-sf-palette] .sf-input::placeholder {
  color: var(--sf-color-text-subtle);
}

html[data-sf-palette] .sf-input:focus {
  outline: none;
  border-color: var(--sf-color-primary);
  box-shadow: var(--sf-shadow-focus);
}

.sf-input-error {
  border-color: var(--sf-color-danger) !important;
  box-shadow: 0 0 0 3px rgb(225 29 72 / 0.15);
}
.sf-input-error:focus {
  outline-color: var(--sf-color-danger);
}
.sf-form-helper {
  display: block;
  margin-top: var(--sf-space-1);
  font-size: var(--sf-font-caption);
  color: var(--sf-color-text-muted);
}
.sf-form-error {
  display: block;
  margin-top: var(--sf-space-1);
  font-size: var(--sf-font-caption);
  color: var(--sf-color-danger);
  font-weight: 600;
}

/* ============================================================
   SKELETONS — loaders durante HTMX swap / SSR pendiente
   ============================================================ */
.sf-skeleton {
  background: linear-gradient(
    90deg,
    var(--sf-color-bg-elevated) 25%,
    var(--sf-color-border) 50%,
    var(--sf-color-bg-elevated) 75%
  );
  background-size: 200% 100%;
  border-radius: var(--sf-radius-md);
  animation: sf-skeleton-loading 1.5s ease-in-out infinite;
}
.sf-skeleton-text {
  height: 1rem;
  margin-bottom: var(--sf-space-2);
}
.sf-skeleton-title {
  height: 1.5rem;
  width: 60%;
  margin-bottom: var(--sf-space-3);
}
.sf-skeleton-img {
  width: 100%;
  aspect-ratio: 1 / 1;
}
.sf-skeleton-circle {
  border-radius: var(--sf-radius-full);
}

/* ============================================================
   TYPOGRAPHY — V2 (complementan sf-display / sf-h1 / sf-h2 /
   sf-eyebrow ya en tailwind.src.css)
   ============================================================ */
.sf-h3 {
  font-size: var(--sf-font-h3);
  font-weight: 700;
  line-height: var(--sf-leading-snug);
  letter-spacing: var(--sf-tracking-tight);
  color: var(--sf-color-text);
}
.sf-h4 {
  font-size: var(--sf-font-h4);
  font-weight: 600;
  line-height: var(--sf-leading-snug);
  color: var(--sf-color-text);
}
.sf-h5 {
  font-size: var(--sf-font-h5);
  font-weight: 600;
  line-height: var(--sf-leading-snug);
  color: var(--sf-color-text);
}
.sf-h6 {
  font-size: var(--sf-font-h6);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--sf-tracking-wide);
  color: var(--sf-color-text);
}
.sf-body-lg {
  font-size: var(--sf-font-body-lg);
  line-height: var(--sf-leading-relaxed);
  color: var(--sf-color-text);
}
.sf-body {
  font-size: var(--sf-font-body);
  line-height: var(--sf-leading-normal);
  color: var(--sf-color-text);
}
.sf-body-sm {
  font-size: var(--sf-font-body-sm);
  line-height: var(--sf-leading-normal);
  color: var(--sf-color-text);
}
.sf-caption {
  font-size: var(--sf-font-caption);
  line-height: var(--sf-leading-normal);
  color: var(--sf-color-text-muted);
}
.sf-overline {
  font-size: var(--sf-font-overline);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--sf-tracking-wider);
  color: var(--sf-color-text-muted);
}

/* ============================================================
   ANIMATIONS
   ============================================================ */
@keyframes sf-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.6; }
}

@keyframes sf-skeleton-loading {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

@keyframes sf-slide-in-right {
  from { transform: translateX(100%); opacity: 0; }
  to { transform: translateX(0); opacity: 1; }
}

@keyframes sf-slide-in-left {
  from { transform: translateX(-100%); opacity: 0; }
  to { transform: translateX(0); opacity: 1; }
}

@keyframes sf-slide-up {
  from { transform: translateY(20px); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}

@keyframes sf-fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes sf-scale-in {
  from { opacity: 0; transform: scale(0.95); }
  to { opacity: 1; transform: scale(1); }
}

/* Utility classes para aplicar las animaciones */
.sf-anim-slide-in-right {
  animation: sf-slide-in-right var(--sf-motion-standard) var(--sf-ease-out);
}
.sf-anim-slide-in-left {
  animation: sf-slide-in-left var(--sf-motion-standard) var(--sf-ease-out);
}
.sf-anim-slide-up {
  animation: sf-slide-up var(--sf-motion-standard) var(--sf-ease-out);
}
.sf-anim-fade-in {
  animation: sf-fade-in var(--sf-motion-standard) var(--sf-ease-out);
}
.sf-anim-scale-in {
  animation: sf-scale-in var(--sf-motion-fast) var(--sf-ease-bounce);
}

/* ============================================================
   SURFACES — utilidades cross-cutting
   ============================================================ */
.sf-surface {
  background: var(--sf-color-bg);
  color: var(--sf-color-text);
}
.sf-surface-elevated {
  background: var(--sf-color-bg-elevated);
  color: var(--sf-color-text);
}
.sf-surface-subtle {
  background: var(--sf-color-bg-subtle);
  color: var(--sf-color-text);
}
.sf-divider {
  height: 1px;
  background: var(--sf-color-border);
  border: 0;
  margin: var(--sf-space-4) 0;
}

/* Stat card / stat mini / .sf-kpi-grid — MOVIDOS a `_kpi_strip.css`
   (IT76): sus consumidores viven en el app-shell, que no carga este
   archivo. Fuente unica alla; los dos shells lo enlazan. */

/* ============================================================
 * Tabla kernel (IT48, S29) — skin canonico de TODA tabla del
 * app-shell. `.sf-table` es el nombre canonico; `.workspace-table`
 * (legacy) queda unificado a este mismo skin. La densidad vive
 * ACA (los px-* / py-* utilitarios por celda quedan anulados por
 * especificidad) — prohibido re-declarar paddings por vertical.
 * ============================================================ */
.sf-table,
.workspace-table {
    width: 100%;
    font-size: 13px;
    border-collapse: collapse;
}
.sf-table thead th,
.workspace-table thead th {
    padding: .5rem .75rem;
    font-size: .62rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: .1em;
    color: var(--sf-color-text-muted, #64748b);
    background: var(--sf-color-bg-subtle, #f8fafc);
    border-bottom: 1px solid var(--sf-color-border, #e2e8f0);
}
.sf-table tbody td,
.workspace-table tbody td {
    padding: .5rem .75rem;
    border-bottom: 1px solid var(--sf-color-border-soft);
}
.sf-table tbody tr,
.workspace-table tbody tr {
    transition: background-color .15s ease;
}
.sf-table tbody tr:hover,
.workspace-table tbody tr:hover {
    background: var(--sf-color-bg-subtle, rgba(248, 250, 252, .86));
}
.dark .sf-table thead th,
html[data-theme="dark"] .sf-table thead th,
.dark .workspace-table thead th,
html[data-theme="dark"] .workspace-table thead th {
    background: rgba(15, 23, 42, .55);
}
.dark .sf-table tbody tr:hover,
html[data-theme="dark"] .sf-table tbody tr:hover,
.dark .workspace-table tbody tr:hover,
html[data-theme="dark"] .workspace-table tbody tr:hover {
    background: rgba(51, 65, 85, .3);
}

/* ============================================================
 * Rank list (IT55, S29) — listas "Top N" de dashboards (top
 * productos, top clientes, top campanas...). Anatomia kernel:
 * medallon de posicion (podio 1/2/3 con metalicos), label+meta,
 * valor tabular y barra de proporcion RELATIVA AL LIDER (width
 * via data-style-width -> style-bind.js, CSP-safe, re-scan en
 * swaps htmx). No re-declarar rankings ad-hoc por vertical.
 * ============================================================ */
.sf-ranklist { list-style: none; margin: 0; padding: 0; }
.sf-ranklist__item {
    display: grid;
    grid-template-columns: auto 1fr auto;
    column-gap: .65rem;
    align-items: center;
    padding: .5rem 0;
    border-bottom: 1px solid var(--sf-color-border-soft);
}
.sf-ranklist__item:last-child { border-bottom: 0; }
.sf-ranklist__rank {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.6rem;
    height: 1.6rem;
    border-radius: 999px;
    font-size: .7rem;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    background: var(--sf-color-bg-subtle, #f1f5f9);
    color: var(--sf-color-text-muted, #64748b);
    border: 1px solid var(--sf-color-border, #e2e8f0);
}
.sf-ranklist__rank--1 {
    background: linear-gradient(135deg, #fbbf24, #d97706);
    color: #fff; border: 0;
    box-shadow: 0 2px 6px -1px rgba(217, 119, 6, .5);
}
.sf-ranklist__rank--2 {
    background: linear-gradient(135deg, #cbd5e1, #94a3b8);
    color: #fff; border: 0;
}
.sf-ranklist__rank--3 {
    background: linear-gradient(135deg, #fdba74, #ea580c);
    color: #fff; border: 0;
}
.sf-ranklist__body { min-width: 0; }
.sf-ranklist__label {
    font-size: .82rem;
    font-weight: 600;
    color: var(--sf-color-text, #0f172a);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sf-ranklist__meta {
    font-size: .68rem;
    color: var(--sf-color-text-muted, #64748b);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sf-ranklist__value {
    font-size: .82rem;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.sf-ranklist__track {
    grid-column: 2 / -1;
    height: 4px;
    margin-top: .3rem;
    border-radius: 999px;
    background: var(--sf-color-bg-subtle, rgba(148, 163, 184, .18));
    overflow: hidden;
}
.sf-ranklist__bar {
    display: block;
    height: 100%;
    width: 0;
    border-radius: 999px;
    background: var(--sf-rank-bar, linear-gradient(90deg, #3b82f6, #6366f1));
    transition: width .5s ease;
}
.sf-ranklist__bar--emerald { --sf-rank-bar: linear-gradient(90deg, #34d399, #059669); }
.sf-ranklist__bar--blue    { --sf-rank-bar: linear-gradient(90deg, #60a5fa, #2563eb); }
.sf-ranklist__bar--amber   { --sf-rank-bar: linear-gradient(90deg, #fbbf24, #d97706); }
.sf-ranklist__bar--violet  { --sf-rank-bar: linear-gradient(90deg, #a78bfa, #7c3aed); }

/* ── htmx indicators (IT122, QA ISSUE-009) ────────────────────────────
 * htmx inyecta estas reglas via <style> SIN nonce y la CSP las bloquea.
 * Se desactiva la inyección (meta htmx-config en base_storefront) y las
 * reglas viven acá — mismo patrón que app_shell + styles.css. */
.htmx-indicator { opacity: 0; transition: opacity 200ms ease-in; }
.htmx-request .htmx-indicator { opacity: 1; }
.htmx-request.htmx-indicator { opacity: 1; }

/* ── Costos de envío por zona (carrito / checkout) ──────────────────────
   Bloque plegable con las tarifas REALES del tenant. `<details>` nativo:
   sin JS y CSP-safe. Colores por tokens --sf-*: dark pareado gratis. */
.sf-envio-zonas {
    margin-top: .75rem;
    border: 1px solid var(--sf-color-border, #e2e8f0);
    border-radius: var(--sf-radius-lg, .75rem);
    background: var(--sf-color-bg-subtle, #f8fafc);
    overflow: hidden;
}
.sf-envio-zonas__sum {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .6rem .75rem;
    cursor: pointer;
    list-style: none;
    font-size: .8rem;
    font-weight: 700;
    color: var(--sf-color-text, #0f172a);
}
.sf-envio-zonas__sum::-webkit-details-marker { display: none; }
.sf-envio-zonas__chev {
    margin-left: auto;
    font-size: .7rem;
    color: var(--sf-color-text-muted, #64748b);
    transition: transform .15s ease;
}
.sf-envio-zonas[open] .sf-envio-zonas__chev { transform: rotate(180deg); }
.sf-envio-zonas__body { padding: 0 .75rem .75rem; }
.sf-envio-zonas__body .sf-table { font-size: .78rem; }
.sf-envio-zonas__ciudades {
    font-size: .7rem;
    font-weight: 400;
    color: var(--sf-color-text-muted, #64748b);
    margin-top: .1rem;
}
.sf-envio-zonas__na {
    font-size: .72rem;
    color: var(--sf-color-text-muted, #64748b);
}
.sf-envio-zonas__nota {
    margin-top: .5rem;
    font-size: .72rem;
    line-height: 1.5;
    color: var(--sf-color-text-muted, #64748b);
}

/* `.sf-note` / `.sf-state-disc` viven en `_notes.css` (IT265) — el
 * app-shell tambien los necesita y este archivo solo lo carga el
 * storefront. Los dos shells linkean ese archivo; aca no se re-declaran.
 */

/* ============================================================
 * RAIL DE PROGRESO — `.sf-rail` (IT263, S25/S29)
 * ------------------------------------------------------------
 * Horizontal en desktop, TIMELINE VERTICAL en mobile (<640px):
 * cinco labels en fila en un celular quedan en 2 letras por
 * columna. Mismo markup, sin duplicar partial.
 * ============================================================ */
.sf-rail {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    margin: var(--sf-space-6) 0 var(--sf-space-2);
    padding: 0;
    list-style: none;
}
.sf-rail__step { position: relative; min-width: 0; text-align: center; }
.sf-rail__step::before {
    content: "";
    position: absolute;
    top: 19px;
    right: 50%;
    width: 100%;
    height: 2px;
    background: var(--sf-color-border);
    z-index: 0;
}
.sf-rail__step:first-child::before { display: none; }
.sf-rail__step--done::before,
.sf-rail__step--current::before { background: var(--sf-color-primary); }

.sf-rail__dot {
    position: relative;
    z-index: 1;
    width: 40px;
    height: 40px;
    margin: 0 auto;
    display: grid;
    place-items: center;
    font-size: .9rem;
    border-radius: var(--sf-radius-full);
    background: var(--sf-color-bg-elevated);
    border: 2px solid var(--sf-color-border);
    color: var(--sf-color-text-subtle);
}
.sf-rail__step--done .sf-rail__dot,
.sf-rail__step--current .sf-rail__dot {
    background: var(--sf-color-primary);
    border-color: var(--sf-color-primary);
    color: var(--sf-color-primary-fg);
}
.sf-rail__step--current .sf-rail__dot {
    box-shadow: 0 0 0 5px color-mix(in srgb, var(--sf-color-primary) 22%, transparent);
}
.sf-rail__label {
    margin-top: var(--sf-space-2);
    padding: 0 .25rem;
    font-size: var(--sf-font-caption);
    line-height: var(--sf-leading-snug);
    color: var(--sf-color-text-muted);
}
.sf-rail__step--done .sf-rail__label,
.sf-rail__step--current .sf-rail__label {
    color: var(--sf-color-text);
    font-weight: 600;
}
.sf-rail__now {
    display: inline-block;
    margin-top: .3rem;
    font-size: var(--sf-font-overline);
    font-weight: 800;
    letter-spacing: var(--sf-tracking-wider);
    text-transform: uppercase;
    color: color-mix(in srgb, var(--sf-color-primary) 50%, var(--sf-color-text));
}

/* «Esta pagina se actualiza sola» — la promesa de que no hay que
 * recargar. Discreta a proposito: es una nota al pie del estado, no un
 * aviso. Se dibuja solo mientras el pedido puede moverse. */
.sf-live-hint {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    margin-left: .5rem;
    padding-left: .55rem;
    border-left: 1px solid var(--sf-color-border);
    color: var(--sf-color-text-muted);
}

/* La hora real del hito y su dato («2 de 3 listos»). Tono secundario a
 * proposito: el rail se lee primero por sus etiquetas; la hora es la
 * confirmacion de que ESO ya paso, y a que hora. */
.sf-rail__meta {
    display: block;
    margin-top: .2rem;
    font-size: var(--sf-font-caption);
    font-variant-numeric: tabular-nums;
    color: var(--sf-color-text-muted);
}

@media (max-width: 640px) {
    .sf-rail { grid-auto-flow: row; grid-auto-columns: auto; }
    .sf-rail__step {
        display: grid;
        grid-template-columns: 40px 1fr;
        align-items: center;
        gap: var(--sf-space-3);
        padding: var(--sf-space-1) 0;
        text-align: left;
    }
    .sf-rail__step::before {
        top: auto;
        bottom: 50%;
        right: auto;
        left: 19px;
        width: 2px;
        height: 100%;
    }
    .sf-rail__body {
        display: flex;
        flex-wrap: wrap;
        align-items: baseline;
        gap: .5rem;
    }
    .sf-rail__label { margin-top: 0; padding: 0; font-size: var(--sf-font-body-sm); }
    .sf-rail__now { margin: 0; }
    .sf-rail__meta { margin: 0; }
}

/* ============================================================
 * CODIGO DESTACADO — `.sf-code` (IT263)
 * Un dato que el comprador tiene que LEER EN VOZ ALTA o mostrar
 * en el mostrador (codigo de retiro BOPIS, referencia de pago).
 * ============================================================ */
.sf-code {
    text-align: center;
    padding: var(--sf-space-4);
    border-radius: var(--sf-radius-lg);
    background: color-mix(in srgb, var(--sf-color-primary) 9%, var(--sf-color-bg-elevated));
    border: 1px dashed color-mix(in srgb, var(--sf-color-primary) 45%, var(--sf-color-border));
}
.sf-code__value {
    font-family: var(--sf-font-mono);
    font-size: clamp(1.65rem, 6vw, 2.1rem);
    font-weight: 800;
    letter-spacing: .3em;
    /* El tracking del ULTIMO caracter empuja el bloque a la izquierda;
       el indent lo devuelve al centro optico. */
    text-indent: .3em;
    line-height: 1.2;
    color: color-mix(in srgb, var(--sf-color-primary) 55%, var(--sf-color-text));
}

/* ============================================================
 * LISTA DE DATOS — `.sf-datalist` (IT263)
 * Pares etiqueta/valor (datos bancarios, direccion de entrega).
 * Colapsa a una columna en mobile.
 * ============================================================ */
.sf-datalist { margin: 0; display: grid; gap: .45rem; }
.sf-datalist__row {
    display: grid;
    grid-template-columns: 6.5rem 1fr;
    gap: var(--sf-space-2);
    align-items: baseline;
}
.sf-datalist__key {
    font-size: var(--sf-font-caption);
    text-transform: uppercase;
    letter-spacing: var(--sf-tracking-wide);
    color: var(--sf-color-text-muted);
}
.sf-datalist__val {
    margin: 0;
    font-size: var(--sf-font-body-sm);
    font-weight: 600;
    color: var(--sf-color-text);
    overflow-wrap: anywhere;
}
@media (max-width: 480px) {
    .sf-datalist__row { grid-template-columns: 1fr; gap: 0; }
}

/* ============================================================
 * PANEL DE CONTENIDO — `.sf-panel` (IT263, S29.1)
 * ------------------------------------------------------------
 * Superficie canonica de una seccion del storefront publico.
 * La DENSIDAD (padding, radio, sombra, separacion entre paneles)
 * vive aca y en ningun otro lado: `_components.css` se carga
 * DESPUES del bundle Tailwind, asi que un `p-5` por template no
 * la puede pisar — y esa es la idea (S29.1, densidad kernel-owned).
 *
 * Se diferencia de `.sf-card-elevated`, que es la tarjeta de un
 * ITEM clickeable (levanta en hover): un panel de contenido no
 * se mueve cuando le pasas el mouse por encima.
 * ============================================================ */
.sf-panel {
    background: var(--sf-color-bg);
    border: 1px solid var(--sf-color-border);
    border-radius: var(--sf-radius-xl);
    padding: var(--sf-space-5);
    box-shadow: var(--sf-shadow-xs);
}
@media (min-width: 640px) {
    .sf-panel { padding: var(--sf-space-6); }
}
.sf-panel + .sf-panel { margin-top: var(--sf-space-4); }
.sf-panel__title {
    display: flex;
    align-items: center;
    gap: var(--sf-space-2);
    margin: 0 0 var(--sf-space-3);
    font-size: var(--sf-font-caption);
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: var(--sf-tracking-wider);
    color: var(--sf-color-text-muted);
}

/* Cierre de una tabla kernel: la fila del TOTAL. Sin esto cada pagina se
   inventaba un `<tr>` con `font-bold` y un borde distinto. */
.sf-table tfoot td {
    padding: .65rem .75rem;
    font-size: var(--sf-font-body-sm);
    font-weight: 800;
    color: var(--sf-color-text);
    border-top: 2px solid var(--sf-color-border);
}

/* Columna lateral que acompana al scroll (resumen de compra del checkout y
   de la pagina de seguimiento). Solo desde lg: en mobile el aside va debajo
   y pegarlo taparia el contenido. Tailwind no tiene `lg:top-24` compilado en
   el bundle, asi que el offset vive aca y no como utilidad fantasma. */
@media (min-width: 1024px) {
    .sf-sticky-aside {
        position: sticky;
        top: 5.5rem;
    }
}

/* ═══════════════════════════════════════════════════════════════════════
 * PORTADA SIN FOTOS — miniatura, ficha compacta y tira de categoria (IT265)
 * ═══════════════════════════════════════════════════════════════════════
 * La portada estaba diseñada alrededor de fotos que no existen: cada
 * tarjeta de producto reservaba ~370px de alto a una imagen que nunca
 * llega, y cada categoria era un degradado de 570px con la inicial
 * encima. Una tienda recien publicada — que es TODA tienda el primer dia
 * — se veia como una pagina rota.
 *
 * La miniatura tipografica ocupa el lugar de la foto y se ve terminada
 * sin ella; cuando la foto exista, entra en el MISMO cuadrado y no hay
 * que rediseñar nada.
 *
 * El tono sale de `--sf-viz-1..8` (paleta categorica del kernel, validada
 * para daltonismo, con set propio en dark) via el filtro `sf_tone_slot`,
 * que mapea el nombre a un slot estable. Como CLASE y no como `style=`:
 * la CSP de produccion bloquea el atributo.
 * ═════════════════════════════════════════════════════════════════════ */

.sf-tile {
    display: grid;
    place-items: center;
    flex: none;
    font-weight: 800;
    line-height: 1;
    letter-spacing: -0.02em;
    border-radius: var(--sf-radius-lg);
    border: 1px solid transparent;
    overflow: hidden;
    background: var(--sf-color-bg-subtle);
    color: var(--sf-color-text-muted);
}
.sf-tile img { width: 100%; height: 100%; object-fit: cover; }
/* El tinte se mezcla contra la SUPERFICIE, no un hex fijo: asi sigue al
   tema del visitante y tambien a la paleta de fondo que eligio el dueño. */
.sf-tile--1 { --sf-tile-c: var(--sf-viz-1); }
.sf-tile--2 { --sf-tile-c: var(--sf-viz-2); }
.sf-tile--3 { --sf-tile-c: var(--sf-viz-3); }
.sf-tile--4 { --sf-tile-c: var(--sf-viz-4); }
.sf-tile--5 { --sf-tile-c: var(--sf-viz-5); }
.sf-tile--6 { --sf-tile-c: var(--sf-viz-6); }
.sf-tile--7 { --sf-tile-c: var(--sf-viz-7); }
.sf-tile--8 { --sf-tile-c: var(--sf-viz-8); }
.sf-tile[class*="sf-tile--"] {
    background: color-mix(in srgb, var(--sf-tile-c) 13%, var(--sf-color-bg-elevated));
    border-color: color-mix(in srgb, var(--sf-tile-c) 30%, transparent);
    /* 55% y no mas: mezclado contra la TINTA, no el acento puro. Medido
       sobre los 8 slots en los dos temas, el peor caso es el ambar
       (`--sf-viz-4`), que al 62% daba 4.00:1 en tema claro — por debajo
       de AA. Al 55% el peor sube a 4.72:1 (claro) y 5.35:1 (oscuro).
       La letra pierde un poco de saturacion; el FONDO de la miniatura
       sigue llevando el color de la categoria, que es donde se lee.
       Guard: test_portada_sin_fotos.py::MiniaturaContrasteTest */
    color: color-mix(in srgb, var(--sf-tile-c) 55%, var(--sf-color-text));
}
.sf-tile--sm { width: 3.25rem; height: 3.25rem; font-size: 1.15rem; }
.sf-tile--md { width: 2.75rem; height: 2.75rem; font-size: 1rem; }



/* ═══════════════════════════════════════════════════════════════════════
 * CARD DE COMPRA — `.sf-shopcard` (IT265, iteracion 2)
 * ═══════════════════════════════════════════════════════════════════════
 * La primera pasada dejo la home con fichas-lista: densas, pero se leian
 * como un panel de administracion, no como una tienda. El pedido del
 * dueño fue explicito: cards de ecommerce moderno.
 *
 * Lo que define a una card de ecommerce moderna no es la estetica, es que
 * SE PUEDE COMPRAR DESDE AHI: agregar al carrito sin entrar al producto,
 * deseados a un toque, precio con su tachado cuando hay descuento. La
 * card anterior obligaba a entrar al detalle para todo.
 *
 * Sin fotos sigue valiendo la regla de la iteracion 1: el arte es una
 * miniatura tipografica teñida (`.sf-tile--N`) que ALOJA la foto cuando
 * exista, en el mismo marco. Sin estrellas de reseña: la home no tiene
 * rating anotado y dibujar prueba social inventada es un fallback (S28.4).
 * ═════════════════════════════════════════════════════════════════════ */

/* El tile en modo lienzo: llena el ancho de la card con proporcion fija.
   aspect-ratio y no alto fijo -> cero CLS y sirve igual a foto y monograma. */
.sf-tile--fill {
    width: 100%;
    height: auto;
    aspect-ratio: 4 / 3;
    font-size: clamp(1.8rem, 4cqw, 2.6rem);
    border-radius: 0;
    border: 0;
}

.sf-shopcard {
    position: relative;
    display: flex;
    flex-direction: column;
    border: 1px solid var(--sf-color-border);
    border-radius: var(--sf-radius-xl);
    background: var(--sf-color-bg-elevated);
    overflow: hidden;
    transition: border-color .18s ease, transform .18s ease, box-shadow .18s ease;
}
.sf-shopcard:hover {
    border-color: var(--sf-color-primary);
    transform: translateY(-2px);
    box-shadow: 0 12px 28px -14px color-mix(in srgb, var(--sf-color-primary) 35%, transparent);
}
.sf-shopcard.is-out { opacity: .68; }
.sf-shopcard.is-out:hover { transform: none; box-shadow: none; }

/* El area clickeable al producto es tile+texto; el boton de carrito y el
   corazon quedan FUERA del link (un <a> no puede contener un <form>). */
.sf-shopcard__link {
    display: block;
    text-decoration: none;
    color: inherit;
}
.sf-shopcard__link:focus-visible { outline: 2px solid var(--sf-color-primary); outline-offset: -2px; }

.sf-shopcard__flag {
    position: absolute;
    top: .6rem; left: .6rem;
    z-index: 2;
}
.sf-shopcard__wish {
    position: absolute;
    top: .5rem; right: .5rem;
    z-index: 2;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem; height: 2rem;
    border-radius: 999px;
    border: 1px solid var(--sf-color-border);
    background: color-mix(in srgb, var(--sf-color-bg-elevated) 88%, transparent);
    backdrop-filter: blur(4px);
    color: var(--sf-color-text-muted);
    cursor: pointer;
    transition: color .15s ease, transform .15s ease;
}
.sf-shopcard__wish:hover { color: var(--sf-color-danger); transform: scale(1.08); }
.sf-shopcard__wish:focus-visible { outline: 2px solid var(--sf-color-primary); outline-offset: 2px; }

.sf-shopcard__body { display: flex; flex-direction: column; gap: .15rem; padding: .7rem .8rem .25rem; }
.sf-shopcard__cat {
    font-size: .62rem;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--sf-color-text-muted);
}
.sf-shopcard__name {
    font-size: .9rem;
    font-weight: 650;
    letter-spacing: -.01em;
    line-height: 1.3;
    color: var(--sf-color-text);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    min-height: 2.34em; /* 2 lineas SIEMPRE: los botones quedan alineados entre cards */
}
.sf-shopcard__prices { display: flex; align-items: baseline; gap: .45rem; flex-wrap: wrap; }
.sf-shopcard__price {
    font-size: 1.02rem;
    font-weight: 750;
    font-variant-numeric: tabular-nums;
    color: var(--sf-color-text);
}
.sf-shopcard__was {
    font-size: .74rem;
    text-decoration: line-through;
    color: var(--sf-color-text-muted);
}

.sf-shopcard__foot { padding: .55rem .8rem .8rem; margin-top: auto; }
.sf-shopcard__add {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: .4rem;
    width: 100%;
    padding: .5rem .75rem;
    border-radius: var(--sf-radius-lg);
    border: 1px solid color-mix(in srgb, var(--sf-color-primary) 45%, var(--sf-color-border));
    background: color-mix(in srgb, var(--sf-color-primary) 10%, var(--sf-color-bg-elevated));
    color: color-mix(in srgb, var(--sf-color-primary) 72%, var(--sf-color-text));
    font-size: .8rem;
    font-weight: 700;
    cursor: pointer;
    transition: background .15s ease, color .15s ease;
}
.sf-shopcard__add:hover {
    background: var(--sf-color-primary);
    color: var(--sf-color-primary-fg, #fff);
}
.sf-shopcard__add:focus-visible { outline: 2px solid var(--sf-color-primary); outline-offset: 2px; }
/* Sin stock el boton NO desaparece (la grilla saltaria): se declara. */
.sf-shopcard__add--off {
    border-color: var(--sf-color-border);
    background: var(--sf-color-bg-subtle);
    color: var(--sf-color-text-muted);
    cursor: not-allowed;
}
.sf-shopcard__add--off:hover { background: var(--sf-color-bg-subtle); color: var(--sf-color-text-muted); }

.sf-grid-shop {
    display: grid;
    gap: .9rem;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 11.5rem), 1fr));
}

/* ── Card de categoria — `.sf-catcard` ──────────────────────────────── */
.sf-catcard {
    display: flex;
    flex-direction: column;
    border: 1px solid var(--sf-color-border);
    border-radius: var(--sf-radius-xl);
    background: var(--sf-color-bg-elevated);
    overflow: hidden;
    text-decoration: none;
    color: inherit;
    transition: border-color .18s ease, transform .18s ease, box-shadow .18s ease;
}
.sf-catcard:hover {
    border-color: var(--sf-color-primary);
    transform: translateY(-2px);
    box-shadow: 0 12px 28px -14px color-mix(in srgb, var(--sf-color-primary) 35%, transparent);
}
.sf-catcard:focus-visible { outline: 2px solid var(--sf-color-primary); outline-offset: 2px; }
.sf-catcard__banner {
    position: relative;
    aspect-ratio: 21 / 9;
    font-size: clamp(1.6rem, 3cqw, 2.2rem);
    border-radius: 0;
    border: 0;
    width: 100%;
    height: auto;
}
.sf-catcard__count {
    position: absolute;
    top: .55rem; right: .6rem;
    font-size: .68rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    padding: .18rem .55rem;
    border-radius: 999px;
    background: color-mix(in srgb, var(--sf-color-bg-elevated) 82%, transparent);
    border: 1px solid var(--sf-color-border);
    color: var(--sf-color-text);
    backdrop-filter: blur(4px);
}
.sf-catcard__body { padding: .75rem .85rem .9rem; }
.sf-catcard__head { display: flex; align-items: center; gap: .5rem; }
.sf-catcard__name {
    margin: 0;
    font-size: 1rem;
    font-weight: 680;
    letter-spacing: -.012em;
    color: var(--sf-color-text);
}
.sf-catcard__go { margin-left: auto; color: var(--sf-color-text-muted); transition: transform .15s ease, color .15s ease; }
.sf-catcard:hover .sf-catcard__go { transform: translateX(3px); color: var(--sf-color-primary); }
.sf-catcard__chips { display: flex; flex-wrap: wrap; gap: .3rem; margin-top: .55rem; }
.sf-catcard__chip {
    max-width: 100%;
    padding: .18rem .5rem;
    border-radius: 999px;
    border: 1px solid var(--sf-color-border);
    background: var(--sf-color-bg-subtle);
    font-size: .7rem;
    color: var(--sf-color-text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.sf-grid-catcard {
    /* Es un <ul>: el reset va aca y no en un style= inline (CSP). */
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: .9rem;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 15rem), 1fr));
}

/* ═══════════════════════════════════════════════════════════════════════
 * FOOTER DE LA TIENDA — `.sf-footer` (IT265)
 * ═══════════════════════════════════════════════════════════════════════
 * El pie era `bg-slate-900 dark:bg-black`: el mismo gris-negro generico
 * para todas las tiendas. Una tienda «rosa» y una «cielo» terminaban en
 * el mismo pie anonimo. La inversion (pie oscuro sobre pagina clara) es
 * una decision correcta de diseño y SE MANTIENE — lo que cambia es que
 * el negro ahora carga la TEMPERATURA de la paleta del dueño: se mezcla
 * un poco de la superficie de la paleta sobre un casi-negro, asi el pie
 * de una tienda calida es un negro calido y el de una fria, uno frio.
 * ═════════════════════════════════════════════════════════════════════ */
.sf-footer {
    /* Luz: inversion deliberada, teñida por la paleta (10% alcanza para
       la temperatura sin aclarar el fondo — el texto claro sigue >12:1). */
    background: color-mix(in srgb, var(--sf-pal-surface, #64748b) 10%, #090c11);
    border-top: 1px solid color-mix(in srgb, var(--sf-color-primary) 24%, transparent);
}
.dark .sf-footer {
    /* Oscuro: un paso MAS profundo que el fondo de pagina de la paleta,
       para que el pie siga leyendose como cierre y no como mas pagina. */
    background: color-mix(in srgb, var(--sf-pal-bg, #020617) 55%, black);
}
/* La tinta del pie NO sigue al tema (design-review FINDING-004-kernel):
   el pie es inversion deliberada — siempre oscuro — pero sf-ink-muted
   resuelve a --sf-color-text-muted, que en modo CLARO es slate oscuro:
   links y tagline invisibles sobre el fondo negro. Tinta fija para
   superficie dark-by-design (#94a3b8 ≈ 7:1 sobre #090c11, AA). */
.sf-footer.sf-ink-muted,
.sf-footer .sf-ink-muted {
    color: #94a3b8;
}
/* auto-fit y no un grid-cols-N fijo: las columnas del pie son
   CONDICIONALES (contacto y redes solo existen si el dueño cargo datos).
   Con columnas fijas, cada ausencia dejaba un hueco en la fila. */
.sf-footer__grid {
    display: grid;
    gap: 2rem;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 11rem), 1fr));
}
.sf-footer__brand { min-width: 0; }
@media (min-width: 1024px) { .sf-footer__brand { grid-column: span 2; max-width: 26rem; } }
.sf-footer__social {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 2.25rem;
    width: 2.25rem;
    border-radius: var(--sf-radius-md, 8px);
    background: color-mix(in srgb, var(--sf-pal-surface, #94a3b8) 14%, transparent);
    color: rgb(255 255 255 / .72);
    transition: background .15s ease, color .15s ease;
}
.sf-footer__social:hover {
    background: color-mix(in srgb, var(--sf-color-primary) 40%, transparent);
    color: #fff;
}

/* Badge del carrito en cero — kernel-global (IT239): cart_badge.js aplica
   esta clase al vaciar el carrito; antes solo la definia pdp_v2.css y en
   el resto de las paginas el "0" quedaba visible. */
.sf-minicart__badge--empty {
  display: none;
}

/* T-14: tailwind.css compila `.sf-btn-primary` con `text-white` fijo; la
   tinta del botón primario la decide el token (luminancia del color de
   marca). Esta hoja carga después de tailwind, así que gana por orden. */
.sf-btn-primary {
  color: var(--sf-color-primary-fg);
}

/* ══════════════════════════════════════════════════════════════════════════
 * Ancho del shell de la tienda en monitores grandes (S29.3)
 * ──────────────────────────────────────────────────────────────────────────
 * Scope `[data-sf-palette]`: ese atributo lo estampa SOLO el <html> del
 * storefront (kernel y las 15 carpetas independientes). El app-shell del
 * dashboard no lo tiene, así que estas reglas no lo alcanzan aunque
 * `_components.css` llegue a los dos shells vía styles.css.
 *
 * `.max-w-7xl` es el contenedor de página de facto del storefront: ~100
 * usos entre el kernel y los temas. Cambiarlo template por template sería
 * un sed sobre N archivos que el próximo tema reintroduce. Acá se ata UNA
 * vez al token: el markup existente hereda sin tocarse, y el markup nuevo
 * declara `.sf-shell-container`, que es el nombre honesto de lo que hace.
 *
 * Especificidad (0,2,0) > la utilidad de Tailwind (0,1,0): gana sin
 * `!important` y sin depender del orden de carga.
 * ════════════════════════════════════════════════════════════════════════ */

[data-sf-palette] .sf-container-wide,
[data-sf-palette] .sf-shell-container {
  width: 100%;
  margin-inline: auto;
}

[data-sf-palette] .sf-container-wide,
[data-sf-palette] .sf-shell-container,
[data-sf-palette] .max-w-7xl {
  max-width: var(--sf-shell-max);
}

/* Grilla de tarjetas que SUMA COLUMNAS en vez de inflar las tarjetas.
 * Sin esto, ensanchar el contenedor deja las mismas 4 cards de producto
 * estiradas a 400px+ — el mismo defecto que S29.2 ya corrigió en los KPIs
 * del dashboard, del otro lado del escalón.
 *
 * Activa SOLO desde 1600px: por debajo manda el ritmo declarado en el
 * markup (`grid-cols-2 md:grid-cols-3 lg:grid-cols-4`), que en notebook y
 * en mobile ya está bien. El mínimo por tarjeta es un token: cada grilla lo
 * ajusta a lo que muestra. */
@media (min-width: 1600px) {
  [data-sf-palette] .sf-cardgrid {
    grid-template-columns: repeat(auto-fill, minmax(var(--sf-cardgrid-min), 1fr));
  }
}

/* Ritmo de columnas de las dos grillas de la home (categorías y productos).
 * Estaba duplicado byte por byte en los 11 `home.html` del storefront: cada
 * carpeta independiente se llevó su copia al nacer, así que el ritmo para
 * 4K se mantenía once veces a mano y los temas que escribieron su propia
 * home (restaurante, puntoventa) lo perdieron — sus grillas quedaron
 * clavadas en 4 y 6 columnas a cualquier ancho. Acá es una sola. */
[data-sf-palette] .sf-grid-cat {
  display: grid;
  gap: 0.75rem;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
@media (min-width: 640px)  { [data-sf-palette] .sf-grid-cat { gap: 1rem; grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1024px) { [data-sf-palette] .sf-grid-cat { gap: 1.25rem; grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (min-width: 1920px) { [data-sf-palette] .sf-grid-cat { grid-template-columns: repeat(6, minmax(0, 1fr)); } }
@media (min-width: 3840px) { [data-sf-palette] .sf-grid-cat { grid-template-columns: repeat(8, minmax(0, 1fr)); gap: 2rem; } }

[data-sf-palette] .sf-grid-product {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
@media (min-width: 640px)  { [data-sf-palette] .sf-grid-product { gap: 1.5rem; grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1024px) { [data-sf-palette] .sf-grid-product { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (min-width: 1280px) { [data-sf-palette] .sf-grid-product { grid-template-columns: repeat(5, minmax(0, 1fr)); } }
@media (min-width: 1920px) { [data-sf-palette] .sf-grid-product { grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 1.75rem; } }
@media (min-width: 3840px) { [data-sf-palette] .sf-grid-product { grid-template-columns: repeat(8, minmax(0, 1fr)); gap: 2.5rem; } }

/* ══════════════════════════════════════════════════════════════════════════
 * El header de la tienda: compacto o completo, un solo breakpoint
 * ──────────────────────────────────────────────────────────────────────────
 * El switch vivía en `md` (768px) y ahí NO entra: la nav completa (359px con
 * reservas + WhatsApp), el buscador (224px) y las acciones (243px) piden
 * ~870px sobre los 720 disponibles, así que la barra desbordaba por la
 * derecha después de comprimir la marca hasta 8px. A 1024px entran los
 * cuatro bloques.
 *
 * Por qué clases kernel y no `lg:flex`/`lg:hidden`: el bundle de Tailwind de
 * este repo no se recompila, y `lg:hidden` no existe en él — usarla dejaba el
 * hamburguesa visible en TODA pantalla, sin error y sin aviso. Y porque el
 * breakpoint tiene que tener UN dueño: antes estaba a la vez en el markup
 * (`md:flex`) y en `search.css` (`@media 768px`), dos mecanismos para lo
 * mismo que se desincronizan sin que nada lo note.
 *
 * `.sf-only-wide`: se ve solo desde 1024px (nav y buscador de la barra).
 * `.sf-only-compact`: se ve hasta 1023px (hamburguesa, menú desplegable,
 * buscador de fila completa, enlace directo al carrito).
 *
 * El nombre dice QUÉ hacen, no dónde se usan: nacieron para el header y el
 * mini-carrito de la ficha de producto necesitó el mismo corte. Un nombre que
 * describe el lugar es un patrón que el siguiente consumidor no encuentra.
 * ════════════════════════════════════════════════════════════════════════ */

[data-sf-palette] .sf-only-wide {
  display: none;
}

@media (min-width: 1024px) {
  [data-sf-palette] .sf-only-wide {
    display: flex;
  }
  [data-sf-palette] .sf-only-compact {
    display: none;
  }
}

/* ============================================================
   MINI-CART FLOTANTE (Sprint UX-5 §3.7)
   Kernel-owned: vive aca y no en `pdp_v2.css` porque el carrito flotante se
   usa en la ficha Y en el catalogo. El breakpoint de posicion sigue al del
   shell (1024px), para que «compacto» signifique lo mismo en todas partes.
   ============================================================ */
.sf-minicart {
  position: fixed;
  top: 80px;
  right: var(--sf-space-4);
  z-index: var(--sf-z-sticky);
}
@media (max-width: 1023px) {
  .sf-minicart {
    top: auto;
    bottom: 5rem; /* arriba del sticky add-to-cart */
    right: var(--sf-space-3);
  }
}
.sf-minicart__toggle {
  position: relative;
  /* Es un `<a>`, no un `<button>`: sin JS navega al carrito. */
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  background: var(--sf-color-primary);
  color: var(--sf-color-primary-fg);
  border: 0;
  border-radius: var(--sf-radius-full);
  cursor: pointer;
  box-shadow: var(--sf-shadow-lg);
  transition: transform var(--sf-motion-fast) var(--sf-ease-out),
              box-shadow var(--sf-motion-fast) var(--sf-ease-out);
}
.sf-minicart__toggle:hover {
  transform: translateY(-2px);
  box-shadow: var(--sf-shadow-xl);
}
.sf-minicart__badge {
  position: absolute;
  top: -6px;
  right: -6px;
  background: var(--sf-color-danger);
  color: white;
  border-radius: var(--sf-radius-full);
  padding: 2px 6px;
  font-size: var(--sf-font-overline);
  font-weight: 700;
  min-width: 18px;
  text-align: center;
  box-shadow: 0 2px 4px rgb(0 0 0 / 0.2);
}
/* Carrito vacio: ocultar el badge (no mostrar un "0" flotante). */
.sf-minicart__badge--empty {
  display: none;
}
.sf-minicart__panel {
  position: absolute;
  top: 100%;
  right: 0;
  margin-top: var(--sf-space-2);
  background: var(--sf-color-bg);
  border: 1px solid var(--sf-color-border);
  border-radius: var(--sf-radius-lg);
  box-shadow: var(--sf-shadow-xl);
  width: 340px;
  max-width: calc(100vw - var(--sf-space-8));
  max-height: 480px;
  overflow-y: auto;
}
.sf-minicart__panel:empty {
  display: none;
}

.sf-minicart-panel__inner {
  display: flex;
  flex-direction: column;
}
.sf-minicart-panel__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--sf-space-3) var(--sf-space-4);
  border-bottom: 1px solid var(--sf-color-border);
}
.sf-minicart-panel__list {
  list-style: none;
  padding: 0;
  margin: 0;
  max-height: 280px;
  overflow-y: auto;
}
.sf-minicart-panel__row {
  display: flex;
  gap: var(--sf-space-3);
  padding: var(--sf-space-3) var(--sf-space-4);
  border-bottom: 1px solid var(--sf-color-border);
  align-items: center;
}
.sf-minicart-panel__row:last-child {
  border-bottom: 0;
}
.sf-minicart-panel__img {
  width: 48px;
  height: 48px;
  object-fit: cover;
  border-radius: var(--sf-radius-md);
  background: var(--sf-color-bg-elevated);
  flex: 0 0 auto;
  display: block;
}
.sf-minicart-panel__img--ph {
  display: grid;
  place-items: center;
  color: var(--sf-color-text-muted);
}
.sf-minicart-panel__data {
  flex: 1;
  min-width: 0;
}
.sf-minicart-panel__name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 600;
}
.sf-minicart-panel__line {
  font-weight: 700;
  color: var(--sf-color-text);
  font-size: var(--sf-font-body-sm);
}
.sf-minicart-panel__footer {
  padding: var(--sf-space-3) var(--sf-space-4);
  border-top: 1px solid var(--sf-color-border);
  background: var(--sf-color-bg-elevated);
  display: flex;
  flex-direction: column;
  gap: var(--sf-space-3);
}
.sf-minicart-panel__total {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
}
.sf-minicart-panel__actions {
  display: flex;
  gap: var(--sf-space-2);
}
.sf-minicart-panel__actions .sf-btn {
  flex: 1;
  justify-content: center;
}
.sf-minicart-panel__empty {
  padding: var(--sf-space-6) var(--sf-space-4);
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sf-space-3);
  color: var(--sf-color-text-muted);
}
.sf-minicart-panel__empty i {
  font-size: 2.5rem;
  color: var(--sf-color-text-muted);
}

/* ── storefront/css/_notes.css ── */
/* ═══════════════════════════════════════════════════════════════════════
 * `_notes.css` — nota de estado kernel, fuente UNICA para los dos shells
 * ═══════════════════════════════════════════════════════════════════════
 * Movido desde `_components.css` (IT265) por el mismo motivo que IT76
 * movio la tira de KPIs a `_kpi_strip.css`: `_components.css` lo carga
 * SOLO el storefront publico, y el app-shell tambien necesita la nota.
 * Sin este archivo, un dashboard que escribiera `.sf-note--danger`
 * renderizaba una fila sin fondo, sin borde y sin tono — la clase estaba
 * en el HTML y la regla no llegaba nunca (misma familia que IT263).
 *
 * Lo cargan `layouts/app_shell.html` y `storefront/base_storefront.html`.
 * NO duplicar las reglas en ninguno de los dos: una sola definicion.
 * ═════════════════════════════════════════════════════════════════════ */

/* ============================================================
 * NOTA DE ESTADO — `.sf-note` (IT263, S25/S28/S29)
 * ------------------------------------------------------------
 * El bloque "esto pasó / esto significa / esto sigue" estaba
 * escrito a mano con utilidades Tailwind en la pagina de
 * seguimiento, en el checkout, en payment_result y en los
 * paneles admin del storefront. Seis copias del mismo tile con
 * tonos distintos y — lo que rompio — pares `dark:` que NO
 * EXISTEN en el bundle compilado:
 *
 *     dark:bg-amber-500/10      -> 0 reglas en static/css/tailwind.css
 *     dark:border-amber-500/40  -> 0 reglas
 *
 * La clase estaba en el HTML, la regla no estaba en el CSS: en
 * dark quedaba el fondo crema de light con texto amber-300
 * encima (1.9:1). Y no se puede recompilar Tailwind — package.json
 * no esta en el working tree.
 *
 * Por eso el tono se resuelve ACA, con `color-mix()` sobre los
 * tokens `--sf-*`: el acento se mezcla contra la SUPERFICIE para
 * el fondo y contra la TINTA para el texto, asi que el pareo dark
 * sale solo (ambos lados del mix flipean con el tema) y ningun
 * consumidor puede volver a congelar un hex de light mode.
 * Guard: apps/core/ui/tests/test_no_phantom_tailwind_dark_storefront.py
 * ============================================================ */
.sf-note {
    --sf-note-accent: var(--sf-color-info);
    display: flex;
    align-items: flex-start;
    gap: var(--sf-space-3);
    padding: var(--sf-space-4);
    border-radius: var(--sf-radius-xl);
    border: 1px solid color-mix(in srgb, var(--sf-note-accent) 38%, var(--sf-color-border));
    background: color-mix(in srgb, var(--sf-note-accent) 10%, var(--sf-color-bg-elevated));
    color: var(--sf-color-text);
}
/* Disco de estado: el mismo tono del `.sf-note` pero como ancla visual de un
   encabezado (el estado del pedido, de un ticket, de una integracion). */
.sf-state-disc {
    --sf-note-accent: var(--sf-color-info);
    flex: none;
    display: grid;
    place-items: center;
    width: 3rem;
    height: 3rem;
    border-radius: var(--sf-radius-full);
    font-size: 1.2rem;
    background: color-mix(in srgb, var(--sf-note-accent) 16%, var(--sf-color-bg-elevated));
    border: 1px solid color-mix(in srgb, var(--sf-note-accent) 32%, var(--sf-color-border));
    color: color-mix(in srgb, var(--sf-note-accent) 70%, var(--sf-color-text));
}

/* Los tonos son compartidos: `.sf-note` y `.sf-state-disc` leen el mismo
   `--sf-note-accent`, asi que un tono nuevo se agrega en UN solo lugar.
   VAN DESPUES de las dos clases base: los modificadores tienen la MISMA
   especificidad (0,1,0) que la base, asi que solo ganan por orden. Con el
   bloque arriba, el `--sf-note-accent: info` de `.sf-state-disc` pisaba a
   `.sf-state-disc--warning` y el disco del pedido reservado salia azul. */
.sf-note--brand,   .sf-state-disc--brand   { --sf-note-accent: var(--sf-color-primary); }
.sf-note--success, .sf-state-disc--success { --sf-note-accent: var(--sf-color-success); }
.sf-note--warning, .sf-state-disc--warning { --sf-note-accent: var(--sf-color-warning); }
.sf-note--danger,  .sf-state-disc--danger  { --sf-note-accent: var(--sf-color-danger); }
.sf-note--info,    .sf-state-disc--info    { --sf-note-accent: var(--sf-color-info); }
.sf-note--neutral, .sf-state-disc--neutral { --sf-note-accent: var(--sf-color-text-muted); }

.sf-note__icon {
    flex: none;
    margin-top: .1rem;
    font-size: 1.05rem;
    line-height: 1.35;
    color: color-mix(in srgb, var(--sf-note-accent) 70%, var(--sf-color-text));
}
.sf-note__body { min-width: 0; flex: 1 1 auto; }
.sf-note__title {
    margin: 0;
    font-size: var(--sf-font-body-sm);
    font-weight: 700;
    line-height: var(--sf-leading-snug);
    /* Mezclado contra la TINTA, no contra el acento puro: en light da un
       ambar oscuro (5.1:1 sobre su fondo) y en dark un ambar claro (7.7:1).
       Un `color: var(--sf-color-warning)` fijo fallaria AA en light. */
    color: color-mix(in srgb, var(--sf-note-accent) 55%, var(--sf-color-text));
}
.sf-note__text {
    margin: .25rem 0 0;
    font-size: var(--sf-font-body-sm);
    line-height: var(--sf-leading-relaxed);
    color: var(--sf-color-text-muted);
}
.sf-note__text + .sf-note__text { margin-top: .4rem; }
.sf-note__next {
    display: block;
    margin-top: .5rem;
    font-size: var(--sf-font-caption);
    line-height: var(--sf-leading-normal);
    color: color-mix(in srgb, var(--sf-note-accent) 45%, var(--sf-color-text));
}
.sf-note__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sf-space-2);
    margin-top: var(--sf-space-3);
}

/* ── Variante fila de tablero (IT265) ────────────────────────────────────
   La nota nacio como bloque de pagina (checkout, seguimiento): padding
   generoso, titulo + parrafo. En un panel de "que revisar ahora" van 4-6
   apiladas y con ese padding la lista no entra sin scroll. Esto es
   densidad kernel-owned (S29.1): se declara UNA vez aca, no la "achica"
   cada vertical en su template. */
.sf-note--row {
    padding: 0.6rem 0.75rem;
    gap: 0.65rem;
    border-radius: var(--sf-radius-lg);
    align-items: center;
}
.sf-note--row .sf-note__icon { margin-top: 0; font-size: 0.95rem; }
.sf-note--row .sf-note__title { font-size: var(--sf-font-body-sm); }

/* Nota accionable: la fila ENTERA es el link. Una alerta que solo se puede
   mirar es la que hace inutil al panel — «4 CxC vencidas» sin camino a las
   CxC obliga a salir a buscarlas por el menu. */
a.sf-note {
    text-decoration: none;
    transition: transform 140ms ease, border-color 140ms ease, background 140ms ease;
}
a.sf-note:hover {
    transform: translateY(-1px);
    border-color: color-mix(in srgb, var(--sf-note-accent) 62%, var(--sf-color-border));
    background: color-mix(in srgb, var(--sf-note-accent) 16%, var(--sf-color-bg-elevated));
}
a.sf-note:focus-visible {
    outline: 2px solid var(--sf-note-accent);
    outline-offset: 2px;
}
.sf-note__go {
    flex: none;
    font-size: 0.75rem;
    opacity: 0.55;
    color: color-mix(in srgb, var(--sf-note-accent) 60%, var(--sf-color-text));
    transition: opacity 140ms ease, transform 140ms ease;
}
a.sf-note:hover .sf-note__go { opacity: 1; transform: translateX(2px); }

/* ── storefront/css/_palettes.css ── */
/* ═══════════════════════════════════════════════════════════════════════
 * `_palettes.css` — paletas de fondo de la tienda publica (IT265)
 * ═══════════════════════════════════════════════════════════════════════
 * El fondo de la tienda estaba clavado en el markup
 * (`bg-slate-50 dark:bg-slate-950` en el <body>) y las superficies en
 * `bg-white dark:bg-slate-900`, repetidas ~200 veces entre templates. El
 * dueño podia elegir sus dos colores de marca, pero no el color sobre el
 * que se apoya su tienda.
 *
 * COMO FUNCIONA. El slug elegido viaja en `data-sf-palette` del <html> y
 * acá se traduce a variables; despues un mapeo reescribe las clases
 * NEUTRAS de Tailwind (bg-white, bg-slate-50, border-slate-200 y sus
 * pares dark) dentro de ese scope. Es el mismo patron que usan las 26
 * skins del terminal POS (`pos_variant_themes.css`): reskin sin tocar
 * doscientos partials.
 *
 * QUE **NO** SE TOCA: los acentos de color (emerald de "agregar al
 * carrito", rose de descuento, amber de estrellas), las sombras, los
 * radios y el layout. Una paleta cambia la superficie, no el semaforo —
 * si el boton de comprar cambiara de color con cada paleta, el cliente
 * tendria que aprender de nuevo donde tocar.
 *
 * CADA PALETA DEFINE LOS DOS TEMAS. La tienda deja al visitante alternar
 * claro/oscuro (`localStorage sf-theme`), asi que una paleta que solo
 * exista en claro dejaria media tienda sin diseñar. Los pares estan
 * VERIFICADOS: ninguno baja de 4.5:1 entre texto y superficie, en
 * ninguno de los dos temas.
 * Guard: apps/commercial/storefront/tests/test_paletas_fondo.py
 *
 * `neutro` reproduce EXACTAMENTE los hex que hoy estan en el markup: es
 * el default y no puede cambiarle la cara a ninguna tienda existente.
 * ═════════════════════════════════════════════════════════════════════ */


/* ── Neutro — El gris azulado de siempre. ─────────────────────────── */
[data-sf-palette="neutro"] {
  --sf-pal-bg: #f8fafc;
  --sf-pal-surface: #ffffff;
  --sf-pal-sunk: #f1f5f9;
  --sf-pal-border: #e2e8f0;
  --sf-pal-border-soft: #f1f5f9;
  --sf-pal-text: #0f172a;
  --sf-pal-muted: #475569;
}
.dark[data-sf-palette="neutro"] {
  --sf-pal-bg: #020617;
  --sf-pal-surface: #0f172a;
  --sf-pal-sunk: #1e293b;
  --sf-pal-border: #334155;
  --sf-pal-border-soft: #1e293b;
  --sf-pal-text: #f1f5f9;
  --sf-pal-muted: #94a3b8;
}
.sf-swatch--neutro { --sf-swatch-bg: #f8fafc; --sf-swatch-surface: #ffffff; --sf-swatch-text: #0f172a; --sf-swatch-border: #e2e8f0; }
.dark .sf-swatch--neutro { --sf-swatch-bg: #020617; --sf-swatch-surface: #0f172a; --sf-swatch-text: #f1f5f9; --sf-swatch-border: #334155; }

/* ── Papel cálido — Blanco roto, como una hoja impresa. ─────────────────────────── */
[data-sf-palette="papel"] {
  --sf-pal-bg: #faf7f2;
  --sf-pal-surface: #fffdfa;
  --sf-pal-sunk: #f3ede4;
  --sf-pal-border: #e7ded1;
  --sf-pal-border-soft: #f3ede4;
  --sf-pal-text: #1c1917;
  --sf-pal-muted: #57534e;
}
.dark[data-sf-palette="papel"] {
  --sf-pal-bg: #12100e;
  --sf-pal-surface: #1c1916;
  --sf-pal-sunk: #292420;
  --sf-pal-border: #3a332e;
  --sf-pal-border-soft: #292420;
  --sf-pal-text: #f5f0e8;
  --sf-pal-muted: #a8a29e;
}
.sf-swatch--papel { --sf-swatch-bg: #faf7f2; --sf-swatch-surface: #fffdfa; --sf-swatch-text: #1c1917; --sf-swatch-border: #e7ded1; }
.dark .sf-swatch--papel { --sf-swatch-bg: #12100e; --sf-swatch-surface: #1c1916; --sf-swatch-text: #f5f0e8; --sf-swatch-border: #3a332e; }

/* ── Arena — Tierra clara, para decoración y oficio. ─────────────────────────── */
[data-sf-palette="arena"] {
  --sf-pal-bg: #f5f1e8;
  --sf-pal-surface: #fdfbf6;
  --sf-pal-sunk: #eee7d8;
  --sf-pal-border: #e0d7c3;
  --sf-pal-border-soft: #eee7d8;
  --sf-pal-text: #1c1a15;
  --sf-pal-muted: #5c5344;
}
.dark[data-sf-palette="arena"] {
  --sf-pal-bg: #14120d;
  --sf-pal-surface: #1f1c15;
  --sf-pal-sunk: #2b2720;
  --sf-pal-border: #3d372b;
  --sf-pal-border-soft: #2b2720;
  --sf-pal-text: #f2ece0;
  --sf-pal-muted: #a8a08d;
}
.sf-swatch--arena { --sf-swatch-bg: #f5f1e8; --sf-swatch-surface: #fdfbf6; --sf-swatch-text: #1c1a15; --sf-swatch-border: #e0d7c3; }
.dark .sf-swatch--arena { --sf-swatch-bg: #14120d; --sf-swatch-surface: #1f1c15; --sf-swatch-text: #f2ece0; --sf-swatch-border: #3d372b; }

/* ── Menta — Verde muy claro, fresco y limpio. ─────────────────────────── */
[data-sf-palette="menta"] {
  --sf-pal-bg: #f0fdf9;
  --sf-pal-surface: #ffffff;
  --sf-pal-sunk: #dcf7ef;
  --sf-pal-border: #c8ece1;
  --sf-pal-border-soft: #dcf7ef;
  --sf-pal-text: #0c1f1a;
  --sf-pal-muted: #3f5f56;
}
.dark[data-sf-palette="menta"] {
  --sf-pal-bg: #04211c;
  --sf-pal-surface: #0a2e27;
  --sf-pal-sunk: #123c33;
  --sf-pal-border: #1b4d42;
  --sf-pal-border-soft: #123c33;
  --sf-pal-text: #e6fbf5;
  --sf-pal-muted: #8fc4b7;
}
.sf-swatch--menta { --sf-swatch-bg: #f0fdf9; --sf-swatch-surface: #ffffff; --sf-swatch-text: #0c1f1a; --sf-swatch-border: #c8ece1; }
.dark .sf-swatch--menta { --sf-swatch-bg: #04211c; --sf-swatch-surface: #0a2e27; --sf-swatch-text: #e6fbf5; --sf-swatch-border: #1b4d42; }

/* ── Cielo — Azul claro, sobrio y confiable. ─────────────────────────── */
[data-sf-palette="cielo"] {
  --sf-pal-bg: #f0f7ff;
  --sf-pal-surface: #ffffff;
  --sf-pal-sunk: #e0efff;
  --sf-pal-border: #cfe3f7;
  --sf-pal-border-soft: #e0efff;
  --sf-pal-text: #0d1b2a;
  --sf-pal-muted: #40566e;
}
.dark[data-sf-palette="cielo"] {
  --sf-pal-bg: #061626;
  --sf-pal-surface: #0d2135;
  --sf-pal-sunk: #152e46;
  --sf-pal-border: #1f405e;
  --sf-pal-border-soft: #152e46;
  --sf-pal-text: #e8f2fc;
  --sf-pal-muted: #8fadc9;
}
.sf-swatch--cielo { --sf-swatch-bg: #f0f7ff; --sf-swatch-surface: #ffffff; --sf-swatch-text: #0d1b2a; --sf-swatch-border: #cfe3f7; }
.dark .sf-swatch--cielo { --sf-swatch-bg: #061626; --sf-swatch-surface: #0d2135; --sf-swatch-text: #e8f2fc; --sf-swatch-border: #1f405e; }

/* ── Lavanda — Violeta suave, para marcas de diseño. ─────────────────────────── */
[data-sf-palette="lavanda"] {
  --sf-pal-bg: #f7f5ff;
  --sf-pal-surface: #ffffff;
  --sf-pal-sunk: #ebe7fb;
  --sf-pal-border: #ddd7f4;
  --sf-pal-border-soft: #ebe7fb;
  --sf-pal-text: #17122b;
  --sf-pal-muted: #4d4470;
}
.dark[data-sf-palette="lavanda"] {
  --sf-pal-bg: #140f26;
  --sf-pal-surface: #1e1836;
  --sf-pal-sunk: #2a2249;
  --sf-pal-border: #392f61;
  --sf-pal-border-soft: #2a2249;
  --sf-pal-text: #f0ecfc;
  --sf-pal-muted: #a79cd0;
}
.sf-swatch--lavanda { --sf-swatch-bg: #f7f5ff; --sf-swatch-surface: #ffffff; --sf-swatch-text: #17122b; --sf-swatch-border: #ddd7f4; }
.dark .sf-swatch--lavanda { --sf-swatch-bg: #140f26; --sf-swatch-surface: #1e1836; --sf-swatch-text: #f0ecfc; --sf-swatch-border: #392f61; }

/* ── Rosa — Cálido y cercano, para moda y regalería. ─────────────────────────── */
[data-sf-palette="rosa"] {
  --sf-pal-bg: #fff5f6;
  --sf-pal-surface: #ffffff;
  --sf-pal-sunk: #ffe6e9;
  --sf-pal-border: #f7d5da;
  --sf-pal-border-soft: #ffe6e9;
  --sf-pal-text: #2b1116;
  --sf-pal-muted: #70414a;
}
.dark[data-sf-palette="rosa"] {
  --sf-pal-bg: #241014;
  --sf-pal-surface: #33191f;
  --sf-pal-sunk: #43222a;
  --sf-pal-border: #582d38;
  --sf-pal-border-soft: #43222a;
  --sf-pal-text: #fdeced;
  --sf-pal-muted: #d09aa4;
}
.sf-swatch--rosa { --sf-swatch-bg: #fff5f6; --sf-swatch-surface: #ffffff; --sf-swatch-text: #2b1116; --sf-swatch-border: #f7d5da; }
.dark .sf-swatch--rosa { --sf-swatch-bg: #241014; --sf-swatch-surface: #33191f; --sf-swatch-text: #fdeced; --sf-swatch-border: #582d38; }

/* ── Grafito — Gris neutro, sin tinte de color. ─────────────────────────── */
[data-sf-palette="grafito"] {
  --sf-pal-bg: #f1f2f4;
  --sf-pal-surface: #ffffff;
  --sf-pal-sunk: #e6e8eb;
  --sf-pal-border: #d8dade;
  --sf-pal-border-soft: #e6e8eb;
  --sf-pal-text: #121316;
  --sf-pal-muted: #4d5057;
}
.dark[data-sf-palette="grafito"] {
  --sf-pal-bg: #0a0a0b;
  --sf-pal-surface: #151618;
  --sf-pal-sunk: #212326;
  --sf-pal-border: #303337;
  --sf-pal-border-soft: #212326;
  --sf-pal-text: #f2f3f5;
  --sf-pal-muted: #9a9da3;
}
.sf-swatch--grafito { --sf-swatch-bg: #f1f2f4; --sf-swatch-surface: #ffffff; --sf-swatch-text: #121316; --sf-swatch-border: #d8dade; }
.dark .sf-swatch--grafito { --sf-swatch-bg: #0a0a0b; --sf-swatch-surface: #151618; --sf-swatch-text: #f2f3f5; --sf-swatch-border: #303337; }


/* ═════════════════════════════════════════════════════════════════════
 * MAPEO — las clases neutras de Tailwind toman la paleta
 * ═════════════════════════════════════════════════════════════════════
 * Scope `[data-sf-palette]`: sin el atributo (todo el back-office) estas
 * reglas no existen. Cada regla lleva ademas el prefijo de su tema para
 * no pisar al par contrario — la leccion de IT80 en las skins del POS:
 * sin eso queda un panel oscuro sobre pagina clara.
 * ═════════════════════════════════════════════════════════════════════ */

/* Fondo de pagina */
html[data-sf-palette]:not(.dark) body,
html[data-sf-palette]:not(.dark) .bg-slate-50 { background-color: var(--sf-pal-bg); }
html.dark[data-sf-palette] body,
html.dark[data-sf-palette] .dark\:bg-slate-950 { background-color: var(--sf-pal-bg); }

/* Superficies elevadas: cards, header, footer, modales */
html[data-sf-palette]:not(.dark) .bg-white { background-color: var(--sf-pal-surface); }
html.dark[data-sf-palette] .dark\:bg-slate-900 { background-color: var(--sf-pal-surface); }

/* Superficie hundida: filas alternas, chips, zonas de descanso */
html[data-sf-palette]:not(.dark) .bg-slate-100 { background-color: var(--sf-pal-sunk); }
html.dark[data-sf-palette] .dark\:bg-slate-800 { background-color: var(--sf-pal-sunk); }

/* Bordes */
html[data-sf-palette]:not(.dark) .border-slate-200 { border-color: var(--sf-pal-border); }
html.dark[data-sf-palette] .dark\:border-slate-700 { border-color: var(--sf-pal-border); }
/* El borde sutil es OTRO nivel, no el mismo: colapsarlos haria que
   `neutro` — que tiene que ser un no-op exacto — cambiara 28 bordes. */
html[data-sf-palette]:not(.dark) .border-slate-100 { border-color: var(--sf-pal-border-soft); }
html.dark[data-sf-palette] .dark\:border-slate-800 { border-color: var(--sf-pal-border-soft); }

/* Tinta. Solo los dos niveles que la paleta define; los acentos de color
   (emerald, rose, amber) NO se tocan: son semaforo, no superficie. */
html[data-sf-palette]:not(.dark) .text-slate-900 { color: var(--sf-pal-text); }
html.dark[data-sf-palette] .dark\:text-slate-100 { color: var(--sf-pal-text); }
html[data-sf-palette]:not(.dark) .text-slate-600,
html[data-sf-palette]:not(.dark) .text-slate-500 { color: var(--sf-pal-muted); }
html.dark[data-sf-palette] .dark\:text-slate-400,
html.dark[data-sf-palette] .dark\:text-slate-300 { color: var(--sf-pal-muted); }

/* ── Variantes con ALPHA (IT265, correccion) ─────────────────────────
   El mapeo cubria solo las clases SOLIDAS, y el storefront usa ademas
   sus variantes con transparencia. Medido en vivo con la paleta Grafito:
   la banda de «Productos destacados» renderizaba rgba(15,23,42,.4) —
   slate-900 azulado — sobre un fondo casi negro, o sea una franja de
   otro color en el medio de la pagina. La superficie con alpha tiene que
   salir de la MISMA variable, no del gris de fabrica. */
html[data-theme="palette-alpha-doc"] { /* solo documental, no aplica */ }
html[data-theme="dark"][data-sf-palette] .dark\:bg-slate-900\/40,
html.dark[data-sf-palette] .dark\:bg-slate-900\/40 {
  background-color: color-mix(in srgb, var(--sf-pal-surface) 40%, transparent);
}
html.dark[data-sf-palette] .dark\:bg-slate-800\/95 {
  background-color: color-mix(in srgb, var(--sf-pal-sunk) 95%, transparent);
}
html.dark[data-sf-palette] .dark\:bg-slate-800\/60 {
  background-color: color-mix(in srgb, var(--sf-pal-sunk) 60%, transparent);
}
html.dark[data-sf-palette] .dark\:bg-slate-800\/50 {
  background-color: color-mix(in srgb, var(--sf-pal-sunk) 50%, transparent);
}
html[data-sf-palette]:not(.dark) .bg-white\/95 {
  background-color: color-mix(in srgb, var(--sf-pal-surface) 95%, transparent);
}

/* NO se mapean a proposito:
   - `bg-slate-800` / `bg-slate-900` en tema CLARO: son inversiones
     deliberadas (una banda oscura sobre pagina clara). Teñirlas con la
     superficie de la paleta las volveria claras y romperia el contraste
     del texto blanco que llevan encima.
   - `bg-white/10`: es un velo sobre una imagen, no una superficie.
   - `bg-slate-400`: separadores y puntos, no fondo.
   Guard: test_paletas_fondo.py::MapeoCubreElArbolTest — si aparece una
   clase neutra nueva en el storefront, hay que mapearla o declararla aca
   con su motivo. */

/* Los tokens del sistema tambien siguen a la paleta, para que los
   componentes `sf-*` (notas, tablas, campos) no queden en el gris de
   fabrica sobre un fondo arena.

   SIN el `html` de adelante, y es deliberado (2026-09-13). Con el, este
   puente pesaba (0,1,1) y le ganaba a `[data-sf-theme="x"]` (0,1,0), que es
   como los theme.css scopean SUS tokens. Resultado: un tema tenia identidad
   cromatica en oscuro — ahi su selector lleva `.dark` y pesa (0,2,0) — y en
   claro quedaba en el slate de fabrica, con sus tokens de superficie como
   letra muerta. El mismo sistema se comportaba de dos maneras segun el tema.

   A (0,1,0) los dos quedan a la par y decide el orden de carga, que en los
   dos caminos pone al tema despues: en el kernel `_palettes.css` va en el
   head antes de `sf_theme_css`, y en el bundle de una carpeta independiente
   el CSS propio se concatena despues de esta hoja (`OWN_CSS_SLOT`). O sea:
   el tema gana, la paleta rellena lo que el tema no declara.

   Precedencia elegida: el tema es la identidad del negocio; la paleta es una
   preferencia de fondo. Los 10 temas que no declaran superficies siguen
   tomando la paleta igual, porque no compiten.

   Las reglas de mas arriba (`html[data-sf-palette]:not(.dark) .bg-white`…)
   NO bajan: mapean utilidades de Tailwind y necesitan ese peso para ganarles.
   Guard: `test_paleta_no_pisa_al_tema`. */
[data-sf-palette] {
  --sf-color-bg: var(--sf-pal-bg);
  --sf-color-bg-elevated: var(--sf-pal-surface);
  --sf-color-bg-subtle: var(--sf-pal-sunk);
  --sf-color-border: var(--sf-pal-border);
  --sf-color-border-soft: var(--sf-pal-border-soft);
  --sf-color-text: var(--sf-pal-text);
  --sf-color-text-muted: var(--sf-pal-muted);
}

/* ── Muestra del selector (back-office) ─────────────────────────────── */
.sf-swatch {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 10;
  border-radius: var(--sf-radius-lg, 12px);
  border: 1px solid var(--sf-swatch-border);
  background: var(--sf-swatch-bg);
  padding: 0.5rem;
  overflow: hidden;
}
/* La muestra dibuja una tienda en miniatura — barra + dos tarjetas — en
   vez de un cuadrado de color: lo que se elige es la relacion entre el
   fondo y las superficies, no un color suelto. */
.sf-swatch__bar {
  height: 0.5rem;
  border-radius: 3px;
  background: var(--sf-swatch-surface);
  border: 1px solid var(--sf-swatch-border);
  margin-bottom: 0.4rem;
}
.sf-swatch__row { display: flex; gap: 0.35rem; height: calc(100% - 0.9rem); }
.sf-swatch__card {
  flex: 1;
  border-radius: 4px;
  background: var(--sf-swatch-surface);
  border: 1px solid var(--sf-swatch-border);
  position: relative;
}
.sf-swatch__card::after {
  content: "";
  position: absolute;
  left: 18%; right: 18%; bottom: 22%;
  height: 2px;
  border-radius: 2px;
  background: var(--sf-swatch-text);
  opacity: 0.5;
}

/* >>> CSS PROPIO DEL TENANT — editá acá; el builder conserva este bloque al regenerar >>> */
/* ============================================================================
   La Trigueña — hoja de diseño del tema standalone.
   ----------------------------------------------------------------------------
   Excepción declarada a S25/S26 (decisión del dueño 2026-09-06): la carta
   pública de cada tenant vive en su propia carpeta, sin herencia del kernel.
   Por eso este archivo es autosuficiente: define TODO lo que los templates
   del tema usan (`restaurant-*`, y los pocos `sf-*` que el markup heredó),
   sin depender de `_components.css` ni de `_design_tokens.css`.

   Reglas que sí se respetan, porque son transversales:
   - Par claro/oscuro COMPLETO. La paleta se declara entera en `:root`; el
     modo oscuro solo REDEFINE tokens, en los dos guardas (`[data-theme]`
     explícito y `prefers-color-scheme` para el modo «sistema»).
   - Cero selectores de elemento globales. La versión anterior pisaba
     `button {}` e `input, select, textarea {}` con `color:#fff;
     background:transparent`, que es exactamente por qué el combo
     «Orden predeterminado» del catálogo salía blanco sobre blanco.
   - Contraste AA (>=4.5:1) en ambos temas para texto, y >=3:1 para bordes
     e iconografía.
   ========================================================================== */

/* ── 1. Marca ───────────────────────────────────────────────────────────────
   El acento sale de `--sf-primary`, que `base_storefront.html` completa con
   `storefront_cfg.color_primario`. Si el dueño carga su color de marca en el
   back-office, gana el suyo; el valor del tema es el default declarado, no un
   hardcode que tape el dato real.                                           */

:root {
  color-scheme: light;

  --lt-accent:          var(--sf-primary, #b4552a);
  --lt-accent-strong:   color-mix(in srgb, var(--lt-accent) 82%, #000);
  --lt-accent-ink:      #fff8f3;
  --lt-accent-soft:     color-mix(in srgb, var(--lt-accent) 12%, #fff);
  --lt-accent-line:     color-mix(in srgb, var(--lt-accent) 34%, #fff);

  --lt-bg:              #faf6f0;
  --lt-bg-elev:         #ffffff;
  --lt-bg-sunken:       #f1e9dd;
  --lt-bg-inverse:      #1a1512;

  --lt-ink:             #1c1714;
  --lt-ink-soft:        #574c43;
  --lt-ink-muted:       #756860;
  --lt-ink-inverse:     #faf6f0;

  --lt-line:            #e4d9cb;
  --lt-line-strong:     #cdbda9;

  --lt-ok:              #2f6f4f;
  --lt-warn:            #8a5a10;
  --lt-danger:          #a3352b;

  --lt-shadow-sm:  0 1px 2px rgba(28, 23, 20, .06), 0 2px 8px -4px rgba(28, 23, 20, .10);
  --lt-shadow-md:  0 4px 12px -4px rgba(28, 23, 20, .12), 0 12px 32px -16px rgba(28, 23, 20, .18);
  --lt-shadow-lg:  0 12px 28px -12px rgba(28, 23, 20, .20), 0 32px 64px -32px rgba(28, 23, 20, .28);

  --lt-radius-sm: .5rem;
  --lt-radius:    .875rem;
  --lt-radius-lg: 1.25rem;
  --lt-radius-xl: 1.75rem;

  --lt-font-display: 'Poppins', 'Inter', system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --lt-font-body:    'Inter', system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  --lt-ease: cubic-bezier(.22, 1, .36, 1);
  --lt-t-fast: .18s var(--lt-ease);
  --lt-t: .28s var(--lt-ease);
}

/* Modo oscuro — mitad «sistema». El guard `:not([data-theme="light"])` evita
   que el usuario que eligió claro a mano reciba la paleta oscura del SO.    */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not(.light) {
    color-scheme: dark;

    --lt-accent:        color-mix(in srgb, var(--sf-primary, #b4552a) 74%, #ffd9c2);
    --lt-accent-strong: color-mix(in srgb, var(--sf-primary, #b4552a) 88%, #ffd9c2);
    --lt-accent-ink:    #17100b;
    --lt-accent-soft:   color-mix(in srgb, var(--sf-primary, #b4552a) 22%, #14100d);
    --lt-accent-line:   color-mix(in srgb, var(--sf-primary, #b4552a) 46%, #14100d);

    --lt-bg:            #14100d;
    --lt-bg-elev:       #1f1815;
    --lt-bg-sunken:     #0d0a08;
    --lt-bg-inverse:    #f6f0e7;

    --lt-ink:           #f7f1e8;
    --lt-ink-soft:      #d2c5b7;
    --lt-ink-muted:     #a19284;
    --lt-ink-inverse:   #1c1714;

    --lt-line:          #352b24;
    --lt-line-strong:   #4c3e34;

    --lt-ok:            #6cc79b;
    --lt-warn:          #e0ab5a;
    --lt-danger:        #ef8279;

    --lt-shadow-sm: 0 1px 2px rgba(0, 0, 0, .40), 0 2px 8px -4px rgba(0, 0, 0, .50);
    --lt-shadow-md: 0 4px 12px -4px rgba(0, 0, 0, .50), 0 12px 32px -16px rgba(0, 0, 0, .60);
    --lt-shadow-lg: 0 12px 28px -12px rgba(0, 0, 0, .55), 0 32px 64px -32px rgba(0, 0, 0, .70);
  }
}

/* Modo oscuro — mitad «elección explícita». Debe repetir los tokens: si sólo
   viviera en el @media, el toggle no podría forzar oscuro desde un SO claro. */
:root[data-theme="dark"],
:root.dark {
  color-scheme: dark;

  --lt-accent:        color-mix(in srgb, var(--sf-primary, #b4552a) 74%, #ffd9c2);
  --lt-accent-strong: color-mix(in srgb, var(--sf-primary, #b4552a) 88%, #ffd9c2);
  --lt-accent-ink:    #17100b;
  --lt-accent-soft:   color-mix(in srgb, var(--sf-primary, #b4552a) 22%, #14100d);
  --lt-accent-line:   color-mix(in srgb, var(--sf-primary, #b4552a) 46%, #14100d);

  --lt-bg:            #14100d;
  --lt-bg-elev:       #1f1815;
  --lt-bg-sunken:     #0d0a08;
  --lt-bg-inverse:    #f6f0e7;

  --lt-ink:           #f7f1e8;
  --lt-ink-soft:      #d2c5b7;
  --lt-ink-muted:     #a19284;
  --lt-ink-inverse:   #1c1714;

  --lt-line:          #352b24;
  --lt-line-strong:   #4c3e34;

  --lt-ok:            #6cc79b;
  --lt-warn:          #e0ab5a;
  --lt-danger:        #ef8279;

  --lt-shadow-sm: 0 1px 2px rgba(0, 0, 0, .40), 0 2px 8px -4px rgba(0, 0, 0, .50);
  --lt-shadow-md: 0 4px 12px -4px rgba(0, 0, 0, .50), 0 12px 32px -16px rgba(0, 0, 0, .60);
  --lt-shadow-lg: 0 12px 28px -12px rgba(0, 0, 0, .55), 0 32px 64px -32px rgba(0, 0, 0, .70);
}

/* ── 2. Base ─────────────────────────────────────────────────────────────── */

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

.lt-body {
  margin: 0;
  min-height: 100svh;
  background-color: var(--lt-bg);
  color: var(--lt-ink-soft);
  font-family: var(--lt-font-body);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

/* `:where()` deja esta regla en especificidad CERO. Escrita como
   `.lt-body h2` valia (0,1,1) y le ganaba a `.restaurant-slider__title`
   (0,1,0): el titulo del carrusel salia con la tinta del cuerpo — texto
   oscuro ilegible sobre la foto. Toda clase de componente debe poder
   redefinir el color de su encabezado sin pelear especificidad. */
:where(.lt-body) :where(h1, h2, h3, h4) {
  font-family: var(--lt-font-display);
  color: var(--lt-ink);
  letter-spacing: -.02em;
  line-height: 1.15;
  margin: 0;
}

.lt-display   { font-family: var(--lt-font-display); }
.lt-ink       { color: var(--lt-ink); }
.lt-ink-soft  { color: var(--lt-ink-soft); }
.lt-ink-muted { color: var(--lt-ink-muted); }

/* Franja de sección: alterna el fondo sin recurrir a hex sueltos. */
.lt-band        { background: var(--lt-bg); }
.lt-band--sunken{ background: var(--lt-bg-sunken); }

.restaurant-container {
  width: 100%;
  max-width: 80rem;
  margin-inline: auto;
  padding-inline: 1rem;
}
@media (min-width: 640px) { .restaurant-container { padding-inline: 1.5rem; } }
@media (min-width: 1024px){ .restaurant-container { padding-inline: 2rem; } }

.restaurant-section    { padding-block: clamp(2.75rem, 6vw, 4.5rem); }
.restaurant-section-sm { padding-block: clamp(2rem, 4vw, 3rem); }

/* Encabezado de sección: kicker + título + bajada, un solo patrón. */
.lt-section-head { margin-bottom: clamp(1.5rem, 3vw, 2.25rem); }
.restaurant-eyebrow,
.lt-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  font-family: var(--lt-font-display);
  font-size: .75rem;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--lt-accent);
}
.restaurant-eyebrow::before,
.lt-eyebrow::before {
  content: "";
  width: 1.75rem;
  height: 2px;
  border-radius: 2px;
  background: currentColor;
  opacity: .55;
}
.lt-section-title {
  font-size: clamp(1.6rem, 3.2vw, 2.35rem);
  font-weight: 700;
  margin-top: .625rem;
}
.lt-section-lead {
  margin-top: .625rem;
  max-width: 46ch;
  color: var(--lt-ink-soft);
  font-size: 1.0625rem;
}

/* ── 3. Controles ────────────────────────────────────────────────────────── */

.lt-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  padding: .6875rem 1.375rem;
  border: 1px solid transparent;
  border-radius: var(--lt-radius-sm);
  font-family: var(--lt-font-display);
  font-size: .9375rem;
  font-weight: 600;
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--lt-t-fast), border-color var(--lt-t-fast),
              color var(--lt-t-fast), box-shadow var(--lt-t-fast), transform var(--lt-t-fast);
}
.lt-btn:active { transform: translateY(1px); }
.lt-btn:focus-visible {
  outline: 2px solid var(--lt-accent);
  outline-offset: 2px;
}

.lt-btn--primary {
  background: var(--lt-accent);
  color: var(--lt-accent-ink);
  box-shadow: var(--lt-shadow-sm);
}
.lt-btn--primary:hover { background: var(--lt-accent-strong); box-shadow: var(--lt-shadow-md); }

.lt-btn--ghost,
.sf-btn-ghost {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  padding: .6875rem 1.375rem;
  border: 1px solid var(--lt-line-strong);
  border-radius: var(--lt-radius-sm);
  background: var(--lt-bg-elev);
  color: var(--lt-ink);
  font-family: var(--lt-font-display);
  font-size: .9375rem;
  font-weight: 600;
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--lt-t-fast), border-color var(--lt-t-fast), color var(--lt-t-fast);
}
.lt-btn--ghost:hover,
.sf-btn-ghost:hover { border-color: var(--lt-accent); color: var(--lt-accent); }
.lt-btn--ghost:focus-visible,
.sf-btn-ghost:focus-visible { outline: 2px solid var(--lt-accent); outline-offset: 2px; }

.lt-btn--quiet {
  background: transparent;
  color: var(--lt-ink-soft);
  border-color: transparent;
}
.lt-btn--quiet:hover { background: var(--lt-bg-sunken); color: var(--lt-ink); }

.lt-btn--sm { padding: .4375rem .875rem; font-size: .8125rem; }

.lt-btn[disabled],
.lt-btn--off {
  background: var(--lt-bg-sunken);
  color: var(--lt-ink-muted);
  border-color: var(--lt-line);
  box-shadow: none;
  cursor: not-allowed;
}

/* Campos. Con alcance — jamás `input, select {}` a secas. */
.lt-field {
  width: 100%;
  padding: .625rem .875rem;
  border: 1px solid var(--lt-line-strong);
  border-radius: var(--lt-radius-sm);
  background: var(--lt-bg-elev);
  color: var(--lt-ink);
  font-family: var(--lt-font-body);
  font-size: .9375rem;
  line-height: 1.4;
  transition: border-color var(--lt-t-fast), box-shadow var(--lt-t-fast);
}
.lt-field::placeholder { color: var(--lt-ink-muted); opacity: 1; }
.lt-field:focus {
  outline: none;
  border-color: var(--lt-accent);
  box-shadow: 0 0 0 3px var(--lt-accent-soft);
}
select.lt-field {
  appearance: none;
  padding-right: 2.25rem;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 1.05rem) 55%, calc(100% - .7rem) 55%;
  background-size: .35rem .35rem, .35rem .35rem;
  background-repeat: no-repeat;
}
/* Las opciones las pinta el SO: sin fondo explícito, el desplegable oscuro
   de Windows/Chrome renderiza texto claro sobre blanco. */
.lt-field option { background: var(--lt-bg-elev); color: var(--lt-ink); }

.lt-chip {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  padding: .3125rem .75rem;
  border: 1px solid var(--lt-line);
  border-radius: 9999px;
  background: var(--lt-bg-elev);
  color: var(--lt-ink-soft);
  font-size: .8125rem;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  transition: border-color var(--lt-t-fast), color var(--lt-t-fast), background-color var(--lt-t-fast);
}
.lt-chip:hover { border-color: var(--lt-accent); color: var(--lt-accent); }
.lt-chip--on { background: var(--lt-accent); border-color: var(--lt-accent); color: var(--lt-accent-ink); }

/* ── 4. Cabecera y pie ───────────────────────────────────────────────────── */

.sf-skip-link {
  position: absolute;
  left: -9999px;
  width: 1px; height: 1px;
  overflow: hidden;
}
.sf-skip-link:focus {
  position: fixed;
  left: 1rem; top: 1rem;
  width: auto; height: auto;
  padding: .625rem 1rem;
  z-index: 100;
  background: var(--lt-accent);
  color: var(--lt-accent-ink);
  border-radius: var(--lt-radius-sm);
  font-weight: 600;
  box-shadow: var(--lt-shadow-md);
}

.sf-header-glass {
  background: color-mix(in srgb, var(--lt-bg) 82%, transparent);
  border-bottom: 1px solid var(--lt-line);
  backdrop-filter: saturate(150%) blur(12px);
  -webkit-backdrop-filter: saturate(150%) blur(12px);
}

.lt-brand-mark,
.sf-tenant-grad {
  display: grid;
  place-items: center;
  background: linear-gradient(135deg, var(--lt-accent), var(--lt-accent-strong));
  color: var(--lt-accent-ink);
  font-family: var(--lt-font-display);
  font-weight: 700;
}
.lt-brand-name {
  font-family: var(--lt-font-display);
  font-weight: 600;
  letter-spacing: -.01em;
  color: var(--lt-ink);
}

.lt-navlink {
  position: relative;
  color: var(--lt-ink-soft);
  text-decoration: none;
  font-weight: 600;
  font-size: .9375rem;
  padding-block: .25rem;
  transition: color var(--lt-t-fast);
}
.lt-navlink::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -2px;
  height: 2px;
  border-radius: 2px;
  background: var(--lt-accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--lt-t);
}
.lt-navlink:hover { color: var(--lt-ink); }
.lt-navlink:hover::after,
.lt-navlink[aria-current="page"]::after { transform: scaleX(1); }
.lt-navlink[aria-current="page"] { color: var(--lt-accent); }
.lt-navlink:focus-visible { outline: 2px solid var(--lt-accent); outline-offset: 4px; border-radius: 2px; }

/* Botón-icono de la barra (carrito, deseados, tema). */
.lt-iconbtn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.375rem;
  height: 2.375rem;
  border: 1px solid var(--lt-line);
  border-radius: var(--lt-radius-sm);
  background: var(--lt-bg-elev);
  color: var(--lt-ink-soft);
  transition: border-color var(--lt-t-fast), color var(--lt-t-fast), background-color var(--lt-t-fast);
}
.lt-iconbtn:hover { border-color: var(--lt-accent); color: var(--lt-accent); }
.lt-iconbtn:focus-visible { outline: 2px solid var(--lt-accent); outline-offset: 2px; }

.lt-countdot {
  position: absolute;
  top: -.3125rem; right: -.3125rem;
  min-width: 1.125rem;
  height: 1.125rem;
  padding-inline: .25rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 9999px;
  background: var(--lt-accent);
  color: var(--lt-accent-ink);
  font-size: .6875rem;
  font-weight: 700;
  line-height: 1;
}

.sf-panel-grad {
  background: linear-gradient(135deg, var(--lt-accent), var(--lt-accent-strong));
  color: var(--lt-accent-ink);
}

.lt-footer {
  background: var(--lt-bg-inverse);
  color: color-mix(in srgb, var(--lt-ink-inverse) 78%, transparent);
  margin-top: auto;
}
.lt-footer h3 {
  color: var(--lt-ink-inverse);
  font-family: var(--lt-font-display);
  font-size: .8125rem;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  margin-bottom: 1rem;
}
.lt-footer a {
  color: color-mix(in srgb, var(--lt-ink-inverse) 78%, transparent);
  text-decoration: none;
  transition: color var(--lt-t-fast);
}
.lt-footer a:hover { color: var(--lt-ink-inverse); }
.lt-footer a:focus-visible { outline: 2px solid var(--lt-accent); outline-offset: 3px; border-radius: 2px; }
.lt-footer__rule { border-top: 1px solid color-mix(in srgb, var(--lt-ink-inverse) 16%, transparent); }

/* ── 5. Carrusel ─────────────────────────────────────────────────────────── */

.restaurant-slider {
  --restaurant-slider-height: clamp(24rem, 62svh, 30rem);
  position: relative;
  isolation: isolate;
  overflow: hidden;
  width: 100%;
  height: var(--restaurant-slider-height);
  border-radius: var(--lt-radius-xl);
  background: var(--lt-bg-inverse);
  box-shadow: var(--lt-shadow-lg);
  user-select: none;
}
@media (min-width: 640px) {
  .restaurant-slider { --restaurant-slider-height: clamp(26rem, min(50vw, 68svh), 34rem); }
}

.restaurant-slider__image,
.sf-slide-media {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  transform-origin: center;
}
/* Ken Burns sólo en el slide activo, y sólo si el usuario no pidió menos
   movimiento. */
@media (prefers-reduced-motion: no-preference) {
  .restaurant-slider__image { transition: transform 9s var(--lt-ease); }
  [data-sf-slide].opacity-100 .restaurant-slider__image { transform: scale(1.07); }
}

/* Degradé de legibilidad: sin esto el título blanco cae sobre zonas claras
   de la foto y se pierde. Vertical + lateral para que aguante cualquier foto. */
/* Velo CONTENIDO (2026-09-07, pedido del dueño: «sin degradado, totalmente
   visual»). Acá el texto va DESNUDO sobre la foto (no hay card glass como en
   los temas del kernel), así que el oscurecido no se elimina: se acota a un
   halo detrás del bloque de texto, que muere antes del centro. Antes era un
   velo de marco completo que arrancaba en 93% de negro y dejaba la foto
   irreconocible. El titular ya trae su propia text-shadow como segunda
   defensa. */
.restaurant-slider__overlay,
.sf-slide-shade {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(56% 104% at 20% 50%, rgba(12, 9, 7, .88) 0%, rgba(12, 9, 7, .62) 40%, rgba(12, 9, 7, .22) 64%, rgba(12, 9, 7, 0) 84%);
}
/* Mobile: el copy pasa a ancho completo (media query de más abajo), así que el
   halo se centra en vez de anclarse a la izquierda. */
@media (max-width: 639px) {
  .restaurant-slider__overlay,
  .sf-slide-shade {
    background:
      radial-gradient(118% 74% at 50% 50%, rgba(12, 9, 7, .86) 0%, rgba(12, 9, 7, .56) 44%, rgba(12, 9, 7, 0) 88%);
  }
}

.restaurant-slider__fallback {
  position: absolute;
  inset: 0;
  background: linear-gradient(135deg, var(--lt-accent-strong), var(--lt-bg-inverse) 70%);
}
.restaurant-slider__pattern {
  position: absolute;
  inset: 0;
  opacity: .18;
  background-image:
    radial-gradient(circle at 1px 1px, rgba(255, 255, 255, .55) 1px, transparent 0);
  background-size: 1.25rem 1.25rem;
}

.restaurant-slider__content {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  padding: clamp(1.5rem, 4vw, 3.5rem);
  padding-bottom: clamp(3.75rem, 8vw, 5rem);
  z-index: 10;
}
.restaurant-slider__copy {
  max-width: 34rem;
  color: #fff;
}
.restaurant-slider__eyebrow {
  display: inline-flex;
  align-items: center;
  padding: .3125rem .875rem;
  border: 1px solid rgba(255, 255, 255, .30);
  border-radius: 9999px;
  background: rgba(255, 255, 255, .14);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  font-family: var(--lt-font-display);
  font-size: .6875rem;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: #fff;
}
.restaurant-slider__title {
  margin-top: 1rem;
  font-family: var(--lt-font-display);
  font-size: clamp(1.9rem, 5vw, 3.15rem);
  font-weight: 700;
  line-height: 1.08;
  letter-spacing: -.025em;
  color: #fff;
  text-wrap: balance;
  text-shadow: 0 2px 22px rgba(12, 9, 7, .62);
}
.restaurant-slider__text {
  margin-top: .875rem;
  max-width: 34rem;
  font-size: clamp(.9375rem, 1.6vw, 1.0625rem);
  line-height: 1.6;
  color: rgba(255, 255, 255, .92);
  text-shadow: 0 1px 12px rgba(0, 0, 0, .5);
}
.restaurant-slider__actions {
  margin-top: 1.75rem;
  display: flex;
  flex-wrap: wrap;
  gap: .75rem;
}

.restaurant-slider__primary {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  padding: .8125rem 1.625rem;
  border-radius: var(--lt-radius-sm);
  background: var(--lt-accent);
  color: var(--lt-accent-ink);
  font-family: var(--lt-font-display);
  font-weight: 600;
  font-size: .9375rem;
  text-decoration: none;
  box-shadow: 0 10px 28px -12px rgba(0, 0, 0, .7);
  transition: background-color var(--lt-t-fast), transform var(--lt-t-fast);
}
.restaurant-slider__primary:hover { background: var(--lt-accent-strong); transform: translateY(-2px); }
.restaurant-slider__primary:focus-visible { outline: 2px solid #fff; outline-offset: 3px; }

.restaurant-slider__secondary {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  padding: .8125rem 1.375rem;
  border: 1px solid rgba(255, 255, 255, .38);
  border-radius: var(--lt-radius-sm);
  background: rgba(255, 255, 255, .12);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  color: #fff;
  font-family: var(--lt-font-display);
  font-weight: 600;
  font-size: .9375rem;
  text-decoration: none;
  transition: background-color var(--lt-t-fast), border-color var(--lt-t-fast);
}
.restaurant-slider__secondary:hover { background: rgba(255, 255, 255, .24); border-color: rgba(255, 255, 255, .6); }
.restaurant-slider__secondary:focus-visible { outline: 2px solid #fff; outline-offset: 3px; }

/* Controles del carrusel */
.restaurant-slider [data-sf-slider-prev],
.restaurant-slider [data-sf-slider-next],
.restaurant-slider [data-sf-slider-toggle] {
  position: absolute;
  z-index: 20;
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  border: 1px solid rgba(255, 255, 255, .26);
  border-radius: 9999px;
  background: rgba(14, 11, 9, .55);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  color: #fff;
  cursor: pointer;
  transition: background-color var(--lt-t-fast), border-color var(--lt-t-fast), transform var(--lt-t-fast);
}
.restaurant-slider [data-sf-slider-prev] { bottom: 1.25rem; right: 4.25rem; }
.restaurant-slider [data-sf-slider-next] { bottom: 1.25rem; right: 1rem; }
.restaurant-slider [data-sf-slider-toggle] { top: 1rem; right: 1rem; width: 2.375rem; height: 2.375rem; }

.restaurant-slider [data-sf-slider-prev]:hover,
.restaurant-slider [data-sf-slider-next]:hover { background: var(--lt-accent); border-color: var(--lt-accent); }
.restaurant-slider [data-sf-slider-toggle]:hover { background: var(--lt-accent); border-color: var(--lt-accent); }
.restaurant-slider [data-sf-slider-prev]:focus-visible,
.restaurant-slider [data-sf-slider-next]:focus-visible,
.restaurant-slider [data-sf-slider-toggle]:focus-visible { outline: 2px solid #fff; outline-offset: 3px; }

.restaurant-slider__progress {
  position: absolute;
  left: clamp(1.5rem, 4vw, 3.5rem);
  right: 7rem;
  bottom: 2.75rem;
  height: 3px;
  border-radius: 3px;
  background: rgba(255, 255, 255, .22);
  overflow: hidden;
  z-index: 15;
}
.restaurant-slider__progress-fill {
  height: 100%;
  background: var(--lt-accent);
  transform: scaleX(0);
  transform-origin: left center;
}

.restaurant-slider__dots {
  position: absolute;
  left: clamp(1.5rem, 4vw, 3.5rem);
  bottom: 1.25rem;
  display: flex;
  gap: .5rem;
  z-index: 20;
}
.restaurant-slider__dot {
  width: .5rem;
  height: .5rem;
  padding: 0;
  border: none;
  border-radius: 9999px;
  background: rgba(255, 255, 255, .45);
  cursor: pointer;
  transition: width var(--lt-t), background-color var(--lt-t);
}
.restaurant-slider__dot.is-active { width: 1.75rem; background: #fff; }
.restaurant-slider__dot:focus-visible { outline: 2px solid #fff; outline-offset: 3px; }

@media (max-width: 639px) {
  .restaurant-slider [data-sf-slider-prev],
  .restaurant-slider [data-sf-slider-next] { display: none; }
  .restaurant-slider__copy { max-width: 100%; }
}

/* ── 6. Tarjeta de producto ──────────────────────────────────────────────── */

.restaurant-card {
  position: relative;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid var(--lt-line);
  border-radius: var(--lt-radius-lg);
  background: var(--lt-bg-elev);
  box-shadow: var(--lt-shadow-sm);
  transition: box-shadow var(--lt-t), transform var(--lt-t), border-color var(--lt-t);
}
.restaurant-card:hover,
.restaurant-card:focus-within {
  transform: translateY(-3px);
  border-color: var(--lt-accent-line);
  box-shadow: var(--lt-shadow-md);
}
.restaurant-card.is-out { opacity: .72; }

.restaurant-card__image {
  position: relative;
  display: block;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: var(--lt-bg-sunken);
  border-radius: 0;
}
.restaurant-card__image:focus-visible { outline: 2px solid var(--lt-accent); outline-offset: -2px; }

.sf-product-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.restaurant-card__fallback {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background: linear-gradient(135deg, var(--lt-bg-sunken), var(--lt-accent-soft));
  color: var(--lt-accent);
  font-family: var(--lt-font-display);
  font-size: 2.5rem;
  font-weight: 700;
}

.restaurant-card__badge {
  position: absolute;
  top: .75rem; left: .75rem;
  z-index: 10;
  padding: .25rem .625rem;
  border-radius: 9999px;
  background: var(--lt-accent);
  color: var(--lt-accent-ink);
  font-size: .6875rem;
  font-weight: 700;
  letter-spacing: .04em;
  box-shadow: var(--lt-shadow-sm);
}
.restaurant-card__badge--low { background: var(--lt-warn); color: #fff; }
.restaurant-card__badge--out { background: var(--lt-ink-muted); color: #fff; }

.restaurant-card__wish {
  position: absolute;
  top: .75rem; right: .75rem;
  z-index: 20;
  display: grid;
  place-items: center;
  width: 2rem; height: 2rem;
  border: 1px solid var(--lt-line);
  border-radius: 9999px;
  background: var(--lt-bg-elev);
  color: var(--lt-ink-muted);
  cursor: pointer;
  transition: color var(--lt-t-fast), border-color var(--lt-t-fast), transform var(--lt-t-fast);
}
.restaurant-card__wish:hover { color: var(--lt-danger); border-color: var(--lt-danger); transform: scale(1.06); }
.restaurant-card__wish:focus-visible { outline: 2px solid var(--lt-accent); outline-offset: 2px; }

.restaurant-card__body {
  display: flex;
  flex-direction: column;
  gap: .25rem;
  flex: 1;
  padding: .875rem 1rem 1rem;
}
.restaurant-card__category {
  font-size: .6875rem;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--lt-accent);
}
.restaurant-card__name {
  font-family: var(--lt-font-display);
  font-size: 1.0625rem;
  font-weight: 600;
  line-height: 1.3;
  color: var(--lt-ink);
  text-decoration: none;
  transition: color var(--lt-t-fast);
}
.restaurant-card__name:hover { color: var(--lt-accent); }
.restaurant-card__name:focus-visible { outline: 2px solid var(--lt-accent); outline-offset: 2px; border-radius: 2px; }
.restaurant-card__description {
  font-size: .875rem;
  line-height: 1.5;
  color: var(--lt-ink-soft);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.restaurant-card__footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  margin-top: auto;
  padding-top: .875rem;
}
.restaurant-card__old-price {
  margin-right: .375rem;
  font-size: .8125rem;
  color: var(--lt-ink-muted);
  text-decoration: line-through;
}
/* `font-variant-numeric` alinea los guaraníes en columna; nunca `uppercase`
   sobre un importe (deforma el separador de miles). */
.restaurant-card__price {
  font-family: var(--lt-font-display);
  font-size: 1.0625rem;
  font-weight: 700;
  color: var(--lt-ink);
  font-variant-numeric: tabular-nums;
}
.restaurant-card__add {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  padding: .4375rem .875rem;
  border: none;
  border-radius: var(--lt-radius-sm);
  background: var(--lt-accent);
  color: var(--lt-accent-ink);
  font-family: var(--lt-font-display);
  font-size: .8125rem;
  font-weight: 600;
  cursor: pointer;
  transition: background-color var(--lt-t-fast), transform var(--lt-t-fast);
}
.restaurant-card__add:hover { background: var(--lt-accent-strong); }
.restaurant-card__add:active { transform: scale(.96); }
.restaurant-card__add:focus-visible { outline: 2px solid var(--lt-accent); outline-offset: 2px; }
.restaurant-card__add--off {
  background: var(--lt-bg-sunken);
  color: var(--lt-ink-muted);
  cursor: not-allowed;
}

/* ── 7. Grillas, estado vacío, paginación ────────────────────────────────── */

.lt-grid {
  display: grid;
  gap: 1.25rem;
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
}
@media (max-width: 480px) {
  .lt-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .75rem; }
}

.lt-rail {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(15rem, 1fr);
  gap: 1.25rem;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  padding-bottom: .5rem;
  scrollbar-width: thin;
}
.lt-rail > * { scroll-snap-align: start; }
@media (min-width: 1024px) {
  .lt-rail { grid-auto-flow: row; grid-template-columns: repeat(4, minmax(0, 1fr)); overflow: visible; }
}

.lt-empty {
  display: grid;
  place-items: center;
  gap: .875rem;
  padding: clamp(2.5rem, 8vw, 4.5rem) 1.5rem;
  border: 1px dashed var(--lt-line-strong);
  border-radius: var(--lt-radius-lg);
  background: var(--lt-bg-elev);
  text-align: center;
}
.lt-empty__icon {
  display: grid;
  place-items: center;
  width: 3.25rem; height: 3.25rem;
  border-radius: 9999px;
  background: var(--lt-accent-soft);
  color: var(--lt-accent);
  font-size: 1.25rem;
}
.lt-empty__title {
  font-family: var(--lt-font-display);
  font-size: 1.125rem;
  font-weight: 600;
  color: var(--lt-ink);
}
.lt-empty__text { max-width: 42ch; color: var(--lt-ink-soft); font-size: .9375rem; }

.lt-pager { display: flex; align-items: center; justify-content: center; gap: .5rem; }
.lt-pager__link,
.lt-pager__state {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  padding: .5rem 1rem;
  border: 1px solid var(--lt-line-strong);
  border-radius: var(--lt-radius-sm);
  font-size: .875rem;
  font-weight: 600;
  text-decoration: none;
  color: var(--lt-ink);
  background: var(--lt-bg-elev);
  transition: border-color var(--lt-t-fast), color var(--lt-t-fast);
}
.lt-pager__link:hover { border-color: var(--lt-accent); color: var(--lt-accent); }
.lt-pager__link:focus-visible { outline: 2px solid var(--lt-accent); outline-offset: 2px; }
.lt-pager__link--off { color: var(--lt-ink-muted); background: var(--lt-bg-sunken); cursor: not-allowed; }
.lt-pager__state { border-color: transparent; background: transparent; color: var(--lt-ink-muted); font-variant-numeric: tabular-nums; }

/* ── 8. Bloques de contenido de la home ──────────────────────────────────── */

.lt-featurette {
  display: grid;
  gap: clamp(1.5rem, 4vw, 3rem);
  align-items: center;
}
@media (min-width: 900px) { .lt-featurette { grid-template-columns: 1.05fr .95fr; } }

.lt-figure {
  position: relative;
  overflow: hidden;
  border-radius: var(--lt-radius-lg);
  background: var(--lt-bg-sunken);
  box-shadow: var(--lt-shadow-md);
  aspect-ratio: 4 / 3;
}
.lt-figure img { width: 100%; height: 100%; object-fit: cover; display: block; }

.lt-valuegrid {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
}
.lt-value {
  display: flex;
  gap: .875rem;
  padding: 1.125rem;
  border: 1px solid var(--lt-line);
  border-radius: var(--lt-radius);
  background: var(--lt-bg-elev);
}
.lt-value__icon {
  flex: none;
  display: grid;
  place-items: center;
  width: 2.5rem; height: 2.5rem;
  border-radius: var(--lt-radius-sm);
  background: var(--lt-accent-soft);
  color: var(--lt-accent);
}
.lt-value__title {
  font-family: var(--lt-font-display);
  font-size: .9375rem;
  font-weight: 600;
  color: var(--lt-ink);
}
.lt-value__text { margin-top: .1875rem; font-size: .8125rem; line-height: 1.5; color: var(--lt-ink-soft); }

.lt-cta {
  position: relative;
  overflow: hidden;
  border-radius: var(--lt-radius-xl);
  background: var(--lt-bg-inverse);
  color: var(--lt-ink-inverse);
  padding: clamp(2rem, 5vw, 3.5rem);
  text-align: center;
}
.lt-cta::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(ellipse at 50% 0%, color-mix(in srgb, var(--lt-accent) 34%, transparent), transparent 62%);
}
.lt-cta > * { position: relative; z-index: 1; }
.lt-cta__title {
  font-family: var(--lt-font-display);
  font-size: clamp(1.5rem, 3.4vw, 2.125rem);
  font-weight: 700;
  color: var(--lt-ink-inverse);
}
.lt-cta__text {
  margin: .75rem auto 0;
  max-width: 44ch;
  color: color-mix(in srgb, var(--lt-ink-inverse) 82%, transparent);
}

/* ── 9. Ficha de producto ────────────────────────────────────────────────── */

.lt-detail { display: grid; gap: clamp(1.5rem, 4vw, 3rem); }
@media (min-width: 900px) { .lt-detail { grid-template-columns: 1fr 1fr; align-items: start; } }

.lt-detail__media {
  overflow: hidden;
  border-radius: var(--lt-radius-lg);
  background: var(--lt-bg-sunken);
  box-shadow: var(--lt-shadow-md);
  aspect-ratio: 4 / 3;
}
.lt-detail__media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.lt-detail__title {
  font-family: var(--lt-font-display);
  font-size: clamp(1.65rem, 3.6vw, 2.375rem);
  font-weight: 700;
  color: var(--lt-ink);
}
.lt-detail__price {
  font-family: var(--lt-font-display);
  font-size: 1.875rem;
  font-weight: 700;
  color: var(--lt-ink);
  font-variant-numeric: tabular-nums;
}
.lt-prose { color: var(--lt-ink-soft); line-height: 1.7; }
.lt-prose :where(h1, h2, h3, h4) { color: var(--lt-ink); margin-top: 1.25rem; }
.lt-prose :where(a) { color: var(--lt-accent); }

.lt-stock { display: inline-flex; align-items: center; gap: .4375rem; font-size: .875rem; font-weight: 600; }
.lt-stock::before { content: ""; width: .5rem; height: .5rem; border-radius: 9999px; background: currentColor; }
.lt-stock--ok   { color: var(--lt-ok); }
.lt-stock--low  { color: var(--lt-warn); }
.lt-stock--out  { color: var(--lt-danger); }

/* ── 10. Utilidades ──────────────────────────────────────────────────────── */

.lt-note { font-size: .8125rem; color: var(--lt-ink-muted); }
.lt-note--ok { color: var(--lt-ok); }
.lt-note--bad { color: var(--lt-danger); }

.lt-body ::-webkit-scrollbar { width: 8px; height: 8px; }
.lt-body ::-webkit-scrollbar-track { background: transparent; }
.lt-body ::-webkit-scrollbar-thumb {
  background-color: var(--lt-line-strong);
  border-radius: 9999px;
  border: 2px solid transparent;
  background-clip: content-box;
}

@media (prefers-reduced-motion: reduce) {
  .lt-body *, .lt-body *::before, .lt-body *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ── 11. Puente hacia los tokens del kernel ──────────────────────────────────
   `search.css` y `_theme_toggle.css` son hojas chicas del kernel que este tema
   SÍ consume (existen para cargarse sueltas, igual que en `/bio/`). Piden los
   tokens `--sf-*` de `_design_tokens.css`, que este tema standalone no carga.

   En vez de arrastrar el sistema entero del kernel —lo que reabriría la
   herencia que la decisión del dueño cerró— se mapean los pocos tokens que
   esas hojas usan contra la paleta de La Trigueña. Efecto lateral bueno: el
   buscador queda con la piel del tema, y hereda el par claro/oscuro solo,
   porque los `--lt-*` ya se redefinen arriba.

   Si una hoja del kernel empieza a pedir un token que no está acá, se ve como
   color transparente/heredado — no como error. Ante una regresión visual del
   buscador, revisar primero esta lista contra `_design_tokens.css`.          */

:root {
  --sf-color-bg:            var(--lt-bg);
  --sf-color-bg-elevated:   var(--lt-bg-elev);
  --sf-color-bg-subtle:     var(--lt-bg-sunken);
  --sf-color-border:        var(--lt-line);
  --sf-color-border-strong: var(--lt-line-strong);
  --sf-color-primary:       var(--lt-accent);
  --sf-color-primary-600:   var(--lt-accent-strong);
  --sf-color-text:          var(--lt-ink);
  --sf-color-text-muted:    var(--lt-ink-muted);

  --sf-radius-sm: var(--lt-radius-sm);
  --sf-radius-md: var(--lt-radius);
  --sf-radius-lg: var(--lt-radius-lg);

  --sf-shadow-xs: var(--lt-shadow-sm);

  --sf-space-1: .25rem;
  --sf-space-2: .5rem;
  --sf-space-3: .75rem;
  --sf-space-4: 1rem;
  --sf-space-6: 1.5rem;
  --sf-space-8: 2rem;

  --sf-z-dropdown: 50;
}

/* Menú móvil desplegable del topbar (mismo patrón que el tema restaurante:
   `data-sf-menu-toggle` + `#sf-mobile-menu`, con la piel de este tema). */
.lt-mobilemenu { border-top: 1px solid var(--lt-line); }
.lt-mobilemenu__link {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .625rem .75rem;
  border-radius: var(--lt-radius-sm);
  color: var(--lt-ink-soft);
  font-size: .9375rem;
  font-weight: 600;
  text-decoration: none;
  transition: background-color var(--lt-t-fast), color var(--lt-t-fast);
}
.lt-mobilemenu__link:hover,
.lt-mobilemenu__link[aria-current="page"] { background: var(--lt-bg-sunken); color: var(--lt-ink); }
.lt-mobilemenu__link:focus-visible { outline: 2px solid var(--lt-accent); outline-offset: -2px; }
.lt-mobilemenu__link i { width: 1.25rem; text-align: center; color: var(--lt-ink-muted); }
.lt-mobilemenu__link:hover i,
.lt-mobilemenu__link[aria-current="page"] i { color: var(--lt-accent); }
.lt-mobilemenu__count {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.25rem;
  height: 1.25rem;
  padding-inline: .375rem;
  border-radius: 9999px;
  background: var(--lt-accent);
  color: var(--lt-accent-ink);
  font-size: .6875rem;
  font-weight: 700;
}

/* Cruce entre slides: los tres <article> estan apilados en el mismo lugar, asi
   que durante los 700ms de fundido se veian los DOS textos superpuestos. Con
   el slide entrante por encima, su foto (opaca) va tapando al saliente a
   medida que aparece, en vez de transparentarse contra el. */
.restaurant-slider [data-sf-slide] { z-index: 1; }
.restaurant-slider [data-sf-slide].opacity-100 { z-index: 2; }


/* Piso de legibilidad del acento en modo oscuro.
   --------------------------------------------------------------------------
   `--sf-primary` es dato del tenant y puede ser CUALQUIER color. La mezcla de
   arriba (`color-mix(... 74%, tinte cálido)`) asume un tono medio y se rompe
   en los extremos: medido en el tenant latriguena, que tiene
   `color_primario='#000000'`, el acento quedaba en 1.03:1 contra el fondo
   oscuro — negro sobre negro. El texto se leía perfecto y todo lo que es
   acento (precios, kickers, botones, nav activa) desaparecía.

   La sintaxis de color relativo permite CLAMPEAR la luminosidad sin tocar el
   tono de la marca. Va detrás de `@supports` para que un browser viejo se
   quede con la mezcla de arriba, que ya es correcta para un color medio.
   No se corrige el dato del dueño: se hace que cualquier dato suyo se vea. */
@supports (color: oklch(from red l c h)) {
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]):not(.light) {
      --lt-accent:        oklch(from var(--sf-primary, #b4552a) clamp(.66, l, .86) max(c, .045) h);
      --lt-accent-strong: oklch(from var(--sf-primary, #b4552a) clamp(.76, calc(l + .10), .92) max(c, .045) h);
    }
  }
  :root[data-theme="dark"],
  :root.dark {
    --lt-accent:        oklch(from var(--sf-primary, #b4552a) clamp(.66, l, .86) max(c, .045) h);
    --lt-accent-strong: oklch(from var(--sf-primary, #b4552a) clamp(.76, calc(l + .10), .92) max(c, .045) h);
  }
}
/* <<< FIN CSS PROPIO <<< */

/* ── storefront/css/_kpi_strip.css ── */
/* ==========================================================================
 * _kpi_strip.css — TIRA DE KPIs DEL KERNEL (S25 / S29)
 * --------------------------------------------------------------------------
 * Primitivas: .sf-kpi-grid (grilla de una sola linea), .sf-stat-card (KPI con
 * icono, del widget kernel `_widgets/_stat_card.html`) y .sf-stat-mini
 * (variante compacta para la tira de resumen de los listados).
 *
 * POR QUE ESTE ARCHIVO EXISTE (IT76, 2026-07-28)
 * ---------------------------------------------
 * Estas reglas vivian dentro de `_components.css`, que SOLO se carga en el
 * storefront (`base_storefront.html`). Pero sus consumidores estan todos del
 * otro lado: el widget kernel `_widgets/_stat_card.html` y 9 paginas del
 * app-shell (POS comprobantes / NCE / cuentas corrientes / DTE / dashboards,
 * CRM analytics). Resultado: el markup se emitia correcto y el browser no
 * encontraba NI UNA de las reglas — KPIs sin card, sin acento, sin grilla,
 * apilados en vertical. Un fallo silencioso: no rompe, se ve pobre.
 *
 * La doctrina S29 declara `.sf-kpi-grid` como el grid canonico de KPIs y
 * prohibe re-declarar grillas por vertical; era imposible de cumplir mientras
 * la clase no existiera en el shell donde viven los verticales.
 *
 * Fuente UNICA: este archivo. Lo cargan los DOS shells —
 * `layouts/app_shell.html` (verticales) y `storefront/base_storefront.html`
 * (tienda publica). No copiar estas reglas a ningun otro stylesheet.
 * Guard: apps/core/ui/tests/test_kernel_css_reachable.py
 * ========================================================================== */

/* ============================================================
 * Stat card KPI premium (_widgets/_stat_card.html) — S25 kernel
 * ============================================================ */
/* Densidad enterprise (IT46/IT47): compacto sin perder jerarquia
   premium — acento, burbuja gradient, tabular nums y hover elevation
   se conservan. El grid canonico es .sf-kpi-grid (S29, prohibido
   re-declarar grids de KPIs por vertical).
   IT47 (pedido del usuario): los KPIs van SIEMPRE en UNA sola linea —
   grid-auto-flow column reparte 1fr por card sin importar cuantas
   haya ni el ancho efectivo (notebooks con zoom incluidos); el valor
   se auto-escala con clamp(). En mobile (<768px) una linea de 6 seria
   ilegible: cae a grilla de 2 columnas. */
.sf-kpi-grid {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: minmax(0, 1fr);
    gap: .65rem;
}
@media (max-width: 767px) {
    .sf-kpi-grid {
        grid-auto-flow: row;
        grid-auto-columns: unset;
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}
@media (min-width: 1920px) {
    .sf-kpi-grid { gap: .8rem; }
}
/* Variante COMPACTA (S29.1, pedido del dueño 2026-08-22): los KPIs de la
   FICHA de un registro entran DENTRO de la tarjeta de identidad como
   franja — sin card propia ni sombra, valor menor. Asi identidad +
   analisis ocupan UNA sola seccion. Opt-in del widget kernel:
   {% include "_widgets/_kpi_row.html" with ... kpi_compact=True %}. */
.sf-kpi-grid--compact { gap: .35rem 1.25rem; }
/* Posicion LATERAL (pedido del dueño 2026-08-22): la franja compacta se
   ancla al lado DERECHO de la tarjeta de identidad de la ficha — foto y
   nombre a la izquierda, analisis a la derecha, una sola seccion. En
   angosto (la tarjeta envuelve) cae debajo a lo ancho con divisor. */
.sf-kpi-side { margin-left: auto; align-self: center; }
.sf-kpi-side .sf-kpi-grid--compact {
    grid-auto-columns: max-content;
    gap: .3rem 1.6rem;
}
.sf-kpi-side .vet-premium-mini-card__value { font-size: 1.1rem; margin-top: .15rem; }
.sf-kpi-side .vet-premium-mini-card__label { font-size: .6rem; }
.sf-kpi-side .vet-premium-mini-card__meta { font-size: .65rem; }
@media (min-width: 1024px) {
    .sf-kpi-side {
        border-left: 1px solid var(--sf-color-border, #e2e8f0);
        padding-left: 1.75rem;
    }
    .dark .sf-kpi-side { border-left-color: #334155; }
}
@media (max-width: 1023px) {
    .sf-kpi-side {
        width: 100%;
        margin-top: .75rem;
        padding-top: .75rem;
        border-top: 1px solid var(--sf-color-border, #e2e8f0);
    }
    .dark .sf-kpi-side { border-top-color: #334155; }
}
.sf-kpi-grid--compact .vet-premium-mini-card {
    background: transparent;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    padding: .1rem 0;
}
.sf-kpi-grid--compact .vet-premium-mini-card__value {
    font-size: clamp(1.05rem, 1.3vw, 1.4rem);
    margin-top: .2rem;
}
.sf-kpi-grid--compact .vet-premium-mini-card__meta { margin-top: .1rem; }

/* ============================================================
 * Card de KPI del widget `_widgets/_kpi_row.html` (IT276)
 * ------------------------------------------------------------
 * La anatomia de esta card vivia en `static/css/styles.css` como
 * `.vet-premium-mini-card`: el nombre de UN vertical para la card que
 * usan los 9+, con hex fijos (#0f172a / #64748b / #94a3b8), padding
 * 1.25rem y un valor de 1.75rem FIJO. Dos sintomas visibles en
 * cualquier pantalla con importes — vistos en restaurante/sala:
 *   · «Gs. 3.342.000» partido en dos renglones («Gs.» arriba, la cifra
 *     abajo), porque el tamaño era fijo y el texto lo unico elastico.
 *   · cards de ~155px de alto para mostrar un numero, con ~60px de aire
 *     muerto (S29.1: la densidad es kernel-owned, no se agranda ni se
 *     hereda de una card de detalle).
 * Se declara ACA, junto al grid canonico y con la misma anatomia que
 * `.sf-stat-card`. La clase legacy sigue en el markup como alias
 * mientras queden consumidores fuera del widget.
 * ============================================================ */
.sf-kpi-card {
    min-width: 0;
    background: var(--sf-color-bg-elevated, #fff);
    border: 1px solid var(--sf-color-border, #e2e8f0);
    border-radius: .875rem;
    padding: .7rem .85rem;
    box-shadow: 0 1px 2px rgb(15 23 42 / .04);
}
.sf-kpi-card__label {
    font-size: .62rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: .09em;
    color: var(--sf-color-text-muted, #64748b);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* El valor NO parte de renglon: es la cifra que se lee de un vistazo, y
   «Gs.» solo arriba de su numero no es una jerarquia, es un accidente.
   clamp() lo achica ANTES de romper; tabular-nums alinea las columnas
   de importes entre cards vecinas. */
.sf-kpi-card__value {
    margin-top: .2rem;
    font-size: clamp(1.05rem, .78rem + .55vw, 1.45rem);
    font-weight: 800;
    line-height: 1.15;
    color: var(--sf-color-text, #0f172a);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.sf-kpi-card__meta {
    margin-top: .1rem;
    font-size: .68rem;
    color: var(--sf-color-text-muted, #94a3b8);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* Variantes ya existentes del grid, con la clase kernel. */
.sf-kpi-grid--compact .sf-kpi-card {
    background: transparent;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    padding: .1rem 0;
}
.sf-kpi-grid--compact .sf-kpi-card__value {
    font-size: clamp(1.05rem, 1.3vw, 1.4rem);
    margin-top: .2rem;
}
.sf-kpi-grid--compact .sf-kpi-card__meta { margin-top: .1rem; }
.sf-kpi-side .sf-kpi-card__value { font-size: 1.1rem; margin-top: .15rem; }
.sf-kpi-side .sf-kpi-card__label { font-size: .6rem; }
.sf-kpi-side .sf-kpi-card__meta { font-size: .65rem; }
.sf-stat-card {
    position: relative;
    overflow: hidden;
    min-width: 0;
    background: var(--sf-color-bg-elevated, #fff);
    border: 1px solid var(--sf-color-border, #e2e8f0);
    border-radius: .875rem;
    padding: .8rem .85rem;
    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
    transition: box-shadow .2s ease, transform .2s ease;
}
.sf-stat-card:hover {
    box-shadow: 0 8px 20px -10px rgba(15, 23, 42, 0.18);
    transform: translateY(-1px);
}
.sf-stat-card__accent {
    position: absolute;
    inset: 0 0 auto 0;
    height: 3px;
    background: var(--sf-color-primary, #0ea5e9);
}
.sf-stat-card--emerald .sf-stat-card__accent { background: #10b981; }
.sf-stat-card--blue    .sf-stat-card__accent { background: #3b82f6; }
.sf-stat-card--amber   .sf-stat-card__accent { background: #f59e0b; }
.sf-stat-card--rose    .sf-stat-card__accent { background: #f43f5e; }
.sf-stat-card--indigo  .sf-stat-card__accent { background: #6366f1; }
.sf-stat-card--slate   .sf-stat-card__accent { background: #94a3b8; }
.sf-stat-card__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .5rem;
    margin-bottom: .4rem;
    min-width: 0;
}
.sf-stat-card__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.85rem;
    height: 1.85rem;
    border-radius: .6rem;
    font-size: .8rem;
    color: #fff;
}
.sf-stat-card--emerald .sf-stat-card__icon { background: linear-gradient(135deg,#10b981,#059669); }
.sf-stat-card--blue    .sf-stat-card__icon { background: linear-gradient(135deg,#3b82f6,#2563eb); }
.sf-stat-card--amber   .sf-stat-card__icon { background: linear-gradient(135deg,#f59e0b,#d97706); }
.sf-stat-card--rose    .sf-stat-card__icon { background: linear-gradient(135deg,#f43f5e,#e11d48); }
.sf-stat-card--indigo  .sf-stat-card__icon { background: linear-gradient(135deg,#6366f1,#4f46e5); }
.sf-stat-card--slate   .sf-stat-card__icon { background: linear-gradient(135deg,#94a3b8,#64748b); }
.sf-stat-card__trend {
    display: inline-flex;
    align-items: center;
    gap: .25rem;
    font-size: .62rem;
    font-weight: 700;
    padding: .15rem .45rem;
    border-radius: 999px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
}
.sf-stat-card__trend--up   { color: #047857; background: rgba(16,185,129,.12); }
.sf-stat-card__trend--down { color: #be123c; background: rgba(244,63,94,.12); }
.sf-stat-card__trend--flat { color: var(--sf-color-text-muted,#64748b); background: rgba(148,163,184,.14); }
.sf-stat-card__label {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    font-size: .66rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--sf-color-text-muted, #64748b);
}
.sf-stat-card__value {
    margin-top: .1rem;
    font-size: clamp(1rem, .55rem + .9vw, 1.3rem);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    font-weight: 800;
    line-height: 1.1;
    letter-spacing: -.01em;
    font-variant-numeric: tabular-nums;
    color: var(--sf-color-text, #0f172a);
}
.sf-stat-card__meta {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    margin-top: .15rem;
    font-size: .68rem;
    color: var(--sf-color-text-muted, #64748b);
}

/* ============================================================
 * Stat MINI (IT48, S29) — tira de resumen compacta para listados
 * (Total / Pagados / Pendientes / ...). Variante liviana de
 * .sf-stat-card (sin icono) para usar DENTRO de .sf-kpi-grid.
 * Tono via modificador --{emerald|blue|amber|rose|indigo|slate}
 * (barra de acento izquierda + label tintado).
 * ============================================================ */
.sf-stat-mini {
    position: relative;
    min-width: 0;
    overflow: hidden;
    background: var(--sf-color-bg-elevated, #fff);
    border: 1px solid var(--sf-color-border, #e2e8f0);
    border-radius: .7rem;
    padding: .5rem .65rem .5rem .8rem;
}
.sf-stat-mini::before {
    content: "";
    position: absolute;
    inset: 0 auto 0 0;
    width: 3px;
    background: var(--sf-mini-accent, #94a3b8);
}
.sf-stat-mini__label {
    font-size: .6rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--sf-color-text-muted, #64748b);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.sf-stat-mini__value {
    margin-top: .15rem;
    font-size: clamp(.9rem, .5rem + .6vw, 1.1rem);
    font-weight: 800;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    color: var(--sf-color-text, #0f172a);
}
/* IT270 — linea de contexto bajo el valor (comparativo, periodo, conteo).
 * La primitiva tenia label + valor: un KPI de cartera que dice "Gs 4.100.000"
 * sin decir "sobre 12 cuentas" obliga a bajar a la tabla para entenderlo. */
.sf-stat-mini__meta {
    margin-top: .15rem;
    font-size: .62rem;
    font-weight: 600;
    line-height: 1.25;
    color: var(--sf-color-text-muted, #64748b);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.sf-stat-mini--emerald { --sf-mini-accent: #10b981; }
.sf-stat-mini--blue    { --sf-mini-accent: #3b82f6; }
.sf-stat-mini--amber   { --sf-mini-accent: #f59e0b; }
.sf-stat-mini--rose    { --sf-mini-accent: #f43f5e; }
.sf-stat-mini--indigo  { --sf-mini-accent: #6366f1; }
.sf-stat-mini--slate   { --sf-mini-accent: #94a3b8; }
.sf-stat-mini--violet  { --sf-mini-accent: #8b5cf6; }
.sf-stat-mini--emerald .sf-stat-mini__label { color: #059669; }
.sf-stat-mini--blue    .sf-stat-mini__label { color: #2563eb; }
.sf-stat-mini--amber   .sf-stat-mini__label { color: #b45309; }
.sf-stat-mini--rose    .sf-stat-mini__label { color: #be123c; }
.sf-stat-mini--indigo  .sf-stat-mini__label { color: #4f46e5; }
.sf-stat-mini--violet  .sf-stat-mini__label { color: #7c3aed; }
.dark .sf-stat-mini--emerald .sf-stat-mini__label,
html[data-theme="dark"] .sf-stat-mini--emerald .sf-stat-mini__label { color: #34d399; }
.dark .sf-stat-mini--blue .sf-stat-mini__label,
html[data-theme="dark"] .sf-stat-mini--blue .sf-stat-mini__label { color: #60a5fa; }
.dark .sf-stat-mini--amber .sf-stat-mini__label,
html[data-theme="dark"] .sf-stat-mini--amber .sf-stat-mini__label { color: #fbbf24; }
.dark .sf-stat-mini--rose .sf-stat-mini__label,
html[data-theme="dark"] .sf-stat-mini--rose .sf-stat-mini__label { color: #fb7185; }
.dark .sf-stat-mini--indigo .sf-stat-mini__label,
html[data-theme="dark"] .sf-stat-mini--indigo .sf-stat-mini__label { color: #a5b4fc; }
.dark .sf-stat-mini--violet .sf-stat-mini__label,
html[data-theme="dark"] .sf-stat-mini--violet .sf-stat-mini__label { color: #c4b5fd; }

/* ============================================================
 * Primitivas dataviz CSS-only (IT89, 2026-08-01) — S25/S29
 * ------------------------------------------------------------
 * .sf-stackbar  barra apilada de composicion (segmentos categoricos)
 * .sf-hbar      barra horizontal rotulada (una medida, un tono)
 * .sf-meter     medida vs umbral (bullet: fill + marker de piso)
 *
 * Reglas (skill dataviz): marcas finas, data-end redondeado 4px,
 * spacer 2px entre segmentos, texto SIEMPRE en tinta (--sf-color-text*),
 * colores de serie SOLO tokens --sf-viz-* (categorica validada CVD
 * light+dark). Anchos data-driven: PROHIBIDO style= inline (CSP) —
 * la pagina genera clases de ancho en su <style nonce>.
 * ============================================================ */
.sf-stackbar {
    display: flex;
    height: 14px;
    border-radius: 4px;
    overflow: hidden;
    background: var(--sf-viz-grid, #e2e8f0);
}
.sf-stackbar__seg { height: 100%; min-width: 2px; }
.sf-stackbar__seg + .sf-stackbar__seg {
    border-left: 2px solid var(--sf-color-bg-elevated, #fff);
}
.sf-viz-fill-1 { background: var(--sf-viz-1, #2a78d6); }
.sf-viz-fill-2 { background: var(--sf-viz-2, #eb6834); }
.sf-viz-fill-3 { background: var(--sf-viz-3, #1baf7a); }
.sf-viz-fill-4 { background: var(--sf-viz-4, #eda100); }

/* Barra apilada SERVER-SIDE (IT273) — la usa `_widgets/_stacked_bar.html`
 * sobre `charts.stacked_bar_svg`. El envoltorio pone el radio de 4px y
 * recorta: asi los data-ends quedan redondeados y los cortes internos
 * rectos, sin que el `rx` de cada rect se deforme con el escalado
 * horizontal del viewBox. El fondo se ve por los huecos de 3 unidades que
 * el renderer deja entre tramos (spacer de superficie, no un borde). */
.sf-stackbar-wrap {
    border-radius: 4px;
    overflow: hidden;
    background: var(--sf-viz-grid, #e2e8f0);
    line-height: 0;
}
.sf-stackbar-svg { display: block; width: 100%; }
.sf-legend--stack { gap: .35rem .9rem; }
.sf-legend--stack .sf-legend__item { gap: .35rem; }

.sf-legend {
    display: flex; flex-wrap: wrap;
    gap: .35rem 1.1rem;
    margin-top: .5rem;
    font-size: .72rem;
    color: var(--sf-color-text-muted, #64748b);
}
.sf-legend__item { display: inline-flex; align-items: center; gap: .4rem; min-width: 0; }
.sf-legend__swatch { width: .65rem; height: .65rem; border-radius: 3px; flex: none; }
.sf-legend__value {
    color: var(--sf-color-text, #0f172a);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.sf-hbar-list { display: block; }
.sf-hbar {
    display: grid;
    grid-template-columns: minmax(7rem, 12rem) 1fr auto;
    align-items: center;
    gap: .6rem;
}
.sf-hbar + .sf-hbar { margin-top: .45rem; }
.sf-hbar__label {
    font-size: .78rem;
    color: var(--sf-color-text-muted, #64748b);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sf-hbar__track {
    display: block;
    height: 10px;
    border-radius: 4px;
    background: var(--sf-viz-grid, #e2e8f0);
    overflow: hidden;
    min-width: 0;
}
.sf-hbar__fill {
    display: block;
    height: 100%;
    border-radius: 0 4px 4px 0;
    background: var(--sf-viz-1, #2a78d6);
}
.sf-hbar__value {
    font-size: .78rem; font-weight: 600;
    color: var(--sf-color-text, #0f172a);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.sf-hbar__sub { color: var(--sf-color-text-muted, #64748b); font-weight: 400; }

.sf-meter { position: relative; height: 14px; border-radius: 4px; background: var(--sf-viz-grid, #e2e8f0); }
.sf-meter__fill {
    position: absolute; top: 0; bottom: 0; left: 0;
    border-radius: 4px;
    background: var(--sf-color-success, #059669);
}
.sf-meter--breach .sf-meter__fill { background: var(--sf-color-danger, #dc2626); }
/* Tonos explicitos (IT270): `--breach` es binario (paso/no paso el umbral) y
 * no alcanza cuando la medida tiene BANDAS — food cost 28% es bueno, 34%
 * atendible y 47% sangra margen. Los tres tonos salen de los tokens del
 * sistema, asi que flipean solos en dark. */
.sf-meter--success .sf-meter__fill { background: var(--sf-color-success, #059669); }
.sf-meter--warning .sf-meter__fill { background: var(--sf-color-warning, #d97706); }
.sf-meter--danger  .sf-meter__fill { background: var(--sf-color-danger, #dc2626); }
.sf-meter--neutral .sf-meter__fill { background: var(--sf-color-border-strong, #94a3b8); }
.sf-meter__marker {
    position: absolute; top: -3px; bottom: -3px;
    width: 2px;
    background: var(--sf-color-text, #0f172a);
}
/* Posicion del marcador SIN escala nueva (IT270): el envoltorio toma el
 * ancho de la escala kernel `.sf-fill--pN` y el marcador se apoya en su
 * borde derecho. Antes cada pantalla que queria un umbral se fabricaba un
 * `left:` propio en un `<style nonce>` local (`propuestas`), que es
 * exactamente lo que la escala vino a eliminar. `pointer-events:none` para
 * que el marcador no se coma el tooltip de la barra. */
.sf-meter__markerwrap {
    position: absolute; top: 0; bottom: 0; left: 0;
    pointer-events: none;
}
.sf-meter__markerwrap .sf-meter__marker { left: auto; right: 0; }
.sf-meter--compact { height: 6px; border-radius: 3px; }
.sf-meter--compact .sf-meter__fill { border-radius: 3px; }

/* Celda de tabla «valor + barra» (IT271) — la anatomia del tipo de celda
 * `meter` de `components/tables/_cell.html`. Densidad kernel-owned (S29.1):
 * ninguna pantalla vuelve a decidir el alto de la barra ni el tamano del
 * numero. El ancho de la barra queda acotado para que la columna no se
 * estire en tablas anchas y siga leyendose en notebook. */
/* Anatomias de celda hermanas de `.sf-cellmeter` (IT273) — las renderiza
 * `components/tables/_cell.html` y su densidad es kernel-owned (S29.1):
 * ninguna pantalla vuelve a decidir el tamano del swatch ni el de la
 * segunda linea.
 *   .sf-cellkey     clave de serie: swatch + icono + rotulo. Es la fila de
 *                   la tabla que ES la leyenda de un grafico, asi que el
 *                   swatch mide lo mismo que el de `.sf-legend__swatch`.
 *   .sf-cellentity  sujeto en dos lineas: nombre + dato de contexto.
 *   .sf-num         columna de numeros: cifras de ancho fijo para que la
 *                   coma caiga en la misma vertical en toda la columna
 *                   (tabular SOLO en columnas — un valor grande suelto va
 *                   con figuras proporcionales, skill dataviz).
 */
.sf-cellkey { display: inline-flex; align-items: center; gap: .45rem; font-weight: 600; }
.sf-cellkey__swatch {
    width: .65rem; height: .65rem;
    border-radius: 3px;
    flex: none;
    display: inline-block;
}
.sf-cellentity { display: flex; flex-direction: column; gap: .1rem; min-width: 0; }
.sf-cellentity__label {
    font-weight: 600;
    color: var(--sf-color-text, #0f172a);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sf-cellentity__meta {
    font-size: .7rem;
    color: var(--sf-color-text-muted, #64748b);
}
.sf-cellentity__link { color: inherit; text-decoration: none; }
.sf-cellentity__link:hover { text-decoration: underline; }
/* La fila entera navega (handler en table-actions.js): el cursor lo tiene
   que decir, o el atajo existe y nadie lo descubre. */
tr[data-row-url] { cursor: pointer; }
.sf-num { font-variant-numeric: tabular-nums; }
.sf-num--strong { font-variant-numeric: tabular-nums; font-weight: 600; }

.sf-cellmeter { display: flex; flex-direction: column; gap: .22rem; min-width: 7.5rem; }
.sf-cellmeter--right { align-items: flex-end; }
.sf-cellmeter__value {
    font-size: .82rem; font-weight: 700;
    color: var(--sf-color-text, #0f172a);
    font-variant-numeric: tabular-nums; line-height: 1.1;
}
.sf-cellmeter .sf-meter { width: 100%; max-width: 8.5rem; }
.sf-cellmeter__hint {
    font-size: .66rem; color: var(--sf-color-text-muted, #64748b);
    line-height: 1.2;
}
.sf-meter__scale {
    display: flex; justify-content: space-between;
    margin-top: .3rem;
    font-size: .68rem;
    color: var(--sf-color-text-muted, #64748b);
    font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------
 * Leyenda en PILDORAS (IT264) — variante de `.sf-legend` para
 * conteos por ESTADO (no por serie de un chart): «Libre 8 ·
 * Ocupada 5 · Limpieza 1». El punto toma el tono del sistema
 * (`.sf-tone--<tono>`, capa de tokens), asi que nunca vuelve a
 * necesitar un hex por vertical.
 * ------------------------------------------------------------ */
.sf-legend--pills { gap: .4rem; margin-top: 0; }
.sf-legend--pills .sf-legend__item {
    gap: .35rem;
    padding: .28rem .65rem;
    border-radius: 999px;
    background: var(--sf-color-bg-elevated, #fff);
    border: 1px solid var(--sf-color-border, #e2e8f0);
    font-weight: 600;
}
.sf-legend__dot {
    width: .5rem;
    height: .5rem;
    border-radius: 999px;
    flex: none;
    background: var(--sf-tone, var(--sf-color-border-strong, #94a3b8));
}

/* ------------------------------------------------------------
 * Anchos data-driven CSP-safe (IT264).
 * El bloque de dataviz de arriba documenta que `style=` inline esta
 * PROHIBIDO (CSP con nonce lo bloquea) y delegaba en que «la pagina
 * genera clases de ancho en su <style nonce>» — es decir, cada
 * pantalla se fabricaba su propia escala. Esta escala fija de 5% es
 * kernel-owned: la pagina redondea el porcentaje y elige la clase.
 * Sirve para .sf-meter__fill, .sf-hbar__fill y .sf-stackbar__seg.
 * ------------------------------------------------------------ */
.sf-fill--p0   { width: 0; }
.sf-fill--p5   { width: 5%; }
.sf-fill--p10  { width: 10%; }
.sf-fill--p15  { width: 15%; }
.sf-fill--p20  { width: 20%; }
.sf-fill--p25  { width: 25%; }
.sf-fill--p30  { width: 30%; }
.sf-fill--p35  { width: 35%; }
.sf-fill--p40  { width: 40%; }
.sf-fill--p45  { width: 45%; }
.sf-fill--p50  { width: 50%; }
.sf-fill--p55  { width: 55%; }
.sf-fill--p60  { width: 60%; }
.sf-fill--p65  { width: 65%; }
.sf-fill--p70  { width: 70%; }
.sf-fill--p75  { width: 75%; }
.sf-fill--p80  { width: 80%; }
.sf-fill--p85  { width: 85%; }
.sf-fill--p90  { width: 90%; }
.sf-fill--p95  { width: 95%; }
.sf-fill--p100 { width: 100%; }

/* ── storefront/css/_social_links.css ── */
/* ==========================================================================
   `.sf-social*` — bloque «Seguinos en nuestras redes» (IT270)
   --------------------------------------------------------------------------
   Fuente UNICA del patron. Archivo propio (mismo criterio que `_notes.css`
   y `_kpi_strip.css`, IT265/IT76): lo consumen la tienda publica
   (`_components.css`) y el app-shell (`_app_components.css`), y una sola
   definicion evita que las dos copias driftien.

   Markup: `templates/_widgets/_redes_sociales.html`.
   Datos:  `apps/core/configuracion/services/branding.py::redes_del_tenant`.

   Reglas que respeta:
   - Solo tokens `--sf-*` — cero hex sueltos fuera de los colores de MARCA
     de cada red (esos son de Meta/ByteDance, no del design system, y son
     los mismos en los dos temas).
   - Cero `@media (prefers-color-scheme)` propio: los tokens ya flipean.
     La variante `--invert` es dark-BY-DESIGN (el pie de la tienda es una
     inversion deliberada), asi que ahi la tinta va fija a proposito.
   ========================================================================== */

.sf-social {
    min-width: 0;
}

.sf-social__title {
    margin: 0 0 var(--sf-space-2, 0.5rem);
    font-size: var(--sf-font-overline, 0.625rem);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: var(--sf-tracking-wider, 0.12em);
    color: var(--sf-color-text-muted, #475569);
}

.sf-social__text {
    margin: 0 0 var(--sf-space-3, 0.75rem);
    font-size: var(--sf-font-caption, 0.75rem);
    line-height: var(--sf-leading-relaxed, 1.65);
    color: var(--sf-color-text-muted, #475569);
}

.sf-social__list {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sf-space-2, 0.5rem);
    margin: 0;
    padding: 0;
    list-style: none;
}

.sf-social__link {
    /* `--sf-social-brand` la define cada modificador de red. El fallback
       es el primario del tenant: si alguna vez se suma una red nueva sin
       color propio, hereda la marca de la tienda en vez de quedar gris. */
    --sf-social-brand: var(--sf-color-primary);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--sf-space-2, 0.5rem);
    height: 2.25rem;
    width: 2.25rem;
    border-radius: var(--sf-radius-md, 8px);
    border: 1px solid var(--sf-color-border, #e2e8f0);
    background: var(--sf-color-bg-elevated, #f8fafc);
    color: var(--sf-color-text-muted, #475569);
    text-decoration: none;
    transition:
        background var(--sf-motion-fast, 150ms) ease,
        border-color var(--sf-motion-fast, 150ms) ease,
        color var(--sf-motion-fast, 150ms) ease,
        transform var(--sf-motion-fast, 150ms) ease;
}

/* Variante con nombre al lado del icono (landings, fichas publicas). */
.sf-social__link--wide {
    width: auto;
    padding: 0 var(--sf-space-3, 0.75rem);
}

.sf-social__icon {
    height: 1rem;
    width: 1rem;
    flex: none;
}

.sf-social__label {
    font-size: var(--sf-font-body-sm, 0.875rem);
    font-weight: 600;
    line-height: 1;
}

.sf-social__link:hover,
.sf-social__link:focus-visible {
    background: color-mix(in srgb, var(--sf-social-brand) 14%, transparent);
    border-color: color-mix(in srgb, var(--sf-social-brand) 45%, transparent);
    color: var(--sf-social-brand);
    transform: translateY(-1px);
}

.sf-social__link:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--sf-social-brand) 28%, transparent);
}

.sf-social__link:active {
    transform: none;
}

/* Colores de marca de cada red (constantes, no del design system). */
.sf-social__link--whatsapp  { --sf-social-brand: #25d366; }
.sf-social__link--facebook  { --sf-social-brand: #1877f2; }
.sf-social__link--instagram { --sf-social-brand: #e1306c; }
.sf-social__link--tiktok    { --sf-social-brand: #25f4ee; }

/* --------------------------------------------------------------------------
   Variante `--invert`: superficies dark-BY-DESIGN (el pie de la tienda).
   La tinta NO sigue al tema — igual criterio que `.sf-footer .sf-ink-muted`:
   en modo claro `--sf-color-text-muted` es slate oscuro y los iconos
   desaparecian sobre el fondo negro del pie.
   -------------------------------------------------------------------------- */
.sf-social--invert .sf-social__title { color: #ffffff; }
.sf-social--invert .sf-social__text { color: #94a3b8; }

.sf-social--invert .sf-social__link {
    border-color: transparent;
    background: color-mix(in srgb, var(--sf-pal-surface, #94a3b8) 14%, transparent);
    color: rgb(255 255 255 / 0.72);
}

.sf-social--invert .sf-social__link:hover,
.sf-social--invert .sf-social__link:focus-visible {
    background: color-mix(in srgb, var(--sf-social-brand) 34%, transparent);
    border-color: transparent;
    color: #ffffff;
}

@media (prefers-reduced-motion: reduce) {
    .sf-social__link { transition: none; }
    .sf-social__link:hover,
    .sf-social__link:focus-visible { transform: none; }
}

/* ── storefront/css/_theme_toggle.css ── */
/* ==========================================================================
   `.sf-theme-toggle` — boton kernel de modo claro/oscuro (IT274)
   --------------------------------------------------------------------------
   Archivo propio y chico (patron `_social_links.css`) porque lo necesitan
   documentos que NO cargan `_components.css`: `/bio/` y la pantalla de
   mantenimiento son standalone a proposito y no pueden pagar 42 KB por un
   boton de 36 px.

   Solo tokens `--sf-*`: el mismo boton se ve correcto en los dos temas sin
   una sola regla `@media prefers-color-scheme` propia.
   Markup: `templates/_widgets/_theme_toggle.html`.
   ========================================================================== */

.sf-theme-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--sf-space-2, 0.5rem);
    /* 2.25rem = 36px. Es un control secundario: no compite con el contenido,
       pero el area tactil llega a 44px con el padding del contenedor. */
    height: 2.25rem;
    min-width: 2.25rem;
    padding: 0 0.6rem;
    border-radius: var(--sf-radius-full, 9999px);
    border: 1px solid var(--sf-color-border);
    background: var(--sf-color-bg-elevated);
    color: var(--sf-color-text-muted);
    font-family: inherit;
    font-size: var(--sf-font-body-sm, 0.875rem);
    line-height: 1;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    transition:
        background-color var(--sf-motion-fast, 150ms) var(--sf-ease-out, ease),
        border-color var(--sf-motion-fast, 150ms) ease,
        color var(--sf-motion-fast, 150ms) ease,
        transform var(--sf-motion-fast, 150ms) ease;
}

.sf-theme-toggle:hover {
    color: var(--sf-color-text);
    border-color: var(--sf-color-border-strong);
}

.sf-theme-toggle:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--sf-color-primary) 32%, transparent);
    border-color: var(--sf-color-primary);
}

.sf-theme-toggle:active {
    transform: scale(0.94);
}

.sf-theme-toggle__icon {
    font-size: 0.9375rem;
}

.sf-theme-toggle__label {
    white-space: nowrap;
}

/* Variante «cuadrada»: para filas de acciones donde los vecinos ya son
   botones de esquina redondeada (el header de la tienda). Un circulo en
   medio de cuatro cuadrados se lee como un control de otro sistema. */
.sf-theme-toggle--square {
    border-radius: var(--sf-radius-md, 0.5rem);
    padding: 0;
    width: 2.25rem;
}

/* Variante para superficies con gradiente/imagen detras: el borde solo no
   alcanza a separarlo del fondo. */
.sf-theme-toggle--solid {
    background: color-mix(in srgb, var(--sf-color-bg-elevated) 82%, transparent);
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
    box-shadow: var(--sf-shadow-sm);
}

@media (prefers-reduced-motion: reduce) {
    .sf-theme-toggle { transition: none; }
    .sf-theme-toggle:active { transform: none; }
}

/* ── storefront/css/_accessibility.css ── */
/* ============================================================
   STOREFRONT V2 — ACCESIBILIDAD (Sprint UX-1, §4.6)
   ------------------------------------------------------------
   Reglas WCAG 2.1 AA no negociables del storefront.
   Complementa el skip-link y reduced-motion ya en base.

   Coverage:
   - Screen-reader-only utilities (`sf-sr-only`, `sf-not-sr-only`).
   - Focus-visible ring consistente (color del brand del tenant).
   - `prefers-reduced-motion` mas agresivo (sobre _components.css).
   - High-contrast mode hooks.
   - Touch target minimo 44x44 (WCAG 2.5.5 Target Size).
   ============================================================ */

/* ============================================================
   SCREEN-READER ONLY
   Para texto que solo deben leer lectores de pantalla
   (instrucciones, labels invisibles, etc.).
   ============================================================ */
.sf-sr-only {
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  padding: 0 !important;
  margin: -1px !important;
  overflow: hidden !important;
  clip: rect(0, 0, 0, 0) !important;
  white-space: nowrap !important;
  border: 0 !important;
}

/* Permite restaurar visibilidad al recibir focus (skip-links). */
.sf-not-sr-only {
  position: static !important;
  width: auto !important;
  height: auto !important;
  padding: 0 !important;
  margin: 0 !important;
  overflow: visible !important;
  clip: auto !important;
  white-space: normal !important;
}

/* ============================================================
   FOCUS-VISIBLE — anillo consistente
   Aplicado a elementos interactivos. Usa color brand del tenant.
   ============================================================ */
:focus-visible {
  outline: 2px solid var(--sf-color-primary);
  outline-offset: 2px;
  border-radius: var(--sf-radius-sm);
}

/* Botones / links del storefront con focus ring extendido */
a:focus-visible,
button:focus-visible,
[role="button"]:focus-visible,
[tabindex]:focus-visible {
  box-shadow: var(--sf-shadow-focus);
}

/* No mostrar outline en mouse, solo teclado (default browser behavior
   pero algunos botones lo sobreescriben — reforzamos). */
:focus:not(:focus-visible) {
  outline: none;
}

/* ============================================================
   SKIP-LINK — refuerzo de la version ya existente
   sf-skip-link ya esta en tailwind.src.css con @apply.
   Aqui solo agregamos color brand y motion para que el slide
   del skip-link respete el design system.
   ============================================================ */
.sf-skip-link:focus {
  background: var(--sf-color-primary) !important;
  color: var(--sf-color-primary-fg) !important;
}

/* ============================================================
   REDUCED MOTION — gate global
   prefers-reduced-motion ya esta cubierto parcialmente en
   base_storefront.html, pero aqui lo agresivamos para que
   tambien apague animaciones del design system V2.
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  /* Cancelar skeleton shimmer (incomodo con reduced motion) */
  .sf-skeleton {
    animation: none !important;
    background: var(--sf-color-bg-subtle);
  }
  /* Cancelar pulse del badge-discount */
  .sf-badge-discount {
    animation: none !important;
  }
}

/* ============================================================
   HIGH-CONTRAST MODE (Windows / forced-colors)
   Algunos navegadores aplican un modo de contraste forzado;
   garantizamos que botones y bordes sigan siendo legibles.
   ============================================================ */
@media (forced-colors: active) {
  .sf-btn-danger,
  .sf-btn-success,
  .sf-badge,
  .sf-badge-discount,
  .sf-badge-new {
    border: 1px solid CanvasText;
  }
  :focus-visible {
    outline: 2px solid Highlight !important;
  }
}

/* ============================================================
   TOUCH TARGET MIN — WCAG 2.5.5 (Level AAA, recomendado)
   Botones / links de UI deben tener minimo 44x44 px para
   tactil. Aplicado solo a elementos marcados explicitamente
   con [data-sf-touch] para no afectar links inline de texto.
   ============================================================ */
[data-sf-touch],
.sf-touch-target {
  min-width: 44px;
  min-height: 44px;
}

/* ============================================================
   ARIA LIVE REGIONS — estilo visual neutral
   Para countdowns, toasts, cart-updates que deben ser anunciados.
   ============================================================ */
[aria-live="polite"],
[aria-live="assertive"] {
  /* Sin estilos visuales por default: solo posicionamiento por su
     contenedor. Mantenemos la regla aqui como anclaje semantico. */
}

/* ============================================================
   COLOR CONTRAST FALLBACKS
   Cuando text-muted aparece sobre bg-subtle, garantizamos
   ratio AA (4.5:1).
   ============================================================ */
.sf-surface-subtle .sf-caption,
.sf-surface-subtle .sf-overline {
  /* Forzar contraste minimo subiendo a text base si el fondo es subtle */
  color: var(--sf-color-text);
}

/* ============================================================
   PRINT MODE
   Ocultar UI no esencial al imprimir (carrito, toasts, ...).
   ============================================================ */
@media print {
  .sf-skip-link,
  [data-sf-toast-zone],
  #sf-toast-zone,
  [aria-hidden="true"] {
    display: none !important;
  }
  * {
    background: transparent !important;
    color: #000 !important;
    box-shadow: none !important;
  }
}

/* ── storefront/css/search.css ── */
/* Sprint UX-3 — Search bar HTMX autocomplete + results page layout.
 *
 * Depende de tokens definidos en `_design_tokens.css` (sf-color-*,
 * sf-space-*, sf-radius-*, sf-shadow-*, sf-z-*). Si una var no existe
 * en el config, hay fallback razonable para no romper render.
 */

/* ════════════ Search bar (input pill) ════════════
 * Elevacion IX/UI 2026-06-30: input pill fluido (escala con el viewport,
 * mantiene proporcion), icono lupa, glow de foco brand, spinner htmx.
 */

/* `display` SOLO desde md (auditoria 2026-07-25).
 *
 * `search.css` se carga DESPUES de tailwind.css y `.sf-searchbar` tiene la
 * misma especificidad que `.hidden` (0,1,0), asi que ganaba por orden de
 * fuente: el buscador se renderizaba en el header en CELULAR pese al
 * `hidden md:flex` del markup. Sus ~380px empujaban los iconos (wishlist,
 * tema, panel, menu) FUERA de la barra, y ademas quedaban dos buscadores
 * visibles (el del header y el del menu movil).
 *
 * El unico consumidor ya declara `md:flex items-center relative` por
 * utilidades, asi que acotar el display al breakpoint no le quita nada y deja
 * de pisar la utilidad.
 */
.sf-searchbar {
  position: relative;
  align-items: center;
  /* Sin esto un flex item no baja de su min-content: el buscador se plantaba
     en su piso de 14rem y lo que cedia era la MARCA, que llego a quedar en
     8px. En una tienda la identidad vale mas que 40px de input: el buscador
     es el elastico de la barra. */
  min-width: 0;
}

/* Cuando se muestra la barra de busqueda lo decide `.sf-only-wide` en
   `_components.css`, junto con el resto del header. Aca habia un
   `@media (min-width: 768px) { display: flex }` que competia con el
   `md:flex` del markup: dos duenos del mismo breakpoint, y este ganaba por
   orden de carga. Mover uno solo no arreglaba nada. */

.sf-searchbox {
  position: relative;
  width: clamp(14rem, 22vw, 22rem);
  /* El clamp es un deseo, no una exigencia: si la barra no da, cede. */
  max-width: 100%;
  /* Mismo radio que el input de adentro. El wrapper es estructura y no se
     pinta, pero en cuanto un tema le agrega fondo o sombra la diferencia de
     radio se ve como un rectangulo detras del pill. Que no puedan separarse
     es el punto del token. */
  border-radius: var(--sf-searchbox-radius);
}

/* Mobile / full-width (search del menú móvil, sin autocomplete). */
.sf-searchbox--block {
  width: 100%;
}

.sf-searchbox-icon {
  position: absolute;
  inset-block: 0;
  left: 0.85rem;
  display: flex;
  align-items: center;
  color: var(--sf-color-text-muted, rgb(100 116 139));
  pointer-events: none;
  transition: color 0.18s ease;
}

.sf-searchbox:focus-within .sf-searchbox-icon {
  color: var(--sf-color-primary, rgb(2 132 199));
}

.sf-searchbox-input {
  width: 100%;
  height: 2.6rem;
  padding: 0 2.5rem 0 2.5rem;
  font-size: 0.875rem;
  color: var(--sf-color-text, rgb(15 23 42));
  background: var(--sf-color-bg, #ffffff);
  /* El trazo del campo sale de `--sf-searchbox-border` (ver su nota en
     `_design_tokens.css`): el relleno del input y el fondo del header son el
     mismo tono en varios temas, asi que el limite es lo UNICO que dibuja el
     control. */
  border: 1px solid var(--sf-searchbox-border);
  border-radius: var(--sf-searchbox-radius);
  box-shadow: var(--sf-shadow-xs);
  transition: border-color 0.18s ease, box-shadow 0.18s ease, background-color 0.18s ease;
}

.sf-searchbox-input::placeholder {
  color: var(--sf-color-text-muted, rgb(148 163 184));
}

/* El reposo ya usa `border-strong`, asi que el hover tiene que ir un paso mas
   hacia la marca para seguir siendo una senal; el foco se queda con el
   primario pleno mas su anillo. */
.sf-searchbox-input:hover {
  border-color: color-mix(in srgb, var(--sf-color-primary) 55%, var(--sf-searchbox-border));
}

.sf-searchbox-input:focus {
  outline: none;
  border-color: var(--sf-color-primary, rgb(2 132 199));
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--sf-color-primary) 18%, transparent);
  background: var(--sf-color-bg-elevated, #ffffff);
}

/* Oculta la X nativa del type=search (usamos diseno propio del browser
 * solo cuando hay texto; el reset evita el doble control en algunos UA). */
.sf-searchbox-input::-webkit-search-decoration { -webkit-appearance: none; }

.sf-searchbox-spinner {
  position: absolute;
  inset-block: 0;
  right: 0.85rem;
  display: flex;
  align-items: center;
  color: var(--sf-color-primary, rgb(2 132 199));
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.15s ease;
}

/* htmx marca el elemento de hx-indicator con `htmx-request` durante el fetch. */
.sf-searchbox-spinner.htmx-request {
  opacity: 1;
  visibility: visible;
}

.sf-searchbox-spinner svg {
  animation: sf-spin 0.7s linear infinite;
}

@keyframes sf-spin {
  to { transform: rotate(360deg); }
}

/* Sin bloque `.dark` propio: el input ya se pinta con `--sf-color-text`,
   `--sf-color-bg` y `--sf-color-border`, que flipean solos con el tema y con
   el modo. Aca habia tres reglas `.dark` con slate FIJO (`rgb(30 41 59)`) que,
   por especificidad (0,2,0), le ganaban a esos tokens: en oscuro la barra de
   una carta gastronomica salia azul grisacea mientras el resto de la tienda
   era calida, y en claro tomaba el color del tema. El mismo control, dos
   identidades segun el modo. Es el patron de
   `feedback_aplanador_dark_pisa_pares_explicitos`: un bloque dark generico
   tapando un par que ya estaba bien resuelto. */

/* ════════════ Dropdown de sugerencias ════════════ */

.sf-suggestions-dropdown {
  position: absolute;
  top: calc(100% + 0.5rem);
  left: 0;
  right: 0;
  min-width: 19rem;
  background: var(--sf-color-bg, #ffffff);
  border: 1px solid var(--sf-color-border, rgb(226 232 240));
  border-radius: var(--sf-radius-lg, 0.85rem);
  box-shadow:
    0 1px 2px rgba(15, 23, 42, 0.04),
    0 12px 32px -8px rgba(15, 23, 42, 0.22);
  max-height: min(70vh, 30rem);
  overflow-y: auto;
  overscroll-behavior: contain;
  z-index: var(--sf-z-dropdown, 50);
  animation: sf-ac-in 0.16s cubic-bezier(0.2, 0.7, 0.3, 1);
}

/* Vacio (query en blanco) o cerrado por JS (Esc / click afuera) -> oculto. */
.sf-suggestions-dropdown:empty,
.sf-suggestions-dropdown.is-closed {
  display: none;
}

@keyframes sf-ac-in {
  from { opacity: 0; transform: translateY(-0.35rem); }
  to { opacity: 1; transform: translateY(0); }
}

.dark .sf-suggestions-dropdown {
  background: rgb(15 23 42);
  border-color: rgb(51 65 85);
  box-shadow:
    0 1px 2px rgba(0, 0, 0, 0.3),
    0 16px 36px -8px rgba(0, 0, 0, 0.6);
}

/* ── Header del dropdown ── */
.sf-ac-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.6rem 0.85rem 0.45rem;
  border-bottom: 1px solid var(--sf-color-border, rgb(241 245 249));
}

.sf-ac-head-label {
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--sf-color-text-muted, rgb(100 116 139));
}

.sf-ac-head-count {
  font-size: 0.66rem;
  font-weight: 700;
  line-height: 1;
  padding: 0.2rem 0.45rem;
  border-radius: 9999px;
  color: var(--sf-color-primary, rgb(2 132 199));
  background: color-mix(in srgb, var(--sf-color-primary) 12%, transparent);
}

.dark .sf-ac-head {
  border-bottom-color: rgb(30 41 59);
}

.dark .sf-ac-head-label {
  color: rgb(148 163 184);
}

/* ── Lista ── */
.sf-autocomplete-list {
  list-style: none;
  padding: 0.3rem;
  margin: 0;
}

.sf-autocomplete-item {
  list-style: none;
}

.sf-autocomplete-item a {
  display: flex;
  gap: var(--sf-space-3, 0.75rem);
  align-items: center;
  padding: 0.5rem;
  text-decoration: none;
  color: var(--sf-color-text, rgb(15 23 42));
  border-radius: var(--sf-radius-md, 0.6rem);
  transition: background-color 0.14s ease;
}

.sf-autocomplete-item a:hover,
.sf-autocomplete-item a:focus,
.sf-autocomplete-item a.is-active {
  background: var(--sf-color-bg-subtle, rgb(241 245 249));
  outline: none;
}

.dark .sf-autocomplete-item a {
  color: rgb(226 232 240);
}

.dark .sf-autocomplete-item a:hover,
.dark .sf-autocomplete-item a:focus,
.dark .sf-autocomplete-item a.is-active {
  background: rgb(30 41 59);
}

.sf-autocomplete-item img,
.sf-autocomplete-thumb {
  width: 44px;
  height: 44px;
  flex: 0 0 auto;
  object-fit: cover;
  border-radius: var(--sf-radius-md, 0.55rem);
  background: var(--sf-color-bg-subtle, rgb(241 245 249));
  display: grid;
  place-items: center;
  color: rgb(148 163 184);
}

.dark .sf-autocomplete-thumb {
  background: rgb(30 41 59);
}

.sf-autocomplete-text {
  min-width: 0;
  flex: 1;
}

.sf-autocomplete-name {
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.25rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Highlight del termino buscado (lo inserta search.js). Tinte brand sutil,
 * nunca el amarillo default del <mark>. */
.sf-autocomplete-name .sf-hl {
  background: color-mix(in srgb, var(--sf-color-primary) 16%, transparent);
  color: inherit;
  font-weight: 700;
  border-radius: 0.2rem;
  padding: 0 0.05rem;
}

.sf-autocomplete-price {
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--sf-color-primary, rgb(2 132 199));
  margin-top: 2px;
}

.dark .sf-autocomplete-price {
  color: var(--sf-color-primary, rgb(56 189 248));
}

/* Chevron "ir": aparece/desliza al hover o item activo. */
.sf-autocomplete-go {
  flex: 0 0 auto;
  color: var(--sf-color-text-muted, rgb(148 163 184));
  opacity: 0;
  transform: translateX(-0.25rem);
  transition: opacity 0.14s ease, transform 0.14s ease;
}

.sf-autocomplete-item a:hover .sf-autocomplete-go,
.sf-autocomplete-item a:focus .sf-autocomplete-go,
.sf-autocomplete-item a.is-active .sf-autocomplete-go {
  opacity: 1;
  transform: translateX(0);
}

/* ── Footer "ver todos" ── */
.sf-ac-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.7rem 0.85rem;
  border-top: 1px solid var(--sf-color-border, rgb(241 245 249));
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--sf-color-primary, rgb(2 132 199));
  text-decoration: none;
  transition: background-color 0.14s ease;
}

.sf-ac-foot:hover,
.sf-ac-foot:focus {
  background: color-mix(in srgb, var(--sf-color-primary) 8%, transparent);
  outline: none;
}

.sf-ac-foot strong {
  font-weight: 700;
}

.dark .sf-ac-foot {
  border-top-color: rgb(30 41 59);
}

/* ── Empty state premium (query >= 2 sin resultados) ── */
.sf-ac-empty {
  padding: 1.6rem 1.25rem 1.4rem;
  text-align: center;
}

.sf-ac-empty-icon {
  display: inline-grid;
  place-items: center;
  width: 3.25rem;
  height: 3.25rem;
  margin-bottom: 0.75rem;
  border-radius: 9999px;
  color: var(--sf-color-text-muted, rgb(100 116 139));
  background: var(--sf-color-bg-subtle, rgb(241 245 249));
}

.dark .sf-ac-empty-icon {
  background: rgb(30 41 59);
  color: rgb(148 163 184);
}

.sf-ac-empty-title {
  margin: 0;
  font-size: 0.9rem;
  font-weight: 700;
  color: var(--sf-color-text, rgb(30 41 59));
}

.dark .sf-ac-empty-title {
  color: rgb(226 232 240);
}

.sf-ac-empty-sub {
  margin: 0.25rem 0 0;
  font-size: 0.8rem;
  color: var(--sf-color-text-muted, rgb(100 116 139));
}

.dark .sf-ac-empty-sub {
  color: rgb(148 163 184);
}

.sf-ac-empty-cta {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  margin-top: 1rem;
  padding: 0.5rem 1rem;
  font-size: 0.8rem;
  font-weight: 600;
  border-radius: 9999px;
  color: #ffffff;
  background: var(--sf-color-primary, rgb(2 132 199));
  text-decoration: none;
  transition: background-color 0.14s ease, transform 0.1s ease;
}

.sf-ac-empty-cta:hover,
.sf-ac-empty-cta:focus {
  background: var(--sf-color-primary-600, rgb(3 105 161));
  outline: none;
}

.sf-ac-empty-cta:active {
  transform: scale(0.97);
}

/* ── Hint de query corta (1 char) ── */
.sf-ac-hint {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.95rem 1rem;
  font-size: 0.82rem;
  color: var(--sf-color-text-muted, rgb(100 116 139));
}

.sf-ac-hint-icon {
  flex: 0 0 auto;
  opacity: 0.7;
}

.dark .sf-ac-hint {
  color: rgb(148 163 184);
}

@media (prefers-reduced-motion: reduce) {
  .sf-suggestions-dropdown { animation: none; }
  .sf-searchbox-spinner svg { animation-duration: 1.4s; }
  .sf-autocomplete-go { transition: none; }
}

/* ────────── Search results page ────────── */

.sf-search-layout {
  display: grid;
  grid-template-columns: 240px 1fr;
  gap: var(--sf-space-6, 1.5rem);
  align-items: start;
}

@media (max-width: 768px) {
  .sf-search-layout {
    grid-template-columns: 1fr;
  }
}

.sf-filters {
  padding: var(--sf-space-4, 1rem);
  background: var(--sf-color-bg-elevated, rgb(248 250 252));
  border: 1px solid var(--sf-color-border, rgb(226 232 240));
  border-radius: var(--sf-radius-md, 0.5rem);
  position: sticky;
  top: 5rem;
}

.dark .sf-filters {
  background: rgb(15 23 42);
  border-color: rgb(51 65 85);
}

.sf-filter-group {
  margin-bottom: var(--sf-space-6, 1.5rem);
}

.sf-filter-group:last-child {
  margin-bottom: 0;
}

.sf-overline {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgb(100 116 139);
  margin: 0 0 var(--sf-space-2, 0.5rem);
}

.dark .sf-overline {
  color: rgb(148 163 184);
}

.sf-facet-list {
  list-style: none;
  padding: 0;
  margin: 0;
}

.sf-facet-list li {
  padding: var(--sf-space-1, 0.25rem) 0;
}

.sf-facet-list label {
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.875rem;
}

.sf-facet-list .sf-caption {
  color: rgb(100 116 139);
  font-size: 0.75rem;
}

.dark .sf-facet-list .sf-caption {
  color: rgb(148 163 184);
}

.sf-price-range {
  display: flex;
  gap: var(--sf-space-2, 0.5rem);
  margin-top: var(--sf-space-2, 0.5rem);
}

.sf-price-range .sf-input {
  width: 100%;
  min-width: 0;
  padding: 0.4rem 0.55rem;
  font-size: 0.875rem;
  border: 1px solid var(--sf-color-border, rgb(203 213 225));
  border-radius: var(--sf-radius-sm, 0.25rem);
  background: var(--sf-color-bg, #fff);
}

.dark .sf-price-range .sf-input {
  background: rgb(30 41 59);
  border-color: rgb(71 85 105);
  color: rgb(226 232 240);
}

/* ────────── Results header + sort ────────── */

.sf-search-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: var(--sf-space-3, 0.75rem);
  margin-bottom: var(--sf-space-6, 1.5rem);
  padding-bottom: var(--sf-space-3, 0.75rem);
  border-bottom: 1px solid var(--sf-color-border, rgb(226 232 240));
}

.dark .sf-search-header {
  border-bottom-color: rgb(51 65 85);
}

.sf-search-header .sf-caption {
  color: rgb(100 116 139);
  font-size: 0.875rem;
  margin-top: 2px;
}

.dark .sf-search-header .sf-caption {
  color: rgb(148 163 184);
}

.sf-sort {
  display: flex;
  align-items: center;
  gap: var(--sf-space-2, 0.5rem);
}

.sf-sort .sf-input {
  padding: 0.4rem 0.6rem;
  font-size: 0.875rem;
  border: 1px solid var(--sf-color-border, rgb(203 213 225));
  border-radius: var(--sf-radius-sm, 0.25rem);
  background: var(--sf-color-bg, #fff);
}

.dark .sf-sort .sf-input {
  background: rgb(30 41 59);
  border-color: rgb(71 85 105);
  color: rgb(226 232 240);
}

/* ────────── Empty state ────────── */

.sf-empty-state {
  padding: var(--sf-space-8, 2rem);
  text-align: center;
  background: var(--sf-color-bg-elevated, rgb(248 250 252));
  border-radius: var(--sf-radius-md, 0.5rem);
  border: 1px dashed var(--sf-color-border, rgb(203 213 225));
}

.dark .sf-empty-state {
  background: rgb(15 23 42);
  border-color: rgb(51 65 85);
}

.sf-empty-state p {
  color: rgb(100 116 139);
  margin: 0.5rem 0 1rem;
}

.dark .sf-empty-state p {
  color: rgb(148 163 184);
}
