/* ============================================================================
   Juicy — Dashboard Design System · POS (lado de productos)
   ----------------------------------------------------------------------------
   Figma: archivo NUEVO — "Juicy POS · Dashboard" (bgAIbrraHKNKn1VF7ZMHBQ),
   frame 2067:7337. OJO: se llama "POS · Cart Fill" pero RENDERIZA EL CARRITO
   VACÍO — el nombre miente. Es solo referencia VISUAL: los tokens de allá pueden
   no llamarse como los de aquí (dicho por el dueño), así que se compara el VALOR.

   Este archivo es la mitad IZQUIERDA: buscador, tabs, y la reja de productos.
   El carrito vive en `ds/cart.css`. La fase se partió así porque el Figma también:
   `Cart Header Search` + `Cart Grid Wrapper` de un lado, `Cart Header Actions` +
   `Cart Sidebar` del otro.

   Markup: templates/template-parts/blocks/pos.php

   Contrato con pos.js / main.js — NO renombrar: `pos_open` / `pos_closed`,
   `loading`, `show_results`, `active` (tab y grid), `outofstock`,
   `data-tabs-wrapper` / `data-tabs-header` / `data-show-tab`, `#pos_search`,
   `#pos_search_results`, `#pos_search_form`.
   ============================================================================ */

/* ---- Tokens ---------------------------------------------------------------- */
:root {
  /* El carril del carrito. Estaba a mano en tres sitios (450 de ancho, 470 =
     450+20 de margen, y el 20 suelto). Ver nota 1. */
  --pos-cart-width: 450px;
  --pos-cart-gap:   20px;
}

/* ---- Estructura ------------------------------------------------------------ */

.page-pos #dashboard_page_content {
  padding: 15px 30px 0 15px;
}

/* En la caja, el hueco del "título" no lleva un título: lleva los chips de la SESIÓN
   (sucursal, bloqueo, cierre) y lo que el vertical cuelgue ahí mismo —la mesa en curso,
   el botón del salón—. Van en FILA.
   Sin esto se APILABAN: cada uno es un bloque, así que el segundo caía a una segunda
   línea y se salía del header de 70px. Pasaba ya con la mesa en curso puesta. Con un
   solo hijo —POS y Espresso— no cambia nada. */
.page-pos #dashboard_title_wrapper {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

/* Sin caja abierta el POS se apaga: no es decoración, es el gate visual de que
   no se puede vender. Lo enciende `pos_open` desde el PHP. */
.pos_page_main_wrapper.pos_closed {
  opacity: 0.5;
  filter: grayscale(1);
}

.pos_page_main {
  width: calc(100% - (var(--pos-cart-width) + var(--pos-cart-gap)));
}

.pos_page_cart {
  width: var(--pos-cart-width);
  margin-left: var(--pos-cart-gap);
}

.pos_search_header,
.pos_product_archive {
  padding: 15px;
  background: var(--surface-page);
  border-radius: var(--radius-md);
  margin-bottom: 15px;
}

/* 205 = header del dashboard (70+15) + buscador (70+15) + respiro (35). Queda a
   mano: es aritmética de esta pantalla, no un token del sistema. */
.pos_product_archive,
.cart {
  height: calc(100dvh - 205px);
}

/* ---- Buscador -------------------------------------------------------------- */

/* El campo y el botón de alta al vuelo son HERMANOS, no padre e hijo. Ver nota 2. */
.pos_search_header_inner {
  display: flex;
  align-items: center;
  gap: 15px;
}

.pos_search_header_inner .field {
  flex: 1;
  min-width: 0;
}

#pos_search_results {
  position: absolute;
  width: 100%;
  bottom: 0;
  left: 0;
  background: var(--surface-page);
  z-index: 9;
  transform: translateY(100%);
  border: var(--stroke-thin) solid var(--neutral-100);
}

#pos_search_results:empty {
  display: none;
}

/* La ✕ de limpiar solo existe cuando hay resultados (`show_results` lo pone pos.js). */
.remove_results {
  display: none;
}

.show_results .remove_results {
  display: inline-flex;
}

.search_result {
  padding: 15px;
  gap: 15px;
  border-bottom: var(--stroke-thin) solid var(--border-default);
  cursor: pointer;
  transition: all 0.3s;
}

.search_result:last-child {
  border-bottom: none;
}

.search_result:hover {
  background: var(--border-default);
}

.search_result_image {
  width: 50px;
  background: var(--surface-page);
  border-radius: var(--radius-md);
}

.search_result_image img {
  float: left;
  width: 50px;
  border-radius: var(--radius-md);
  box-shadow: 0 0 3px rgba(0, 0, 0, 0.2);
}

.search_result_name {
  font-size: 14px;
  font-weight: bold;
  color: var(--text-primary);
  text-transform: uppercase;
}

.search_result_sku {
  font-size: 12px;
  font-weight: 500;
  color: var(--text-muted);
  text-transform: none;
}

.search_result_price {
  font-size: 16px;
  font-weight: bold;
  color: var(--text-muted);
}

