/*
  Kabelo UI v1.0 — the design system, as this project consumes it.
  Tagline: Tecnología que impulsa tu estilo.

  Source of truth for the VALUES is `assets/design/tokens.json`, shipped from
  the design package unchanged. This file is the CSS half of it, plus the two
  things a package cannot know: how this codebase serves fonts, and which of
  its conventions must not be broken.

  NOTHING CONSUMES THIS YET, and that is deliberate.

  Every surface still paints itself with its own palette. This file lands first
  so the screens still to be written — the two panel views left in the point of
  sale — are born in the system instead of being born pink and repainted later.
  Migrating an existing surface means pointing its own variables at these and
  checking the result, one surface at a time, never all four at once on a live
  product.

  The accent is copper and it is rationed. The package is explicit: it should
  normally occupy a small part of the interface. It is not the default action
  colour — that is the deep teal.
*/

/*
  Montserrat, self-hosted, same as the font the landing already serves.

  No CDN: this product opens on a phone with two bars of signal inside a salon,
  and a webfont from a third-party domain costs a DNS lookup and a TLS
  handshake before a single letter can be drawn. It is also a variable font, so
  one file covers 400 to 700 instead of four downloads.

  The latin-ext subset only downloads if a character needs it — a business name
  with a letter outside Spanish should not arrive broken, and should not cost
  anything to everyone else either.
*/
@font-face {
  font-family: 'Montserrat';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/fonts/montserrat-v31-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Montserrat';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/fonts/montserrat-v31-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/*
  Fraunces, para los títulos grandes. También propia, por lo mismo.

  Este archivo dice, unas líneas más arriba, que aquí hubo una serif inventada
  —Georgia— buscando "aire de salón", y que se quitó porque meter una segunda
  familia que nadie eligió es tan malo como inventarse los colores. Eso sigue
  siendo cierto: lo que cambió es que ahora la eligió Héctor y entra por la
  puerta, como token del sistema, con su archivo servido desde este dominio y
  disponible para la consola igual que para la página del negocio.

  Sólo pinta títulos: una serif en un botón, en un precio o en una tabla de
  horas se lee peor y más despacio, que es justo lo contrario de lo que hace
  falta en una pantalla que se usa con un cliente delante.

  Variable de 400 a 700 en un archivo: cuatro pesos sin cuatro descargas. Y el
  subconjunto extendido sólo baja si un nombre lo necesita.
*/
@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/fonts/fraunces-v38-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/fonts/fraunces-v38-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  --k-font-sans: 'Montserrat', 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
  /*
    La de los títulos grandes.

    Georgia detrás y no una sans: si Fraunces no llega —red mala, o el archivo
    todavía bajando—, lo que se ve tiene que seguir siendo una serif. Cambiar de
    serif a sans a mitad de carga mueve todo el texto de sitio.
  */
  --k-font-display: 'Fraunces', Georgia, 'Times New Roman', serif;

  /* The brand itself. These two never change between themes. */
  --k-brand: #184A5A;
  --k-accent: #C89A4B;

  /*
    El color de marca cuando hace de TEXTO.

    `--k-brand` pinta fondos de botón, donde el color manda y encima va letra
    blanca. Pero el mismo color como letra sobre el fondo de la página es otra
    cosa: FMNavarro eligió un verde azulado oscuro que sobre blanco se lee
    perfecto y sobre el fondo oscuro da 1.59 de contraste — sus enlaces
    "Reservar →" desaparecían.

    Y el acento tiene el problema al revés: el dorado `#C89A4B` sobre el crema
    de la página da 2.40, así que los ojales de cada sección se leían a medias.

    Estas variantes las calcula `assets/color.js` a partir del color que el
    negocio ya dio: aclarándolo u oscureciéndolo lo justo para llegar a 4.5:1,
    y parando ahí — llevarlo al blanco sería legible y ya no sería su color.

    El valor de aquí es el de fábrica, para cuando no hay negocio que aplicar
    (la landing de la plataforma, la consola) o mientras carga.
  */
  --k-brand-texto: var(--k-brand-texto-claro, var(--k-brand));
  --k-accent-texto: var(--k-accent-texto-claro, #8A6524);

  /* Light. Ivory rather than white: a full-white ground under a whole day of
     use is harsher than it looks in a screenshot. */
  --k-bg: #F8F7F4;
  --k-surface: #FFFFFF;
  --k-surface-raised: #FFFFFF;
  --k-text: #1F2A36;
  --k-text-muted: #66747C;
  --k-border: #E3E5E4;
  /*
    El borde de un CONTROL, que no es el de separar dos cosas.

    `--k-border` está pensado para dividir: un filete casi invisible entre una
    tarjeta y el fondo. Sobre el fondo crema da 1.06 de contraste, y con eso un
    botón blanco de borde suave sobre fondo casi blanco no se ve como un botón
    — se ve como una palabra flotando. Es la mitad del "todo está muy plano".

    Un control se toca, así que su límite tiene que existir. 3.3:1 contra el
    fondo de página, que es lo que pide la norma para el límite de un control
    (WCAG 1.4.11) con un poco de margen. Se ve, y sigue sin gritar.
  */
  --k-border-control: #7F8A86;
  --k-success: #16865C;
  --k-warning: #B7791F;
  --k-danger: #C44242;
  --k-info: #287AA0;

  --k-space-1: 4px;
  --k-space-2: 8px;
  --k-space-3: 12px;
  --k-space-4: 16px;
  --k-space-5: 20px;
  --k-space-6: 24px;
  --k-space-8: 32px;
  --k-space-10: 40px;
  --k-space-12: 48px;
  --k-space-16: 64px;
  --k-space-20: 80px;

  --k-radius-sm: 6px;
  --k-radius-md: 10px;
  --k-radius-lg: 14px;
  --k-radius-xl: 20px;
  --k-radius-pill: 999px;

  --k-fast: 120ms;
  --k-base: 180ms;
  --k-slow: 240ms;

  /*
    La escala tipográfica, tal cual la lámina Foundations.

    Tamaño y altura de línea van juntos porque en la lámina van juntos: un
    título de 32 con interlineado de 22 no es el mismo título.
  */
  --k-display: 40px/48px;
  --k-h1: 32px/40px;
  --k-h2: 24px/32px;
  --k-h3: 20px/28px;
  --k-body-lg: 16px/24px;
  --k-body: 14px/22px;
  --k-small: 12px/18px;
  --k-label: 13px/18px;
  --k-button: 14px/20px;

  /* Las tres alturas de botón de la lámina. El control de formulario sigue en
     44, que es lo que dice COMPONENTS.md para los campos. */
  --k-btn-sm: 32px;
  --k-btn-md: 40px;
  --k-btn-lg: 48px;

  /*
    Elevación, con los valores exactos de la lámina.

    Son cuatro niveles y no tres: superficie, elevada, desplegable y modal. La
    nota al pie de la lámina dice que la profundidad se logra con superficies y
    bordes, no con sombras intensas — por eso los valores son tan bajos.
  */
  /*
    Las tres del paquete, con sus valores exactos.

    Estaban más planas y con otra base de color: `rgba(31, 42, 54, .06)` en vez
    de `rgba(13, 27, 32, .08)`, y la geometría a la mitad. Se escribieron a ojo
    antes de leer el paquete, que es justo lo que Héctor pidió que dejáramos de
    hacer. Una sombra más plana no se ve mal por sí sola: se ve mal al lado de
    una maqueta que sí las tiene.

    `--k-shadow-drop` no está en el paquete y se queda, con nota: la usa el menú
    de cuenta, y es una elevación entre `md` y `lg` que el sistema no nombra.
  */
  --k-shadow-sm: 0 1px 2px rgba(13, 27, 32, .05);
  --k-shadow-md: 0 8px 24px rgba(13, 27, 32, .08);
  --k-shadow-drop: 0 4px 16px rgba(13, 27, 32, .08);
  --k-shadow-lg: 0 18px 48px rgba(13, 27, 32, .12);

  --k-sidebar: 256px;
  --k-sidebar-collapsed: 72px;
  --k-header: 64px;
  /* 44px is the control height AND the minimum touch target. A barber taps
     this with wet hands between clients. */
  --k-control: 44px;

  /*
    El ancho del panel de IA, que el paquete declara y aquí faltaba.

    Todavía no lo usa nadie —el estudio vive fuera del panel— y se declara ahora
    para que nazca con la medida del sistema en vez de con una inventada el día
    que se escriba.

    La barra lateral NO se declara aquí: ya está arriba, con los valores del
    paquete. Estuve a punto de duplicarla con otro nombre.
  */
  --k-ai-panel: 380px;
}

/*
  Dark is a separate palette, not an inversion.

  The dark ground is #0D1B20 and never pure black: black kills the sense of
  depth that separates a raised surface from the one behind it, and the status
  colours are re-picked rather than reused, because #16865C on ivory and on
  near-black are not the same green to a human eye.

  Both selectors, because this codebase sets `data-theme` on the root element
  and the package documents `.dark` as an alternative. Supporting one and not
  the other is how a theme toggle ends up half working.
*/
:root[data-theme="dark"],
.dark {
  /* Las mismas variantes, calculadas contra el fondo oscuro. El interruptor de
     tema no vuelve a pedir nada: las dos existen desde que carga la página. */
  --k-brand-texto: var(--k-brand-texto-oscuro, #7FB3C4);
  --k-accent-texto: var(--k-accent-texto-oscuro, #E0BE7E);

  --k-bg: #0D1B20;
  --k-surface: #14272E;
  --k-surface-raised: #19323A;
  --k-text: #F8F7F4;
  --k-text-muted: #AAB8BD;
  --k-border: #29434B;
  /* En oscuro el control se separa aclarando, no oscureciendo: por debajo del
     fondo no queda sitio. 4.3:1 contra el fondo de página. */
  --k-border-control: #6E8189;
  --k-success: #3BB98A;
  --k-warning: #E5A93D;
  --k-danger: #EF6B6B;
  --k-info: #55A8CB;

  /* En oscuro la lámina dice que la profundidad se logra con superficies y
     bordes, no con sombras intensas: sobre casi negro una sombra no se ve, y
     subirla sólo ensucia. */
  --k-shadow-sm: 0 1px 2px rgba(0, 0, 0, .12);
  --k-shadow-md: 0 8px 24px rgba(0, 0, 0, .18);
  --k-shadow-drop: 0 4px 16px rgba(0, 0, 0, .2);
  --k-shadow-lg: 0 18px 48px rgba(0, 0, 0, .22);
}

/*
  Three primitives, and only three.

  The package lists two dozen components. They are not written here because a
  component nobody has used yet is a guess: these three are what every screen
  in the mockups is actually built from, and the rest earn their place when a
  real screen needs them.
*/

/* The focus ring. Written once because it is the accessibility guarantee that
   is easiest to forget per-component and most obvious when missing. */
.k-focus:focus-visible,
.k-focusable:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--k-brand) 24%, transparent);
}

