/* ============================================================
   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.
   ============================================================ */

/* ============================================================
   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);
}
