/* =====================================================================
   CAZU — Panel administrativo. Sans-serif exclusivamente (sin serif en
   dashboards, por consistencia de producto).
   Rediseño sep-2026: paleta "bosque + lima" (inspirada en referencia de
   dashboard verde oscuro) SOLO para el panel interno — las páginas
   públicas de cada negocio (public.css) usan la paleta que el propio
   negocio elige y no se tocan aquí. El sidebar es la superficie oscura de
   marca; el resto del panel se queda claro para máxima legibilidad en
   tablas/formularios largos.
   ===================================================================== */

@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&family=JetBrains+Mono:wght@500;600&display=swap');

:root {
  --ink: #142720;
  --ink-soft: #5C6E64;
  --ink-faint: #93A69A;
  --surface: #FFFFFF;
  --bg: #F1F2EC;
  --border: #E3E6DD;
  --accent: #2F7D4C;
  --accent-soft: #E4F2E9;
  --success: #237A4B;
  --success-soft: #E3F3E9;
  --danger: #B3261E;
  --danger-soft: #FBEAE9;
  /* #8C601E en vez del #9C6B22 original (auditoría sep/2026, accesibilidad):
     el original daba 4.01:1 sobre --warning-soft en el badge de estado
     ("Borrador"/"Vencido"/"Pendiente"), por debajo del 4.5:1 que exige
     WCAG AA para texto normal (el badge es texto pequeño en negrita,
     11.5px, no califica como "texto grande" con el umbral más bajo de
     3:1). Este tono da 4.78:1, mismo matiz ámbar, casi imperceptible el
     cambio a simple vista. */
  --warning: #8C601E;
  --warning-soft: #F6EEDC;
  /* Verde-lima de marca: acento vivo reservado para el sidebar (ítem activo)
     y detalles puntuales — nunca como color de texto/fondo extenso, es
     demasiado saturado para eso. */
  --lime: #C7F26B;
  --lime-ink: #10281C;
  /* Sidebar: única superficie oscura del panel. */
  --sidebar-bg: #0F2A1D;
  --sidebar-bg-soft: #17392A;
  --sidebar-text: #9FB6A8;
  --sidebar-border: rgba(255,255,255,0.08);
  /* Verde oscuro de marca (mismo tono que el fondo del sidebar) reservado
     para títulos de sección — separado de --ink (el texto normal del
     panel) para que un título como "Dashboard" o "Resumen de la
     plataforma" se lea claramente como encabezado y no se confunda con
     texto de cuerpo, aunque ambos tonos sean cercanos. */
  --heading: #0F2A1D;
  --radius-xl: 26px;
  --radius-lg: 20px;
  --radius-md: 14px;
  --radius-sm: 10px;
  /* Sombras teñidas del verde de marca (no gris/negro genérico) — más
     coherente con la paleta que una sombra neutra. */
  --shadow: 0 16px 36px -20px rgba(15,42,29,0.24), 0 2px 6px rgba(15,42,29,0.05);
  --shadow-shell: 0 30px 60px -32px rgba(15,42,29,0.38);
  --shell-gap: 18px;
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --font: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-mono: 'JetBrains Mono', 'SFMono-Regular', monospace;
}

* { box-sizing: border-box; }
html, body { margin: 0; }
body {
  font-family: var(--font);
  background: var(--bg);
  color: var(--ink);
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}
a { color: inherit; text-decoration: none; }
h1, h2, h3 { margin: 0; letter-spacing: -0.01em; }
img { max-width: 100%; }
.mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

/* ---------- Foco visible (accesibilidad) ----------
   Antes solo los inputs de formulario tenían anillo de foco propio;
   botones y enlaces de navegación dependían del outline por defecto del
   navegador (inconsistente entre navegadores, y a veces invisible sobre
   un pill de border-radius:999px). Un anillo consistente en el color de
   marca ayuda a cualquiera que navegue el panel con teclado. */
a:focus-visible, button:focus-visible, input:focus-visible,
select:focus-visible, textarea:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ---------- Respeto a "reducir movimiento" ----------
   El panel usa transiciones cortas (hover de botones/nav) y, más abajo,
   una entrada progresiva de tarjetas — ninguna dependía antes de esta
   preferencia de accesibilidad. No cambia ningún layout: solo colapsa la
   duración a algo imperceptible para quien la activó en su sistema. */
@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;
  }
}

/* ---------- Shell / layout ----------
   Dos superficies "flotantes" sobre el fondo del body (var(--bg)), con
   espacio entre ellas — look de referencia — en vez del sidebar+contenido
   a todo lo ancho de antes. Ambas usan position:sticky con el mismo offset
   (--shell-gap) para que, al hacer scroll, se detengan justo contra el
   margen exterior en vez de pegarse al borde real del viewport (lo que
   rompería visualmente la esquina redondeada). */