.k-surface {
  background: var(--k-surface);
  border: 1px solid var(--k-border);
  border-radius: var(--k-radius-lg);
}

.k-raised {
  background: var(--k-surface-raised);
  border: 1px solid var(--k-border);
  border-radius: var(--k-radius-xl);
  box-shadow: var(--k-shadow-md);
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --k-fast: 0ms;
    --k-base: 0ms;
    --k-slow: 0ms;
  }
}

/* --- La foto en grande -------------------------------------------------------

   Vive en el sistema de diseño y no en la hoja de una página porque lo usan
   tres: la página del salón, Mi cuenta y la ficha del cliente en el panel. El
   comportamiento está en `assets/lupa.js`, que también las tres cargan.

   Un `<dialog>` de verdad: el navegador le da la capa de encima, el cierre con
   Escape, el foco atrapado dentro y el fondo inerte. Todo eso a mano son
   cincuenta líneas que se rompen la primera vez que alguien navega con teclado.
*/
.lupa {
  /* `inset: 0` con los cuatro lados fijados: un `<dialog>` se centra solo con
     los márgenes automáticos del navegador, y eso lo encoge al tamaño de su
     contenido. Aquí tiene que ocupar la pantalla entera. */
  position: fixed;
  inset: 0;
  width: 100vw;
  max-width: 100vw;
  height: 100dvh;
  max-height: 100dvh;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  overflow: hidden;
}