/* ---- Barra de tabs --------------------------------------------------------- */

/* SUPERFICIE OSCURA. `--surface-raised` es el token del DS para esto — y
   semantics.css ya lo dice en su comentario: "oscuro: barra de tabs del POS".
   Igual que la caja del login, voltea SU tinta para que lo de encima se lea.
   Ver nota 3. */
.pos_products_nav {
  position: relative;
  display: flex;
  align-items: center;
  border-radius: 7px;
  background: var(--surface-raised);
  border: 3px solid var(--surface-raised);

  --text-primary: var(--neutral-white);
  color: var(--text-primary);
}

/* La tinta de los CONTROLES que van encima también se invierte. El chip `ghost`
   pinta su icono con `--tone-line` (icon-chip.css), no con `--text-primary`, así
   que voltear solo el texto dejaba el icono del tono por defecto — cian sobre la
   barra oscura. Lo cazó la foto, no la lectura: el CSS "se veía bien". Es la
   misma lección que el checkbox del login (F2f), calcada. */
.pos_products_nav .icon-chip {
  --tone-line: var(--neutral-white);
  --tone-fill: rgba(255, 255, 255, 0.15);
  --tone-fg:   var(--neutral-white);
}

.pos_closed .pos_categories_tabs {
  opacity: 0;
  pointer-events: none;
}

/* El desborde horizontal y el esconder su barra los pone `[data-hscroll]`
   (ds/utilities.css), que además la hace movible con la rueda y arrastrando.
   Aquí solo queda cómo ocupa su sitio en la barra. La `scrollbar-width: none`
   que vivía aquí solo escondía la barra en Firefox: en Chrome hacía falta el
   `::-webkit-scrollbar`, y de ahí venía la barra que se veía bajo los tabs. */
.pos_categories_tabs {
  flex: 1;
  min-width: 0;
}

.pos_tab {
  padding: 15px 20px;
  text-transform: uppercase;
  font-size: 12px;
  font-weight: 500;
  color: var(--text-primary);
  cursor: pointer;
  border-radius: var(--radius-md);
  white-space: nowrap;
}

/* El activo invierte: papel blanco, tinta oscura. Declara SU tinta junto a su
   papel, que es la regla que dejó F2f — si solo pusiera el fondo, heredaría el
   blanco de la barra y saldría blanco sobre blanco. */
.pos_tab.active {
  background: var(--neutral-white);
  color: var(--neutral-500);
}

/* El slot de acciones de la barra (hoy: ordenar). 44 en el Figma, que es lo que
   deja 30 de chip + 7 de aire a cada lado. */
.pos_products_nav_actions {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
}

/* El popover de orden vive DENTRO de la barra oscura, que invierte la tinta a
   blanca (`--text-primary: white`). Pero el bubble se pinta SOBRE el grid
   (blanco), así que hay que des-invertir o su texto sale blanco sobre blanco.
   Es el mismo gesto del par papel+tinta de `.pos_tab.active`. */
.pos_products_nav .bubble {
  --text-primary: var(--neutral-500);
  color: var(--neutral-500);
}

/* La opción de orden aplicada (persistida en localStorage `pos_sort`). */
.pos_sort_menu .bubble__item.is-active {
  color: var(--action-primary-default);
  font-weight: 600;
}

/* ---- La reja --------------------------------------------------------------- */

.pos_product_archives {
  height: calc(100% - 50px);
  overflow: auto;
  scrollbar-width: none;
}

/* El velo + el spinner de "cargando". `loading` lo pone pos.js. */
.pos_product_archive::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(255, 255, 255, 0.95);
  z-index: 2;
  visibility: hidden;
  opacity: 0;
}

.pos_product_archive::after {
  content: '';
  position: absolute;
  top: calc(50% - 25px);
  left: calc(50% - 25px);
  width: var(--control-md);
  height: var(--control-md);
  border-width: 5px;
  border-style: solid;
  border-color: var(--neutral-500) var(--neutral-500) var(--neutral-500) transparent;
  border-radius: var(--radius-round);
  z-index: 3;
  animation: loadingRotate 1s infinite ease;
  visibility: hidden;
  opacity: 0;
}

.pos_page_main_wrapper.loading .pos_product_archive::before,
.pos_page_main_wrapper.loading .pos_product_archive::after {
  visibility: visible;
  opacity: 1;
}

.pos_product_archive_grid_wrapper {
  display: none;
}

/* `block` y NO `inline-block`. Un inline-block se encoge a su contenido, así que
   la reja no tenía un ancho definido que llenar y `auto-fill` colapsaba a las
   columnas mínimas. Con las 6 fijas de antes daba igual —forzaban 6 pasara lo que
   pasara— y por eso el bug estaba dormido. Ver nota 4. */
.pos_product_archive_grid_wrapper.active {
  display: block;
}

/* La reja respira sola: `auto-fill` + un mínimo. Ver nota 4. */
.pos_product_archive_grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(135px, 1fr));
  gap: 20px;
  padding: 20px 10px;
}

/* ---- El producto ----------------------------------------------------------- */