body { background: var(--bg); }
.ad-shell { display: flex; min-height: 100dvh; gap: var(--shell-gap); padding: var(--shell-gap); align-items: flex-start; }
.ad-sidebar {
  width: 240px; flex: none; background: var(--sidebar-bg); color: var(--sidebar-text);
  border-radius: var(--radius-xl); box-shadow: var(--shadow-shell);
  padding: 1.5rem 1rem; position: sticky; top: var(--shell-gap);
  height: calc(100dvh - (var(--shell-gap) * 2)); overflow-y: auto;
  display: flex; flex-direction: column;
}
/* .ad-brand se reutiliza en dos superficies muy distintas: el sidebar
   oscuro (necesita texto blanco) y la tarjeta de login, blanca (necesita
   texto oscuro) — sin el color aquí scopeado, el blanco del sidebar se
   colaba al login y dejaba "CAZU" invisible sobre fondo blanco. */
.ad-brand { display: flex; align-items: center; gap: 0.6rem; padding: 0 0.5rem 1.5rem; font-weight: 800; font-size: 1.1rem; color: var(--ink); }
.ad-sidebar .ad-brand { color: #fff; }
.ad-nav a {
  display: flex; align-items: center; gap: 0.7rem; padding: 0.65rem 0.75rem; border-radius: 999px;
  color: var(--sidebar-text); font-weight: 600; font-size: 0.92rem; margin-bottom: 0.15rem;
  transition: background 0.18s var(--ease), color 0.18s var(--ease);
}
.ad-nav a:hover { background: var(--sidebar-bg-soft); color: #fff; }
/* Ítem activo: pill lima sólido, como el "chip" de sección activa de la
   referencia — es el único lugar del panel donde se usa --lime a tamaño
   grande, por eso el texto pasa a --lime-ink (oscuro) para contraste. */
.ad-nav a.active { background: var(--lime); color: var(--lime-ink); }
.ad-nav svg { flex: none; }
.ad-nav-group { margin-top: 1.25rem; padding-top: 1.25rem; border-top: 1px solid var(--sidebar-border); }
.ad-user { margin-top: auto; padding: 1rem 0.5rem 0; font-size: 0.82rem; color: var(--sidebar-text); border-top: 1px solid var(--sidebar-border); }
/* Botones dentro del sidebar oscuro (ej. "Cerrar sesión"): btn-ghost por
   defecto asume texto/borde oscuros sobre fondo claro, invisibles aquí. */
.ad-sidebar .btn-ghost { color: var(--sidebar-text); border-color: var(--sidebar-border); }
.ad-sidebar .btn-ghost:hover { background: var(--sidebar-bg-soft); color: #fff; }

.ad-main {
  flex: 1; min-width: 0; background: var(--surface); border-radius: var(--radius-xl);
  box-shadow: var(--shadow-shell); overflow: hidden;
}
.ad-topbar {
  display: flex; align-items: center; justify-content: space-between;
  padding: 1.1rem 1.75rem; background: var(--surface); border-bottom: 1px solid var(--border);
  position: sticky; top: var(--shell-gap); z-index: 5;
}
.ad-topbar h1 { font-size: 1.5rem; color: var(--heading); font-weight: 800; }
/* Lienzo del contenido en gris cálido (var(--bg)) en vez de blanco puro:
   así las .card blancas de adentro (stat-cards, tablas, company-card...)
   se distinguen por color además de por sombra — si el lienzo también
   fuera blanco, una card blanca sin borde marcado se perdería contra el
   fondo. border-bottom del topbar (arriba) ya marca la costura entre
   ambos tonos. */
/* max-width sin margin:auto dejaba el contenido pegado al borde izquierdo
   de .ad-main y todo el resto (potencialmente cientos de px en monitores
   anchos) como una franja vacía a la derecha — se veía como si el panel
   "no se adaptara" a pantallas grandes. Un primer intento centró el bloque
   con max-width:1400px, pero en laptops/monitores normales (1440-1920,
   el rango más común) eso todavía dejaba franjas vacías simétricas a los
   lados que se seguían viendo "raras" — el usuario lo reportó dos veces.
   Subir el tope a 1900px hace que, en la práctica, el contenido ocupe
   TODO el ancho de .ad-main en cualquier pantalla común (hasta ~1920px de
   ventana) y el límite solo entra en juego en monitores 4K/ultra-anchos,
   donde sí conviene no estirar tablas y tarjetas a un ancho absurdo. */
.ad-content { padding: 1.75rem; max-width: 1900px; margin: 0 auto; background: var(--bg); border-radius: 0 0 var(--radius-xl) var(--radius-xl); }

/* ---------- Títulos de sección ----------
   Los <h2>/<h3> de cada página ("Resumen de la plataforma", "Sedes
   recientes", "Colores", etc.) traían tamaños pequeños e inconsistentes
   fijados inline página por página (0.88rem–1.05rem) y heredaban el color
   de texto normal (--ink) sin distinguirse como encabezados. Se sube el
   tamaño (con !important porque hay decenas de estilos inline `font-size`
   ya en las vistas que si no, ganarían por especificidad) y se usa el
   verde oscuro de marca (--heading) en vez de --ink para que un título
   como "Dashboard" se lea de inmediato como encabezado. */
.ad-content h2 { font-size: 1.3rem !important; color: var(--heading); font-weight: 700; }
.ad-content h3 { font-size: 1.05rem !important; color: var(--heading); font-weight: 700; }

/* Botón de cerrar sesión del topbar: solo tiene sentido en móvil, donde el
   sidebar (y su "Cerrar sesión" de siempre) está oculto — ver .ad-sidebar
   y .ad-bottom-nav más abajo. En desktop se oculta para no duplicar. */
.ad-topbar-logout { display: none; }

/* ---------- Menú inferior (solo móvil) ----------
   Reemplazo real del sidebar cuando este se oculta (mismo breakpoint,
   620px): sin esto, una vez oculto el sidebar no había NINGUNA forma de
   navegar entre secciones ni de cerrar sesión desde el celular — el panel
   quedaba "atrapado" en la página actual. Mismos 5 destinos que el
   sidebar, con ícono + etiqueta (nunca solo ícono, por descubribilidad),
   nunca más de 5 ítems y con el activo resaltado, como en cualquier tab
   bar nativo. */
.ad-bottom-nav {
  display: none;
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 20;
  background: var(--surface); border-top: 1px solid var(--border);
  padding: 0.35rem 0.25rem calc(0.35rem + env(safe-area-inset-bottom));
}

/* ---------- Botones ---------- */
.btn {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center; gap: 0.45rem;
  border: 1px solid transparent; border-radius: 999px; padding: 0.65rem 1.15rem;
  font-weight: 700; font-size: 0.88rem; cursor: pointer; min-height: 40px;
  transition: transform 0.18s var(--ease), filter 0.18s var(--ease), background 0.18s var(--ease), box-shadow 0.18s var(--ease);
  font-family: inherit;
}
.btn:active { transform: scale(0.97); }
.btn-primary { background: var(--ink); color: #fff; }
.btn-primary:hover { filter: brightness(1.15); box-shadow: 0 8px 20px -10px rgba(23,23,26,0.45); }
.btn-accent { background: var(--accent); color: #fff; }
.btn-accent:hover { filter: brightness(1.08); box-shadow: 0 8px 20px -10px color-mix(in srgb, var(--accent) 70%, transparent); }
.btn-ghost { background: transparent; color: var(--ink); border-color: var(--border); }
.btn-ghost:hover { background: var(--bg); }
.btn-danger { background: var(--danger-soft); color: var(--danger); }
.btn-sm { padding: 0.45rem 0.85rem; font-size: 0.8rem; min-height: 32px; }
.btn[disabled] { opacity: 0.5; cursor: not-allowed; }

/* Convención de jerarquía (auditoría sep/2026, P2.2): btn-primary (tinta
   sólida) es SOLO para la acción más importante de una pantalla completa
   (ej. "Entrar" del login) — no para marcar "seleccionado" dentro de un
   grupo de opciones, que es lo que .seg de abajo resuelve. btn-accent
   (verde) es la acción principal de una vista/tarjeta puntual (Guardar,
   Publicar, + Nueva sede); btn-ghost, cualquier acción secundaria; y
   btn-danger, solo acciones destructivas o de pausa/alerta. */

/* ---------- Selector segmentado (pills tipo "7 días / 30 días") ----------
   Antes esto se armaba reutilizando btn-primary/btn-ghost para marcar cuál
   pill está activa (ver businesses/analytics.php) — btn-primary era la
   única pantalla del panel que lo usaba así, mientras que el resto de
   selectores de período son un <select> nativo (period_selector.php). .seg
   unifica el patrón de "grupo de opciones, una activa" en un componente
   propio, sin pedir prestado el significado de btn-primary. */
.seg { display: inline-flex; gap: 0.3rem; background: var(--bg); border: 1px solid var(--border); border-radius: 999px; padding: 0.2rem; }
.seg-btn {
  border: 0; background: transparent; color: var(--ink-soft); font-weight: 700; font-family: inherit;
  font-size: 0.8rem; padding: 0.4rem 0.85rem; border-radius: 999px; cursor: pointer; min-height: 32px;
  text-decoration: none; display: inline-flex; align-items: center; transition: background 0.15s var(--ease), color 0.15s var(--ease);
}
.seg-btn:hover { color: var(--ink); }
.seg-btn.is-active { background: var(--surface); color: var(--ink); box-shadow: var(--shadow); }

/* Estado de carga (admin.js lo agrega al enviar un formulario): oculta el
   texto/ícono y muestra un spinner en su lugar, sin que el botón cambie
   de tamaño. El spinner es blanco para primary/accent (texto claro) y
   tono tinta para ghost/danger (texto oscuro sobre fondo claro). */
.btn.is-loading { color: transparent !important; pointer-events: none; }
.btn.is-loading[disabled] { opacity: 0.85; }
.btn.is-loading::after {
  content: '';
  position: absolute; top: 50%; left: 50%;
  width: 15px; height: 15px; margin: -7.5px 0 0 -7.5px;
  border: 2px solid rgba(255,255,255,0.4); border-top-color: #fff;
  border-radius: 50%;
  animation: ad-spin 0.6s linear infinite;
}
.btn-ghost.is-loading::after, .btn-danger.is-loading::after {
  border-color: rgba(23,23,26,0.2); border-top-color: var(--ink-soft);
}
@keyframes ad-spin { to { transform: rotate(360deg); } }

/* ---------- Cards / grid ---------- */
.card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: 1.4rem; box-shadow: var(--shadow); }
.grid { display: grid; gap: 1rem; }
/* minmax(0,1fr) en vez de 1fr a secas: una pista de grid con "1fr" solo
   tiene un mínimo implícito de auto (= min-content), así que un hijo con
   contenido ancho que no puede achicarse más — típicamente un
   <input type="file">, cuyo botón nativo "Elegir archivo" tiene un ancho
   mínimo propio — expande esa columna más allá de su parte justa y
   desborda la tarjeta/página entera en celular (visto en identity.php:
   Logo/Portada). minmax(0,1fr) fuerza el mínimo real a 0 para que la
   columna sí se achique y el contenido interno decida su propio scroll si
   hace falta. */
.grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
/* Subido de 900 a 1100: a 1024px (portátil/tablet horizontal muy común)
   4 columnas dejaban ~156px por tarjeta — suficiente para el número pero no
   para etiquetas largas ("SUSCRIPCIONES AL DÍA", "NUEVAS SEDES (30D)"),
   que se partían en 2-3 líneas y se veían apretadas. Con el corte a 1100px
   esos anchos típicos ya caen en el layout de 2 columnas, con espacio de
   sobra. */
@media (max-width: 1100px) { .grid-4, .grid-3, .grid-2 { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); } }
@media (max-width: 620px) {
  .grid-4, .grid-3, .grid-2 { grid-template-columns: minmax(0, 1fr); }
  .ad-sidebar { display: none; }
  /* En celular el sidebar flotante desaparece (lo reemplaza .ad-bottom-nav)
     y el panel principal vuelve a ocupar todo el ancho a ras — el "look"
     de tarjetas flotantes con separación es un lujo de escritorio; en una
     pantalla angosta solo resta espacio útil. */
  .ad-shell { padding: 0; gap: 0; }
  .ad-main { border-radius: 0; box-shadow: none; }
  .ad-topbar { border-radius: 0; top: 0; }
  .ad-content { border-radius: 0; }
  .ad-topbar-logout { display: block; }
  /* Espacio real para que el menú inferior fijo nunca tape el último botón
     o campo de la página (p. ej. "Guardar" al fondo de un formulario). */
  .ad-content { padding: 1rem 1rem calc(5.5rem + env(safe-area-inset-bottom)); }
  .ad-bottom-nav { display: flex; }
  /* Los botones de navegación del wizard de "Nuevo negocio" (Atrás /
     Siguiente / Omitir y crear / Crear negocio y continuar) suman más
     ancho que el que cabe en una pantalla de celular — hasta 3 botones con
     texto largo en una sola fila sin wrap. Se apilan a ancho completo,
     manteniendo "Atrás" siempre arriba (secundario primero, izquierda a
     derecha se lee de arriba hacia abajo) y el grupo de acciones primarias
     debajo, en el orden en que ya estaban en el HTML. */
  .wizard-nav { flex-wrap: wrap; gap: 0.6rem; }
  .wizard-nav > .btn, .wizard-nav-group { flex: 1 1 100%; }
  .wizard-nav-group { display: flex; flex-direction: column; }
}
.ad-bottom-nav a {
  flex: 1; display: flex; flex-direction: column; align-items: center; gap: 0.2rem;
  padding: 0.4rem 0.2rem; border-radius: var(--radius-sm);
  /* --ink-soft en vez de --ink-faint (auditoría sep/2026, accesibilidad):
     --ink-faint da 2.29:1 sobre el fondo del nav — muy por debajo del
     4.5:1 de WCAG AA para texto normal, y este es texto real (las
     etiquetas "Inicio"/"Negocios"/etc. del nav inferior en móvil), no un
     detalle decorativo. --ink-soft da 4.82:1. */
  color: var(--ink-soft); font-size: 0.66rem; font-weight: 700;
  min-height: 44px; justify-content: center;
}
.ad-bottom-nav a.active { color: var(--accent); }
.ad-bottom-nav a span { line-height: 1; white-space: nowrap; }

.stat-card { display: flex; flex-direction: column; gap: 0.3rem; }
.stat-card .label { color: var(--ink-soft); font-size: 0.8rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; }
.stat-card .value { font-family: var(--font-mono); font-size: 1.8rem; font-weight: 600; }
.stat-card .delta { font-size: 0.78rem; color: var(--success); font-weight: 700; }

/* ---------- Entrada progresiva de tarjetas ----------
   Solo CSS (no depende de que ningún script llegue a correr): las
   tarjetas de una fila de grid (los 4 KPI del dashboard, por ejemplo)
   aparecen con un pequeño fade-up escalonado en vez de aparecer todas de
   golpe. @media (prefers-reduced-motion:reduce) ya la neutraliza arriba;
   esto además solo se activa si el sistema no pidió lo contrario. */
@media (prefers-reduced-motion: no-preference) {
  .grid > .card { animation: ad-fade-up 0.45s var(--ease) both; }
  .grid > .card:nth-child(1) { animation-delay: 0ms; }
  .grid > .card:nth-child(2) { animation-delay: 55ms; }
  .grid > .card:nth-child(3) { animation-delay: 110ms; }
  .grid > .card:nth-child(4) { animation-delay: 165ms; }
  .grid > .card:nth-child(n+5) { animation-delay: 200ms; }
}
@keyframes ad-fade-up {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: translateY(0); }
}

/* ---------- Formularios ---------- */
.field { margin-bottom: 1.1rem; }
.field label { display: block; font-size: 0.82rem; font-weight: 700; margin-bottom: 0.35rem; }
.field .hint { font-size: 0.76rem; color: var(--ink-soft); margin-top: 0.3rem; }
.field input[type=text], .field input[type=email], .field input[type=tel], .field input[type=url],
.field input[type=password], .field input[type=number], .field input[type=date], .field textarea, .field select {
  width: 100%; padding: 0.7rem 0.85rem; border: 1px solid var(--border); border-radius: var(--radius-sm);
  font-family: inherit; font-size: 0.92rem; background: #fff; color: var(--ink);
}
/* input[type=file] no tenía ninguna regla de ancho — a diferencia de los
   demás inputs de arriba, el widget nativo del navegador ("Elegir
   archivo" + nombre) tiene su propio ancho mínimo, así que sin esto podía
   sobresalir de su columna en el grid de Logo/Portada en celular. */
.field input[type=file] { width: 100%; max-width: 100%; }
.field input:focus, .field textarea:focus, .field select:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
.field textarea { resize: vertical; min-height: 80px; }
.field-error { color: var(--danger); font-size: 0.78rem; margin-top: 0.3rem; }
.field-row { display: flex; gap: 1rem; }
.field-row > .field { flex: 1; }
/* .field-row pone 2-3 campos lado a lado (categoría/email, utm_source/
   utm_medium/utm_campaign, etc.) sin wrap — cada input de texto tiene un
   ancho mínimo propio que el navegador respeta aunque el padre se achique,
   así que en un celular angosto la fila se desborda y empuja scroll
   horizontal a toda la página. Apilarlos resuelve esto sin tocar ninguna
   de las vistas que usan esta clase. Esta regla va DESPUÉS de la base de
   arriba (misma especificidad) para que gane en cascada dentro del media
   query — antes estaba dentro de un @media más arriba en el archivo y la
   base la pisaba silenciosamente. */
@media (max-width: 620px) {
  .field-row { flex-wrap: wrap; }
  .field-row > .field { flex: 1 1 100%; }
}
.color-field { display: flex; align-items: center; gap: 0.6rem; }
.color-field input[type=color] { width: 42px; height: 42px; padding: 2px; border-radius: var(--radius-sm); border: 1px solid var(--border); }
.checkbox-field { display: flex; align-items: center; gap: 0.5rem; font-size: 0.88rem; font-weight: 600; }

/* ---------- Tabla ---------- */
.table-wrap { overflow-x: auto; border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--surface); }
table { width: 100%; border-collapse: collapse; font-size: 0.88rem; min-width: 640px; }
/* Tablas de 2 columnas tipo "clave: valor" (analytics: enlaces más usados,
   visitas por origen) no necesitan el min-width de 640px pensado para las
   tablas de datos grandes (negocios, leads, QR) — ese mínimo, sin
   .table-wrap alrededor, las desbordaba en celular. */
table.table-compact { min-width: 0; }
th, td { text-align: left; padding: 0.85rem 1rem; border-bottom: 1px solid var(--border); }
th { color: var(--ink-soft); font-weight: 700; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.04em; }
tr:last-child td { border-bottom: none; }
tbody tr { transition: background 0.15s var(--ease); }
tbody tr:hover { background: var(--bg); }
/* Filas/tarjetas clicables (ver admin.js: delegado de clic en .row-link) —
   el cursor de mano es la única pista visual de que toda la fila/tarjeta
   abre el registro, no solo el botón "Administrar"/"Editar" de siempre. */
tr.row-link { cursor: pointer; }
tr.row-link:hover { background: var(--accent-soft); }
.company-card.row-link { cursor: pointer; transition: transform 0.15s var(--ease), border-color 0.15s var(--ease); }
.company-card.row-link:hover { transform: translateY(-2px); border-color: var(--accent); }
.row-avatar { width: 36px; height: 36px; border-radius: 50%; object-fit: cover; background: var(--bg); }

/* ---------- Badges ---------- */
.badge { display: inline-flex; align-items: center; gap: 0.3rem; padding: 0.25rem 0.65rem; border-radius: 999px; font-size: 0.72rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em; }
.badge-published { background: var(--success-soft); color: var(--success); }
.badge-draft { background: var(--warning-soft); color: var(--warning); }
.badge-paused { background: #EDEBE6; color: var(--ink-soft); }
.badge-archived { background: var(--danger-soft); color: var(--danger); }
/* Semáforo de suscripción (companies): verde=activo, amarillo=pendiente o
   en periodo de gracia ("vencido" internamente SIEMPRE significa "todavía
   en gracia", nunca pausado — ver App\Services\SubscriptionService), rojo=
   pausado por falta de pago (gracia agotada, lo más urgente), gris=sin
   plan asignado. No se tocan los nombres internos de subscription_status
   (atados a la lógica de facturación/Wompi), solo su color en pantalla. */
.badge-activo { background: var(--success-soft); color: var(--success); }
.badge-pendiente { background: var(--warning-soft); color: var(--warning); }
.badge-vencido { background: var(--warning-soft); color: var(--warning); }
.badge-pausado { background: var(--danger-soft); color: var(--danger); }
.badge-sin_plan { background: #EDEBE6; color: var(--ink-soft); }

/* ---------- Panel "Negocios": filtros, cards de negocio, paginación ---------- */
.filter-bar { display: flex; flex-wrap: wrap; gap: .75rem; align-items: flex-end; }
.filter-bar .field { margin-bottom: 0; min-width: 160px; }
.filter-bar .field-check { display: flex; align-items: center; gap: .4rem; font-size: .82rem; font-weight: 600; min-width: auto; margin-bottom: 0; padding-bottom: .7rem; }
.filter-bar .field-check input { width: auto; }
.view-toggle { display: inline-flex; border: 1px solid var(--border); border-radius: var(--radius-sm); overflow: hidden; }
.view-toggle a { padding: .5rem .85rem; font-size: .8rem; font-weight: 700; color: var(--ink-soft); }
.view-toggle a.active { background: var(--accent-soft); color: var(--accent); }
.view-toggle a + a { border-left: 1px solid var(--border); }
.company-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 1rem; }
.company-card { display: flex; flex-direction: column; gap: .6rem; }
/* Nombre de negocio largo + badge de estado con texto largo (ej. "Pausado
   por falta de pago") competían por el mismo ancho de fila: el badge tenía
   prioridad (flex-shrink:0) y le dejaba al título una columna de apenas
   ~30px, que se veía como si el badge quedara encimado sobre el título.
   flex-wrap:wrap dejar caer el badge a una segunda línea cuando no cabe,
   y cc-title-wrap con flex-basis:140px le da al título un ancho mínimo
   razonable antes de que eso ocurra — así ninguno de los dos se aplasta. */
.company-card .cc-head { display: flex; align-items: flex-start; flex-wrap: wrap; gap: .5rem .65rem; }
.company-card .cc-title-wrap { flex: 1 1 140px; min-width: 0; }
.company-card .cc-head .badge { flex-shrink: 0; margin-top: .15rem; }
.company-card .cc-logo { width: 44px; height: 44px; border-radius: 50%; object-fit: cover; background: var(--bg); flex: none; }
.company-card .cc-title { font-weight: 800; font-size: 1rem; line-height: 1.25; }
.company-card .cc-contact { color: var(--ink-soft); font-size: .78rem; }
.company-card .cc-row { display: flex; justify-content: space-between; gap: .5rem; font-size: .82rem; }
.company-card .cc-row .l { color: var(--ink-soft); }
.company-card .cc-row .v { font-weight: 700; }
.company-card .cc-metrics { display: flex; gap: 1rem; padding: .5rem 0; border-top: 1px dashed var(--border); border-bottom: 1px dashed var(--border); }
.company-card .cc-metrics div { flex: 1; text-align: center; }
.company-card .cc-metrics .n { font-weight: 800; font-size: 1.05rem; display: block; }
.company-card .cc-metrics .l { color: var(--ink-soft); font-size: .7rem; text-transform: uppercase; letter-spacing: .03em; }
.pagination-bar { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: .75rem; margin-top: 1rem; }
.breadcrumbs { font-size: .82rem; color: var(--ink-soft); margin-bottom: .75rem; }
.breadcrumbs a { color: var(--ink-soft); text-decoration: underline; }
.breadcrumbs .sep { margin: 0 .35rem; }

/* ---------- Tabs ---------- */
.tabs { display: flex; gap: 0.3rem; border-bottom: 1px solid var(--border); margin-bottom: 1.5rem; overflow-x: auto; }
.tabs a { padding: 0.75rem 0.9rem; font-weight: 700; font-size: 0.86rem; color: var(--ink-soft); border-bottom: 2px solid transparent; white-space: nowrap; }
.tabs a.active { color: var(--ink); border-color: var(--accent); }

/* ---------- Flash / alerts ---------- */
.alert { padding: 0.85rem 1rem; border-radius: var(--radius-md); font-size: 0.88rem; margin-bottom: 1.25rem; font-weight: 600; }
.alert-success { background: var(--success-soft); color: var(--success); }
.alert-error { background: var(--danger-soft); color: var(--danger); }

/* ---------- Templates gallery ---------- */
.template-card { border: 1px solid var(--border); border-radius: var(--radius-lg); overflow: hidden; background: var(--surface); transition: box-shadow .18s var(--ease), border-color .18s var(--ease), transform .18s var(--ease); }
.template-card:hover { transform: translateY(-2px); box-shadow: var(--shadow); }
input:checked + .template-card { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent); }
.template-card .thumb { height: 140px; display: flex; align-items: center; justify-content: center; color: #fff; font-weight: 800; font-size: 1.1rem; }
.template-card .body { padding: 1rem; }
.template-card .body p { color: var(--ink-soft); font-size: 0.85rem; margin: 0.3rem 0 0; }

/* Mini-mockup de vista previa de plantilla: reproduce en miniatura la
   página pública (hero + avatar + botones) con la paleta real de la
   plantilla, para que se vea "cómo queda" sin crear un negocio. */
.tpl-preview {
  position: relative;
  height: 150px;
  display: flex;
  flex-direction: column;
  align-items: center;
  overflow: hidden;
}
.tpl-preview-hero { position: absolute; top: 0; left: 0; right: 0; height: 62px; }
.tpl-preview-badge {
  position: absolute; top: 8px; left: 8px; z-index: 1;
  display: flex; align-items: center; gap: 4px;
  background: rgba(255,255,255,0.92);
  padding: 3px 9px 3px 6px; border-radius: 999px;
  font-size: 0.62rem; font-weight: 700; letter-spacing: 0.03em; text-transform: uppercase;
  box-shadow: 0 1px 4px rgba(0,0,0,0.14);
}
.tpl-preview-badge-icon { display: flex; line-height: 0; }
.tpl-preview-badge-icon svg { display: block; }
.tpl-preview-avatar {
  position: relative; z-index: 1;
  width: 34px; height: 34px; border-radius: 50%;
  background: #fff; border: 3px solid #fff;
  box-shadow: 0 2px 8px rgba(0,0,0,0.18);
  margin-top: 45px;
}
.tpl-preview-name-bar { width: 70px; height: 8px; border-radius: 4px; background: rgba(0,0,0,0.16); margin-top: 12px; }
.tpl-preview-line { width: 46px; height: 5px; border-radius: 3px; background: rgba(0,0,0,0.09); margin-top: 6px; }
.tpl-preview-btns { display: flex; gap: 6px; margin-top: 12px; }
.tpl-preview-btn { width: 48px; height: 16px; display: block; }

/* ---------- Blocks list (drag & drop) ---------- */
.block-row {
  display: flex; align-items: center; gap: 0.75rem; padding: 0.85rem 1rem; background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--radius-md); margin-bottom: 0.6rem; cursor: grab;
}
.block-row.dragging { opacity: 0.4; }
/* Botones de reordenar (arriba/abajo): reemplazan al ícono estático de
   "handle" — el drag-and-drop nativo (abajo) no responde al dedo en
   celular, así que esto es el único método de reordenar que funciona en
   touch. Se ven idénticos y funcionan igual en mouse y en celular. */
.block-row .reorder-btns { display: flex; flex-direction: column; gap: 2px; flex: none; }
.block-row .reorder-btn {
  display: flex; align-items: center; justify-content: center;
  width: 28px; height: 24px; padding: 0; border: 1px solid var(--border); border-radius: 6px;
  background: var(--surface); color: var(--ink-soft); cursor: pointer;
}
.block-row .reorder-btn:hover:not(:disabled) { background: var(--bg); color: var(--ink); }
.block-row .reorder-btn:disabled { opacity: 0.3; cursor: not-allowed; }
.block-row .info { flex: 1; min-width: 0; }
.block-row .info strong { display: block; font-size: 0.9rem; }
.block-row .info span { color: var(--ink-soft); font-size: 0.78rem; }
.block-row .actions { display: flex; gap: 0.4rem; flex: none; }
.type-pill { display: inline-block; font-size: 0.68rem; font-weight: 700; text-transform: uppercase; color: var(--accent); background: var(--accent-soft); padding: 0.15rem 0.5rem; border-radius: 999px; margin-right: 0.4rem; }
/* En una fila angosta (celular), las flechas + info + 3 botones de acción no
   caben en una sola línea sin apretujar el título. Se parte en dos líneas:
   arriba flechas+info, abajo los 3 botones a todo el ancho. */
@media (max-width: 620px) {
  .block-row { flex-wrap: wrap; }
  .block-row .actions { flex-basis: 100%; justify-content: flex-end; margin-top: 0.6rem; padding-top: 0.6rem; border-top: 1px solid var(--border); }
}

/* ---------- Chart (SVG inline, sin librerías) ---------- */
.chart-wrap { overflow-x: auto; }
.chart-bar-track { fill: var(--bg); }
.chart-bar { fill: var(--accent); }
.chart-axis { stroke: var(--border); stroke-width: 1; }
.chart-label { fill: var(--ink-soft); font-size: 10px; font-family: var(--font); }

/* ---------- Analytics: desglose por dispositivo (barras horizontales) ---------- */
.device-insight { display: flex; align-items: center; gap: .6rem; padding: .85rem 1rem; margin-bottom: 1.1rem; background: var(--accent-soft); border-radius: var(--radius-lg); color: var(--ink); font-size: .92rem; font-weight: 600; }
.device-insight svg { flex-shrink: 0; color: var(--accent); }
.device-row { display: flex; align-items: center; gap: .75rem; margin-bottom: .65rem; }
.device-row:last-child { margin-bottom: 0; }
.device-row .device-label { flex: 0 0 88px; font-size: .82rem; color: var(--ink-soft); font-weight: 600; }
.device-row .device-track { flex: 1; height: 10px; background: var(--bg); border-radius: 999px; overflow: hidden; }
.device-row .device-fill { height: 100%; background: var(--accent); border-radius: 999px; }
.device-row .device-pct { flex: 0 0 42px; text-align: right; font-family: var(--font-mono); font-size: .82rem; font-weight: 700; }

/* ---------- Login (auditoría sep/2026, P2.3) ----------
   Antes era una tarjeta blanca plana sobre fondo plano, sin ninguna marca
   más allá del texto "CAZU" — funcional pero sin nada que la distinguiera
   de un formulario genérico. El degradado sutil y la marca cuadrada dan
   una primera impresión más cuidada sin tocar el resto del panel (.ad-brand
   sigue intacto para el sidebar, ver comentario junto a su definición). */
.login-wrap {
  min-height: 100dvh; display: flex; align-items: center; justify-content: center; padding: 1.5rem;
  background: radial-gradient(circle at 50% -10%, color-mix(in srgb, var(--accent) 12%, var(--bg)) 0%, var(--bg) 60%);
}
.login-card {
  width: 100%; max-width: 380px; background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); padding: 2.5rem 2.25rem 2.25rem;
  box-shadow: 0 32px 56px -28px rgba(20, 39, 32, 0.28), var(--shadow);
}
.login-brand { display: flex; flex-direction: column; align-items: center; margin-bottom: 1.85rem; }
.login-logo {
  height: 46px; width: auto; margin-bottom: 0.85rem;
  filter: drop-shadow(0 10px 20px -10px color-mix(in srgb, var(--accent) 70%, transparent));
}
.login-subtitle { font-size: 0.82rem; color: var(--ink-soft); font-weight: 500; margin: 0.3rem 0 0; }