/*
  El centrado va en `[open]`, y ése era el error.

  La hoja del navegador trae `dialog:not([open]) { display: none }`. Un
  `display: grid` en `.lupa` a secas la pisa y el visor se queda visible siempre
  — pero puesto sólo en `[open]` no pisa nada y el diálogo cerrado sigue
  cerrado. Sin esta regla los hijos eran posicionados absolutos sobre un bloque
  sin centrar, y la foto salía pegada arriba y a un lado, que es justo lo que se
  vio en la captura.
*/
.lupa[open] {
  display: grid;
  place-items: center;
}

.lupa::backdrop { background: rgba(6, 12, 14, .92); }

.lupa img {
  display: block;
  /* Cabe entera SIEMPRE: una foto vertical de tres mil píxeles recortada por
     arriba y por abajo es justo lo que el visor viene a evitar. */
  max-width: min(92vw, 1100px);
  max-height: 78dvh;
  width: auto;
  height: auto;
  object-fit: contain;
  border-radius: var(--k-radius-md);
}

.lupa-pie {
  position: absolute;
  z-index: 1;
  left: 0; right: 0; bottom: var(--k-space-8);
  margin: 0;
  padding: 0 var(--k-space-6);
  text-align: center;
  color: #f8f7f4;
  font: var(--k-body) var(--k-font-sans);
}
.lupa-pie:empty { display: none; }