.pos_product_item {
  cursor: pointer;
  transition: all 0.3s;
}

.pos_product_item:hover {
  background: var(--neutral-100);
  border-radius: var(--radius-md);
}

.pos_product_item_image {
  background: var(--surface-page);
  border-radius: var(--radius-md);
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
  overflow: hidden;
}

.pos_product_item_image img {
  float: left;
  width: 100%;
}

.product_title {
  text-transform: uppercase;
  font-size: 11px;
  font-weight: 500;
}

.product_price {
  font-weight: bold;
  font-size: 13px;
  margin-top: 4px;
}

/* ---- Agotado --------------------------------------------------------------- */

.pos_product_item.outofstock {
  text-decoration: line-through;
  pointer-events: none;
  color: var(--text-muted);
}

.outofstock .pos_product_item_image img {
  filter: grayscale(1);
  opacity: 0.5;
}

.outofstock_banner {
  position: absolute;
  top: 15px;
  right: -30px;
  width: 100%;
  height: 30px;
  line-height: 30px;
  font-size: 11px;
  color: var(--text-on-color);
  background: var(--neutral-300);
  text-transform: uppercase;
  transform: rotate(40deg);
  display: none;
}

.pos_product_item.outofstock .outofstock_banner {
  display: inline-block;
}

/* ---- Opciones de producto variable (dentro de su lightbox) ----------------- */

.attribute_label {
  text-align: center;
  display: block;
  margin-bottom: 15px;
  font-weight: 600;
  text-transform: uppercase;
}

.attribute_option_label input {
  display: none;
}

.cart_option {
  height: 60px;
  border: var(--stroke-thin) solid var(--neutral-300);
  color: var(--text-primary);
  border-radius: var(--radius-md);
  padding: 10px;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.3s;
}

.cart_option:hover {
  background: var(--neutral-100);
}

.attribute_option_label input:checked + .cart_option {
  background: var(--neutral-300);
  color: var(--text-on-color);
}

/* ============================================================================
   NOTAS

   1. EL CARRIL DEL CARRITO ESTABA EN TRES SITIOS Y NO CUADRABAN SOLOS:
      `.pos_page_cart{width:450px; margin-left:20px}` y
      `.pos_page_main{width:calc(100% - 470px)}`. El 470 era 450+20 calculado a
      mano — o sea que cambiar el ancho del carrito pedía acordarse de sumar. Ya
      no: `--pos-cart-width` y `--pos-cart-gap`, y el 470 se calcula solo.

   2. EL BOTÓN DE ALTA AL VUELO SALIÓ DEL CAMPO (decisión del dueño; el Figma lo
      pone en `On-fly Add Product`, 40x40, en x=815 con el input midiendo 790).
      Antes vivía DENTRO, en `.input_actions`, junto a la ✕ de limpiar. Y tenía
      sentido cuando el campo era un `<input>` pelón, pero desde F1 el campo es
      `.field > .field__control > .input`, y el DS dice que lo que va dentro del
      `.input` es una ACCIÓN DEL CAMPO (`Add Action`: limpiar lo escrito). Dar de
      alta un producto no es una acción del campo — es una acción de la pantalla
      que casualmente estaba pegada al campo. Fuera, es un hermano de 40 (el
      mismo `--control-md` del campo, por eso "igual que el field").
      La ✕ de limpiar resultados SÍ se queda dentro: esa sí es del campo.

   3. LA BARRA DE TABS ES LA SEGUNDA SUPERFICIE OSCURA DEL PRODUCTO, y aquí el
      token ya existía con el nombre puesto: `--surface-raised` (neutral/500), y
      su comentario en semantics.css dice literalmente "oscuro: barra de tabs del
      POS". O sea que el DS ya sabía de esta barra antes de que la barra lo
      supiera: pintaba `var(--neutral-500)` a pelo, el primitivo, teniendo su
      semántica a mano.
      Voltea la tinta igual que la caja del login (F2f). Van DOS consumidores del
      mismo patrón; a la tercera se promueve a `ds/` (regla 8). El tab activo es
      el caso interesante: invierte OTRA VEZ (papel blanco sobre barra oscura) y
      por eso declara su tinta junto a su papel — es exactamente la regla del par
      que dejó F2f, aplicada dos niveles seguidos.

   4. LA REJA YA NO CUENTA COLUMNAS. Había tres media queries con 6/5/4 columnas
      fijas — números que no se corresponden con nada salvo el ancho de pantalla
      del que los escribió. Ahora `auto-fill` + `minmax(135px, 1fr)`: la reja mete
      las que quepan. El 135 sale del Figma (146.8 de item con 844 de ancho útil
      = 5 columnas), redondeado para abajo para que a 1440 dé las mismas 5 que el
      diseño. Con el sidebar expandido a ≥1920 caben más, que es lo que se quiere.
      Es menos CSS y además responde al ancho REAL disponible, no al de la ventana
      — que no es lo mismo cuando el sidebar reserva 230 (ver ds/sidebar.css nota 4).
   ============================================================================ */