/* ---------- Empty state ---------- */
.empty-state { text-align: center; padding: 3rem 1rem; color: var(--ink-soft); }
.empty-state svg { color: var(--ink-faint); margin-bottom: 0.75rem; }

/* ---------- Selector visual de icono (auditoría sep/2026, P2.6) ----------
   Reemplaza el <select> de nombres crudos ("map-pin", "menu-food"...) de
   block_form.php por una grilla de botones que muestran el SVG real de
   cada icono — antes había que adivinar qué dibujaba cada opción. */
.icon-picker { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.icon-picker-item {
  display: flex; flex-direction: column; align-items: center; gap: 0.3rem; width: 72px;
  padding: 0.6rem 0.3rem; border: 1.5px solid var(--border); border-radius: 12px; background: var(--surface);
  color: var(--ink-soft); cursor: pointer; font-family: inherit; transition: border-color 0.15s var(--ease), color 0.15s var(--ease), background 0.15s var(--ease);
}
.icon-picker-item:hover { border-color: var(--accent); color: var(--ink); }
.icon-picker-item.is-selected { border-color: var(--accent); background: var(--accent-soft); color: var(--ink); }
.icon-picker-item-label { font-size: 0.68rem; font-weight: 600; text-align: center; line-height: 1.15; }

/* ---------- Eliminar una foto de la galería (auditoría sep/2026, P2.5) ----------
   Badge superpuesto en la esquina de cada thumbnail existente en el editor
   de la galería; marcarlo no borra nada hasta que se guarda el formulario. */
.gallery-remove-toggle {
  position: absolute; top: 6px; right: 6px; z-index: 2; display: flex; align-items: center; gap: 0.3rem;
  background: rgba(23, 23, 26, 0.72); color: #fff; font-size: 0.68rem; font-weight: 700;
  padding: 0.3rem 0.5rem; border-radius: 999px; cursor: pointer; pointer-events: auto;
}
.gallery-remove-toggle input { margin: 0; }
.gallery-focal-picker.is-marked-for-removal { outline: 2px solid var(--danger); outline-offset: 2px; opacity: 0.6; }

/* ---------- Zonas de arrastrar-y-soltar para subir archivos (auditoría
   sep/2026, P2.4) ----------
   admin.js envuelve cada <input type="file"> del panel con este marcado;
   el input real queda encima, transparente, cubriendo toda la zona, así
   que sigue siendo 100% funcional (clic para elegir archivo, teclado,
   lector de pantalla) incluso si algo en el JS de arriba falla. */
.file-drop {
  position: relative; border: 1.5px dashed var(--border); border-radius: 12px;
  padding: 1.1rem 1rem; text-align: center; cursor: pointer;
  transition: border-color 0.15s var(--ease), background 0.15s var(--ease);
}
.file-drop:hover, .file-drop.is-dragover { border-color: var(--accent); background: var(--accent-soft); }
.file-drop.is-focused { outline: 2px solid var(--accent); outline-offset: 2px; }
.file-drop input[type="file"] { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; }
.file-drop-label { font-size: 0.82rem; color: var(--ink-soft); pointer-events: none; }
.file-drop.has-file .file-drop-label { color: var(--ink); font-weight: 600; }