/* Los tres controles, con área táctil de verdad: esto se toca con el pulgar en
   una pantalla llena de foto. */
.lupa-cerrar, .lupa-ir {
  position: absolute;
  display: grid;
  place-items: center;
  width: 52px; height: 52px;
  border: 0;
  border-radius: var(--k-radius-pill);
  background: rgba(0, 0, 0, .45);
  color: #fff;
  font-size: 2rem;
  line-height: 1;
  cursor: pointer;
}
/* Los tres van sobre la foto, no en el flujo de la retícula: así el centrado
   de la imagen no cuenta con ellos. */
.lupa-cerrar { top: var(--k-space-4); right: var(--k-space-4); font-size: 1.8rem; }
.lupa-ir[data-lupa-ir="-1"] { left: var(--k-space-3); top: 50%; transform: translateY(-50%); }
.lupa-ir[data-lupa-ir="1"] { right: var(--k-space-3); top: 50%; transform: translateY(-50%); }
.lupa-cerrar:hover, .lupa-ir:hover { background: rgba(0, 0, 0, .7); }
.lupa-cerrar:focus-visible, .lupa-ir:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 2px;
}

/*
  El botón que envuelve una foto de prueba.

  Es un `<button>` y no un `<img>` con un `onclick` para que se llegue con
  tabulador y el lector de pantalla diga que se puede pulsar. Pero no se puede
  VER como un botón: lo que se ve es la foto, y un marco gris alrededor de cada
  miniatura convertiría una rejilla de fotos en una barra de herramientas.

  El `zoom-in` es la única pista, y es la correcta: dice exactamente lo que va a
  pasar al pulsar.
*/
.prueba-lupa {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
  /* Sin esto, el botón hereda el `line-height` del texto y deja una franja
     bajo la foto que desalinea las dos columnas del antes y el después. */
  line-height: 0;
}
.prueba-lupa:focus-visible {
  outline: 2px solid var(--k-brand);
  outline-offset: 2px;
  border-radius: var(--k-radius-md);
}

