Files
Autoparts-DB/pos/templates/inventory.html
consultoria-as 6558e289f3 fix(pos): reemplazar datos demo con datos reales del empleado logueado
- Nuevo app-init.js: auth check, inyecta nombre/rol real del empleado
  en sidebar, header, y status bar de TODAS las páginas
- Eliminados 6 productos demo hardcodeados del catálogo
- Sidebar muestra nombre real del usuario logueado
- Links de navegación marcan la página activa correctamente
- Función posLogout() global para cerrar sesión

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 20:09:12 +00:00

2530 lines
93 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="es" data-theme="industrial">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Inventario — Nexus Autoparts POS</title>
<link rel="stylesheet" href="/pos/static/css/tokens.css" />
<style>
/* =========================================================================
BASE RESET & SHELL
========================================================================= */
*, *::before, *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html, body {
height: 100%;
}
body {
font-family: var(--font-body);
font-size: var(--text-body-sm);
color: var(--color-text-primary);
background-color: var(--color-bg-base);
transition: background-color var(--duration-normal) var(--ease-in-out),
color var(--duration-normal) var(--ease-in-out);
overflow: hidden;
}
[data-theme="modern"] body {
background-color: var(--color-bg-base);
background-image: radial-gradient(
circle,
var(--dot-grid-color) 1px,
transparent 1px
);
background-size: var(--dot-grid-size) var(--dot-grid-size);
}
/* =========================================================================
THEME SWITCHER BAR
========================================================================= */
.theme-bar {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: var(--z-toast);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 var(--space-5);
background: var(--color-bg-overlay);
border-bottom: 1px solid var(--color-border);
backdrop-filter: blur(10px);
height: 36px;
}
[data-theme="industrial"] .theme-bar {
background: rgba(13, 13, 13, 0.95);
border-bottom-color: var(--color-primary-muted);
}
.theme-bar__left {
display: flex;
align-items: center;
gap: var(--space-3);
}
.theme-bar__store {
display: flex;
align-items: center;
gap: var(--space-2);
font-family: var(--font-heading);
font-weight: var(--heading-weight-primary);
font-size: 0.75rem;
letter-spacing: var(--tracking-widest);
text-transform: uppercase;
color: var(--color-text-accent);
}
.theme-bar__dot {
width: 6px;
height: 6px;
background: var(--color-success);
border-radius: var(--radius-full);
box-shadow: 0 0 6px var(--color-success);
animation: blink 2.5s ease-in-out infinite;
}
@keyframes blink {
0%, 100% { opacity: 1; }
50% { opacity: 0.35; }
}
.theme-bar__sep {
width: 1px;
height: 16px;
background: var(--color-border);
}
.theme-bar__label {
font-size: var(--text-caption);
color: var(--color-text-muted);
letter-spacing: var(--tracking-wide);
text-transform: uppercase;
}
.theme-bar__right {
display: flex;
align-items: center;
gap: var(--space-2);
}
.theme-btn {
display: inline-flex;
align-items: center;
gap: var(--space-1);
padding: 2px var(--space-3);
border: 1px solid var(--color-border);
border-radius: var(--radius-full);
background: transparent;
color: var(--color-text-secondary);
font-family: var(--font-body);
font-size: var(--text-caption);
font-weight: var(--font-weight-semibold);
cursor: pointer;
transition: var(--transition-fast);
letter-spacing: var(--tracking-wide);
}
.theme-btn:hover {
border-color: var(--color-primary);
color: var(--color-primary);
}
.theme-btn.is-active {
background: var(--color-primary);
border-color: var(--color-primary);
color: var(--color-text-inverse);
}
.theme-btn__swatch {
width: 8px;
height: 8px;
border-radius: var(--radius-full);
}
.theme-btn--industrial .theme-btn__swatch { background: #F5A623; }
.theme-btn--modern .theme-btn__swatch { background: #FF6B35; }
/* =========================================================================
APP LAYOUT
========================================================================= */
.app-shell {
display: flex;
height: 100vh;
padding-top: 36px;
}
/* =========================================================================
SIDEBAR
========================================================================= */
.sidebar {
width: 260px;
flex-shrink: 0;
display: flex;
flex-direction: column;
background: var(--color-bg-elevated);
border-right: 1px solid var(--color-border);
overflow-y: auto;
scrollbar-width: thin;
scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track);
}
.sidebar::-webkit-scrollbar { width: 4px; }
.sidebar::-webkit-scrollbar-track { background: var(--scrollbar-track); }
.sidebar::-webkit-scrollbar-thumb { background: var(--scrollbar-thumb); border-radius: var(--radius-full); }
/* Brand */
.sidebar__brand {
display: flex;
align-items: center;
gap: var(--space-3);
padding: var(--space-4) var(--space-4) var(--space-3);
border-bottom: 1px solid var(--color-border);
flex-shrink: 0;
}
.brand-logo {
width: 36px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
background: var(--color-primary);
color: var(--color-text-inverse);
font-family: var(--font-heading);
font-weight: var(--heading-weight-primary);
font-size: 1.125rem;
letter-spacing: -0.04em;
flex-shrink: 0;
}
[data-theme="industrial"] .brand-logo {
clip-path: polygon(0 0, calc(100% - 9px) 0, 100% 9px, 100% 100%, 0 100%);
}
[data-theme="modern"] .brand-logo {
border-radius: var(--radius-md);
}
.brand-name__primary {
font-family: var(--font-heading);
font-weight: var(--heading-weight-primary);
font-size: 0.9375rem;
letter-spacing: var(--tracking-wide);
text-transform: uppercase;
color: var(--color-text-primary);
line-height: 1;
}
.brand-name__sub {
font-size: var(--text-caption);
color: var(--color-text-muted);
letter-spacing: var(--tracking-wider);
text-transform: uppercase;
margin-top: 2px;
}
/* Navigation */
.sidebar__nav {
flex: 1;
padding: var(--space-3) 0;
}
.nav-section-label {
padding: var(--space-3) var(--space-4) var(--space-1);
font-size: 0.6875rem;
font-weight: var(--font-weight-semibold);
letter-spacing: var(--tracking-widest);
text-transform: uppercase;
color: var(--color-text-muted);
}
.nav-item {
display: flex;
align-items: center;
gap: var(--space-3);
padding: var(--space-2) var(--space-4);
color: var(--color-text-secondary);
text-decoration: none;
font-size: var(--text-body-sm);
font-weight: var(--font-weight-regular);
border-left: 3px solid transparent;
transition: var(--transition-fast);
cursor: pointer;
}
.nav-item:hover {
background: var(--color-surface-2);
color: var(--color-text-primary);
}
.nav-item.is-active {
background: var(--color-primary-muted);
color: var(--color-primary);
border-left-color: var(--color-primary);
font-weight: var(--font-weight-semibold);
}
.nav-item__icon {
width: 18px;
height: 18px;
flex-shrink: 0;
opacity: 0.7;
}
.nav-item.is-active .nav-item__icon {
opacity: 1;
}
/* Sidebar footer */
.sidebar__footer {
padding: var(--space-3) var(--space-4);
border-top: 1px solid var(--color-border);
display: flex;
align-items: center;
gap: var(--space-2);
}
.sidebar__user-avatar {
width: 28px;
height: 28px;
border-radius: var(--radius-full);
background: var(--color-primary);
color: var(--color-text-inverse);
display: flex;
align-items: center;
justify-content: center;
font-size: var(--text-caption);
font-weight: var(--font-weight-bold);
flex-shrink: 0;
}
.sidebar__user-info { flex: 1; overflow: hidden; }
.sidebar__user-name {
font-size: var(--text-body-sm);
font-weight: var(--font-weight-semibold);
color: var(--color-text-primary);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.sidebar__user-role {
font-size: var(--text-caption);
color: var(--color-text-muted);
}
/* =========================================================================
MAIN CONTENT
========================================================================= */
.main {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
min-width: 0;
}
/* ---- Page Header ---- */
.page-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: var(--space-4) var(--space-6);
background: var(--color-bg-elevated);
border-bottom: 1px solid var(--color-border);
flex-shrink: 0;
}
[data-theme="industrial"] .page-header {
background: var(--color-surface-1);
}
.page-header__title-group { display: flex; flex-direction: column; gap: 2px; }
.page-header__eyebrow {
font-size: var(--text-caption);
font-weight: var(--font-weight-semibold);
letter-spacing: var(--tracking-widest);
text-transform: uppercase;
color: var(--color-text-muted);
}
.page-header__title {
font-family: var(--font-heading);
font-weight: var(--heading-weight-primary);
font-size: var(--text-h4);
letter-spacing: var(--heading-tracking-h4);
color: var(--color-text-primary);
line-height: 1.2;
}
[data-theme="industrial"] .page-header__title {
text-transform: uppercase;
}
.page-header__actions {
display: flex;
align-items: center;
gap: var(--space-3);
}
/* ---- Summary Cards ---- */
.summary-strip {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: var(--space-4);
padding: var(--space-4) var(--space-6);
background: var(--color-bg-base);
border-bottom: 1px solid var(--color-border);
flex-shrink: 0;
}
[data-theme="modern"] .summary-strip {
background: transparent;
}
.summary-card {
background: var(--color-bg-elevated);
border: 1px solid var(--color-border);
border-radius: var(--radius-lg);
padding: var(--space-4) var(--space-5);
display: flex;
align-items: flex-start;
gap: var(--space-3);
box-shadow: var(--shadow-sm);
transition: var(--transition-normal);
}
.summary-card:hover {
box-shadow: var(--shadow-md);
border-color: var(--color-border-strong);
}
[data-theme="industrial"] .summary-card {
border-left: 3px solid var(--color-primary);
}
[data-theme="modern"] .summary-card {
background: var(--color-bg-overlay);
}
.summary-card__icon {
width: 38px;
height: 38px;
border-radius: var(--radius-md);
background: var(--color-primary-muted);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.summary-card__icon svg {
width: 20px;
height: 20px;
stroke: var(--color-primary);
fill: none;
stroke-width: 1.75;
stroke-linecap: round;
stroke-linejoin: round;
}
.summary-card__icon--alert { background: rgba(239,68,68,.12); }
.summary-card__icon--alert svg { stroke: var(--color-error); }
.summary-card__icon--value { background: rgba(34,197,94,.12); }
.summary-card__icon--value svg { stroke: var(--color-success); }
.summary-card__icon--time { background: var(--color-primary-muted); }
.summary-card__icon--time svg { stroke: var(--color-primary); }
.summary-card__body { flex: 1; min-width: 0; }
.summary-card__label {
font-size: var(--text-caption);
font-weight: var(--font-weight-semibold);
letter-spacing: var(--tracking-wider);
text-transform: uppercase;
color: var(--color-text-muted);
margin-bottom: var(--space-1);
}
.summary-card__value {
font-family: var(--font-heading);
font-weight: var(--heading-weight-primary);
font-size: 1.5rem;
color: var(--color-text-primary);
line-height: 1.1;
}
.summary-card__sub {
font-size: var(--text-caption);
color: var(--color-text-muted);
margin-top: 2px;
}
.summary-card__delta {
font-size: var(--text-caption);
font-weight: var(--font-weight-semibold);
margin-top: 2px;
}
.summary-card__delta--up { color: var(--color-success); }
.summary-card__delta--down { color: var(--color-error); }
/* ---- Tabs Row ---- */
.tabs-row {
display: flex;
align-items: stretch;
gap: 0;
padding: 0 var(--space-6);
background: var(--color-bg-elevated);
border-bottom: 1px solid var(--color-border);
flex-shrink: 0;
overflow-x: auto;
scrollbar-width: none;
}
.tabs-row::-webkit-scrollbar { display: none; }
[data-theme="industrial"] .tabs-row {
background: var(--color-surface-1);
}
.tab-btn {
display: inline-flex;
align-items: center;
gap: var(--space-2);
padding: var(--space-3) var(--space-4);
border: none;
border-bottom: 2px solid transparent;
background: transparent;
color: var(--color-text-muted);
font-family: var(--font-body);
font-size: var(--text-body-sm);
font-weight: var(--font-weight-semibold);
cursor: pointer;
white-space: nowrap;
transition: var(--transition-fast);
letter-spacing: var(--tracking-wide);
text-transform: uppercase;
position: relative;
}
.tab-btn:hover {
color: var(--color-text-primary);
background: var(--color-surface-2);
}
.tab-btn.is-active {
color: var(--color-primary);
border-bottom-color: var(--color-primary);
}
.tab-btn__badge {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 18px;
height: 18px;
padding: 0 var(--space-1);
border-radius: var(--radius-full);
background: var(--color-primary-muted);
color: var(--color-primary);
font-size: 0.6875rem;
font-weight: var(--font-weight-bold);
}
.tab-btn.is-active .tab-btn__badge {
background: var(--color-primary);
color: var(--color-text-inverse);
}
.tab-btn__badge--alert {
background: rgba(239,68,68,.15);
color: var(--color-error);
}
.tab-btn.is-active .tab-btn__badge--alert {
background: var(--color-error);
color: #fff;
}
/* ---- Tab Panels ---- */
.tab-panels {
flex: 1;
overflow-y: auto;
scrollbar-width: thin;
scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track);
}
.tab-panels::-webkit-scrollbar { width: 6px; }
.tab-panels::-webkit-scrollbar-track { background: var(--scrollbar-track); }
.tab-panels::-webkit-scrollbar-thumb { background: var(--scrollbar-thumb); border-radius: var(--radius-full); }
.tab-panel {
display: none;
padding: var(--space-5) var(--space-6);
}
.tab-panel.is-active {
display: block;
}
/* =========================================================================
TOOLBAR (search, filters, actions)
========================================================================= */
.toolbar {
display: flex;
align-items: center;
gap: var(--space-3);
margin-bottom: var(--space-4);
flex-wrap: wrap;
}
.search-box {
display: flex;
align-items: center;
gap: var(--space-2);
background: var(--color-bg-elevated);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
padding: 0 var(--space-3);
height: 36px;
flex: 1;
min-width: 200px;
max-width: 360px;
transition: var(--transition-fast);
}
.search-box:focus-within {
border-color: var(--color-border-focus);
box-shadow: var(--shadow-accent);
}
.search-box svg {
width: 15px;
height: 15px;
stroke: var(--color-text-muted);
fill: none;
stroke-width: 2;
stroke-linecap: round;
flex-shrink: 0;
}
.search-box input {
flex: 1;
background: transparent;
border: none;
outline: none;
color: var(--color-text-primary);
font-family: var(--font-body);
font-size: var(--text-body-sm);
}
.search-box input::placeholder {
color: var(--color-text-muted);
}
.select-filter {
height: 36px;
padding: 0 var(--space-3);
background: var(--color-bg-elevated);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
color: var(--color-text-secondary);
font-family: var(--font-body);
font-size: var(--text-body-sm);
cursor: pointer;
outline: none;
transition: var(--transition-fast);
}
.select-filter:focus {
border-color: var(--color-border-focus);
box-shadow: var(--shadow-accent);
}
.toolbar__spacer { flex: 1; }
/* =========================================================================
BUTTONS
========================================================================= */
.btn {
display: inline-flex;
align-items: center;
gap: var(--space-2);
padding: 0 var(--space-4);
height: 36px;
border-radius: var(--radius-md);
font-family: var(--font-body);
font-size: var(--text-body-sm);
font-weight: var(--font-weight-semibold);
letter-spacing: var(--tracking-wide);
cursor: pointer;
border: 1px solid transparent;
transition: var(--transition-fast);
text-decoration: none;
white-space: nowrap;
}
.btn svg {
width: 15px;
height: 15px;
stroke: currentColor;
fill: none;
stroke-width: 2;
stroke-linecap: round;
stroke-linejoin: round;
flex-shrink: 0;
}
.btn--primary {
background: var(--btn-primary-bg);
color: var(--btn-primary-text);
border-color: var(--btn-primary-border);
}
.btn--primary:hover {
background: var(--btn-primary-bg-hover);
}
.btn--secondary {
background: var(--btn-secondary-bg);
color: var(--btn-secondary-text);
border-color: var(--btn-secondary-border);
}
.btn--secondary:hover {
background: var(--btn-secondary-bg-hover);
}
.btn--ghost {
background: var(--btn-ghost-bg);
color: var(--btn-ghost-text);
border-color: var(--btn-ghost-border);
}
.btn--ghost:hover {
background: var(--color-surface-2);
border-color: var(--color-border-strong);
color: var(--color-text-primary);
}
.btn--sm {
height: 28px;
padding: 0 var(--space-3);
font-size: var(--text-caption);
}
/* =========================================================================
DATA TABLE
========================================================================= */
.table-wrapper {
background: var(--color-bg-elevated);
border: 1px solid var(--color-border);
border-radius: var(--radius-lg);
overflow: hidden;
box-shadow: var(--shadow-sm);
}
[data-theme="modern"] .table-wrapper {
background: var(--color-bg-overlay);
}
.data-table {
width: 100%;
border-collapse: collapse;
font-size: var(--text-body-sm);
}
.data-table thead {
background: var(--color-surface-2);
border-bottom: 1px solid var(--color-border);
}
[data-theme="industrial"] .data-table thead {
background: var(--color-surface-3);
}
.data-table th {
padding: var(--space-3) var(--space-4);
text-align: left;
font-size: var(--text-caption);
font-weight: var(--font-weight-semibold);
letter-spacing: var(--tracking-wider);
text-transform: uppercase;
color: var(--color-text-muted);
white-space: nowrap;
}
.data-table th:first-child { padding-left: var(--space-5); }
.data-table th:last-child { padding-right: var(--space-5); }
.data-table tbody tr {
border-bottom: 1px solid var(--color-border);
transition: background var(--duration-fast) var(--ease-in-out);
}
.data-table tbody tr:last-child {
border-bottom: none;
}
.data-table tbody tr:hover {
background: var(--color-surface-2);
}
.data-table td {
padding: var(--space-3) var(--space-4);
color: var(--color-text-secondary);
vertical-align: middle;
}
.data-table td:first-child { padding-left: var(--space-5); }
.data-table td:last-child { padding-right: var(--space-5); }
.data-table .td--primary {
color: var(--color-text-primary);
font-weight: var(--font-weight-semibold);
}
.data-table .td--mono {
font-family: var(--font-mono);
font-size: 0.8125rem;
color: var(--color-text-accent);
}
.data-table .td--amount {
font-family: var(--font-mono);
font-size: 0.8125rem;
color: var(--color-text-primary);
font-weight: var(--font-weight-semibold);
}
/* =========================================================================
BADGES / STATUS PILLS
========================================================================= */
.badge {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 2px var(--space-2);
border-radius: var(--radius-full);
font-size: 0.6875rem;
font-weight: var(--font-weight-bold);
letter-spacing: var(--tracking-wide);
text-transform: uppercase;
white-space: nowrap;
}
.badge::before {
content: '';
width: 5px;
height: 5px;
border-radius: var(--radius-full);
background: currentColor;
flex-shrink: 0;
}
.badge--ok {
background: rgba(34, 197, 94, 0.15);
color: var(--color-success);
}
.badge--low {
background: rgba(239, 68, 68, 0.15);
color: var(--color-error);
}
.badge--over {
background: rgba(234, 179, 8, 0.15);
color: var(--color-warning);
}
.badge--pending {
background: var(--color-primary-muted);
color: var(--color-primary);
}
.badge--complete {
background: rgba(34, 197, 94, 0.15);
color: var(--color-success);
}
.badge--transit {
background: rgba(99, 102, 241, 0.15);
color: #818cf8;
}
.badge--cancelled {
background: rgba(115, 115, 115, 0.15);
color: var(--color-text-muted);
}
.badge--damage {
background: rgba(239, 68, 68, 0.15);
color: var(--color-error);
}
.badge--shrinkage {
background: rgba(234, 179, 8, 0.15);
color: var(--color-warning);
}
.badge--correction {
background: var(--color-primary-muted);
color: var(--color-primary);
}
.badge--partial {
background: rgba(234, 179, 8, 0.15);
color: var(--color-warning);
}
/* =========================================================================
ALERT CARDS (Tab Alertas)
========================================================================= */
.alerts-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: var(--space-4);
}
.alert-card {
background: var(--color-bg-elevated);
border: 1px solid var(--color-border);
border-radius: var(--radius-lg);
padding: var(--space-4) var(--space-5);
display: flex;
gap: var(--space-4);
box-shadow: var(--shadow-sm);
transition: var(--transition-normal);
position: relative;
overflow: hidden;
}
[data-theme="modern"] .alert-card {
background: var(--color-bg-overlay);
}
.alert-card::before {
content: '';
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 4px;
}
.alert-card--critical::before { background: var(--color-error); }
.alert-card--warning::before { background: var(--color-warning); }
.alert-card--info::before { background: #818cf8; }
.alert-card--accent::before { background: var(--color-primary); }
.alert-card:hover {
box-shadow: var(--shadow-md);
transform: translateY(-1px);
}
.alert-card__icon {
width: 40px;
height: 40px;
border-radius: var(--radius-md);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.alert-card__icon svg {
width: 22px;
height: 22px;
fill: none;
stroke-width: 1.75;
stroke-linecap: round;
stroke-linejoin: round;
}
.alert-card--critical .alert-card__icon { background: rgba(239,68,68,.15); }
.alert-card--critical .alert-card__icon svg { stroke: var(--color-error); }
.alert-card--warning .alert-card__icon { background: rgba(234,179,8,.15); }
.alert-card--warning .alert-card__icon svg { stroke: var(--color-warning); }
.alert-card--info .alert-card__icon { background: rgba(99,102,241,.15); }
.alert-card--info .alert-card__icon svg { stroke: #818cf8; }
.alert-card--accent .alert-card__icon { background: var(--color-primary-muted); }
.alert-card--accent .alert-card__icon svg { stroke: var(--color-primary); }
.alert-card__body { flex: 1; min-width: 0; }
.alert-card__title {
font-weight: var(--font-weight-semibold);
font-size: var(--text-body-sm);
color: var(--color-text-primary);
margin-bottom: 2px;
}
.alert-card__desc {
font-size: var(--text-caption);
color: var(--color-text-muted);
margin-bottom: var(--space-3);
line-height: var(--leading-caption);
}
.alert-card__meta {
display: flex;
align-items: center;
gap: var(--space-3);
flex-wrap: wrap;
}
.alert-card__count {
font-family: var(--font-heading);
font-weight: var(--heading-weight-primary);
font-size: 1.5rem;
line-height: 1;
}
.alert-card--critical .alert-card__count { color: var(--color-error); }
.alert-card--warning .alert-card__count { color: var(--color-warning); }
.alert-card--info .alert-card__count { color: #818cf8; }
.alert-card--accent .alert-card__count { color: var(--color-primary); }
.alert-card__count-label {
font-size: var(--text-caption);
color: var(--color-text-muted);
}
/* =========================================================================
ALERTS SECTION HEADER
========================================================================= */
.section-heading {
display: flex;
align-items: center;
gap: var(--space-3);
margin-bottom: var(--space-4);
}
.section-heading__title {
font-family: var(--font-heading);
font-weight: var(--heading-weight-secondary);
font-size: var(--text-h6);
letter-spacing: var(--heading-tracking-h6);
text-transform: uppercase;
color: var(--color-text-secondary);
}
.section-heading__line {
flex: 1;
height: 1px;
background: var(--color-border);
}
/* =========================================================================
TABLE FOOTER / PAGINATION ROW
========================================================================= */
.table-footer {
display: flex;
align-items: center;
justify-content: space-between;
padding: var(--space-3) var(--space-5);
border-top: 1px solid var(--color-border);
background: var(--color-surface-1);
font-size: var(--text-caption);
color: var(--color-text-muted);
}
.pagination {
display: flex;
align-items: center;
gap: var(--space-1);
}
.page-btn {
width: 28px;
height: 28px;
display: flex;
align-items: center;
justify-content: center;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
background: transparent;
color: var(--color-text-secondary);
font-size: var(--text-caption);
font-family: var(--font-body);
cursor: pointer;
transition: var(--transition-fast);
}
.page-btn:hover {
border-color: var(--color-primary);
color: var(--color-primary);
}
.page-btn.is-active {
background: var(--color-primary);
border-color: var(--color-primary);
color: var(--color-text-inverse);
font-weight: var(--font-weight-bold);
}
/* =========================================================================
RESPONSIVE
========================================================================= */
@media (max-width: 1024px) {
.summary-strip {
grid-template-columns: repeat(2, 1fr);
}
.sidebar {
width: 60px;
overflow: visible;
}
.brand-name, .nav-item span, .sidebar__user-info,
.nav-section-label { display: none; }
.nav-item {
justify-content: center;
padding: var(--space-3);
border-left: none;
border-bottom: 2px solid transparent;
}
.nav-item.is-active {
border-left: none;
border-bottom-color: var(--color-primary);
}
}
@media (max-width: 768px) {
.summary-strip {
grid-template-columns: repeat(2, 1fr);
padding: var(--space-3) var(--space-4);
gap: var(--space-3);
}
.page-header { padding: var(--space-3) var(--space-4); }
.tabs-row { padding: 0 var(--space-4); }
.tab-panel { padding: var(--space-4); }
.toolbar { gap: var(--space-2); }
.search-box { max-width: 100%; }
.page-header__actions { display: none; }
}
/* =====================================================================
OFFLINE BANNER
===================================================================== */
@keyframes slideDown { from { transform: translateY(-100%); opacity: 0; } to { transform: translateY(0); opacity: 1; } }
@keyframes slideUp { from { transform: translateY(0); opacity: 1; } to { transform: translateY(-100%); opacity: 0; } }
.banner {
display: flex; align-items: center; gap: var(--space-3);
padding: var(--space-3) var(--space-4); border-radius: var(--radius-md);
font-size: var(--text-body-sm); font-weight: 500; line-height: 1.4;
}
.banner--warning {
background: var(--color-warning-light, #fef9c3); color: var(--color-warning-dark, #854d0e);
border: 1px solid var(--color-warning, #eab308);
}
.banner--success {
background: var(--color-success-light, #dcfce7); color: var(--color-success-dark, #166534);
border: 1px solid var(--color-success, #22c55e);
}
.banner--error {
background: var(--color-error-light, #fef2f2); color: var(--color-error-dark, #991b1b);
border: 1px solid var(--color-error, #ef4444);
}
.banner--dismissing { animation: slideUp 0.3s ease-in forwards; }
.banner__icon { font-size: 18px; flex-shrink: 0; }
.banner__text { flex: 1; }
.banner__text strong { font-weight: 700; }
.banner__dismiss {
background: none; border: none; cursor: pointer; font-size: 18px;
padding: var(--space-1); opacity: 0.7; color: inherit;
}
.banner__dismiss:hover { opacity: 1; }
/* =========================================================================
INVENTORY MODALS
========================================================================= */
.inv-modal-overlay {
display: none;
position: fixed;
inset: 0;
z-index: 9000;
background: rgba(0,0,0,0.6);
backdrop-filter: blur(4px);
align-items: center;
justify-content: center;
}
.inv-modal-overlay.is-open {
display: flex;
}
.inv-modal {
background: var(--color-bg-elevated);
border: 1px solid var(--color-border);
border-radius: var(--radius-lg);
width: 520px;
max-height: 85vh;
overflow-y: auto;
box-shadow: 0 20px 60px rgba(0,0,0,0.4);
}
.inv-modal--wide {
width: 700px;
}
.inv-modal__header {
display: flex;
align-items: center;
justify-content: space-between;
padding: var(--space-4) var(--space-5);
border-bottom: 1px solid var(--color-border);
}
.inv-modal__header h3 {
font-family: var(--font-heading);
font-weight: var(--heading-weight-primary);
font-size: var(--text-h5);
color: var(--color-text-primary);
margin: 0;
}
.inv-modal__close {
background: none;
border: none;
font-size: 1.5rem;
color: var(--color-text-muted);
cursor: pointer;
padding: 0 var(--space-1);
line-height: 1;
}
.inv-modal__close:hover {
color: var(--color-text-primary);
}
.inv-modal__body {
padding: var(--space-4) var(--space-5);
}
.inv-modal__footer {
display: flex;
justify-content: flex-end;
gap: var(--space-3);
padding: var(--space-3) var(--space-5);
border-top: 1px solid var(--color-border);
}
.inv-form-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: var(--space-3);
}
.inv-field {
display: flex;
flex-direction: column;
gap: var(--space-1);
}
.inv-field--full {
grid-column: 1 / -1;
}
.inv-field label {
font-size: var(--text-caption);
font-weight: var(--font-weight-semibold);
color: var(--color-text-muted);
letter-spacing: var(--tracking-wide);
text-transform: uppercase;
}
.inv-field input {
padding: var(--space-2) var(--space-3);
background: var(--color-surface-1);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
color: var(--color-text-primary);
font-family: var(--font-body);
font-size: var(--text-body-sm);
}
.inv-field input:focus {
outline: none;
border-color: var(--color-primary);
box-shadow: 0 0 0 2px var(--color-primary-muted);
}
.count-row {
display: flex;
gap: var(--space-2);
align-items: center;
margin-bottom: var(--space-2);
}
.count-row input {
padding: var(--space-2) var(--space-3);
background: var(--color-surface-1);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
color: var(--color-text-primary);
font-family: var(--font-body);
font-size: var(--text-body-sm);
}
/* History table inside modal */
.inv-modal .data-table { width: 100%; }
</style>
</head>
<body>
<!-- =========================================================================
THEME SWITCHER BAR
========================================================================= -->
<header class="theme-bar" role="banner">
<div class="theme-bar__left">
<div class="theme-bar__store">
<span class="theme-bar__dot"></span>
Nexus Autoparts
</div>
<div class="theme-bar__sep"></div>
<span class="theme-bar__label">Sucursal Centro &mdash; Usuario: H. García</span>
</div>
<div class="theme-bar__right">
<span class="theme-bar__label">Tema:</span>
<button class="theme-btn theme-btn--industrial is-active" data-theme-target="industrial" onclick="setTheme('industrial')">
<span class="theme-btn__swatch"></span>
Industrial
</button>
<button class="theme-btn theme-btn--modern" data-theme-target="modern" onclick="setTheme('modern')">
<span class="theme-btn__swatch"></span>
Moderno
</button>
</div>
</header>
<!-- =========================================================================
APP SHELL
========================================================================= -->
<div class="app-shell">
<!-- -----------------------------------------------------------------------
SIDEBAR NAVIGATION
----------------------------------------------------------------------- -->
<aside class="sidebar" role="navigation" aria-label="Navegación principal">
<!-- Brand -->
<div class="sidebar__brand">
<div class="brand-logo">NA</div>
<div class="brand-name">
<span class="brand-name__primary">Nexus</span>
<span class="brand-name__sub">Autoparts POS</span>
</div>
</div>
<!-- Nav -->
<nav class="sidebar__nav">
<div class="nav-section-label">Principal</div>
<a class="nav-item" href="/pos/sale">
<!-- Dashboard icon -->
<svg class="nav-item__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
<rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/>
<rect x="14" y="14" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/>
</svg>
<span>Dashboard</span>
</a>
<a class="nav-item" href="/pos/sale">
<svg class="nav-item__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
<rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8M12 17v4"/>
</svg>
<span>POS</span>
</a>
<a class="nav-item" href="/pos/catalog">
<svg class="nav-item__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
<path d="M4 6h16M4 10h16M4 14h16M4 18h16"/>
</svg>
<span>Catálogo</span>
</a>
<a class="nav-item is-active" href="#" aria-current="page">
<svg class="nav-item__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/>
<polyline points="3.27 6.96 12 12.01 20.73 6.96"/><line x1="12" y1="22.08" x2="12" y2="12"/>
</svg>
<span>Inventario</span>
</a>
<div class="nav-section-label">Gestión</div>
<a class="nav-item" href="#">
<svg class="nav-item__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/>
<circle cx="9" cy="7" r="4"/>
<path d="M23 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75"/>
</svg>
<span>Clientes</span>
</a>
<a class="nav-item" href="#">
<svg class="nav-item__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
<polyline points="14 2 14 8 20 8"/>
<line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/>
<polyline points="10 9 9 9 8 9"/>
</svg>
<span>Facturación</span>
</a>
<a class="nav-item" href="#">
<svg class="nav-item__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
<line x1="12" y1="1" x2="12" y2="23"/>
<path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/>
</svg>
<span>Contabilidad</span>
</a>
<a class="nav-item" href="#">
<svg class="nav-item__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
<line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/>
<line x1="6" y1="20" x2="6" y2="14"/>
</svg>
<span>Reportes</span>
</a>
<div class="nav-section-label">Sistema</div>
<a class="nav-item" href="#">
<svg class="nav-item__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="3"/>
<path d="M19.07 4.93a10 10 0 0 1 0 14.14M4.93 4.93a10 10 0 0 0 0 14.14"/>
</svg>
<span>Configuración</span>
</a>
</nav>
<!-- Footer user -->
<div class="sidebar__footer">
<div class="sidebar__user-avatar">HG</div>
<div class="sidebar__user-info">
<div class="sidebar__user-name">Hugo García</div>
<div class="sidebar__user-role">Administrador</div>
</div>
</div>
</aside>
<!-- -----------------------------------------------------------------------
MAIN CONTENT
----------------------------------------------------------------------- -->
<main class="main" role="main">
<!-- Page Header -->
<div class="page-header">
<div class="page-header__title-group">
<span class="page-header__eyebrow">Almacén &middot; Sucursal Centro</span>
<h1 class="page-header__title">Inventario</h1>
</div>
<div class="page-header__actions">
<button class="btn btn--ghost">
<svg viewBox="0 0 24 24"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
Exportar
</button>
<button class="btn btn--ghost">
<svg viewBox="0 0 24 24"><polyline points="23 4 23 10 17 10"/><path d="M20.49 15a9 9 0 1 1-.38-4.93"/></svg>
Sincronizar
</button>
<button class="btn btn--primary">
<svg viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
Nuevo Movimiento
</button>
</div>
</div>
<!-- Summary Cards -->
<div class="summary-strip">
<div class="summary-card">
<div class="summary-card__icon">
<svg viewBox="0 0 24 24"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/><polyline points="3.27 6.96 12 12.01 20.73 6.96"/><line x1="12" y1="22.08" x2="12" y2="12"/></svg>
</div>
<div class="summary-card__body">
<div class="summary-card__label">Total SKUs</div>
<div class="summary-card__value">4,817</div>
<div class="summary-card__delta summary-card__delta--up">+38 este mes</div>
</div>
</div>
<div class="summary-card">
<div class="summary-card__icon summary-card__icon--value">
<svg viewBox="0 0 24 24"><line x1="12" y1="1" x2="12" y2="23"/><path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/></svg>
</div>
<div class="summary-card__body">
<div class="summary-card__label">Valor Inventario</div>
<div class="summary-card__value">$2.4M</div>
<div class="summary-card__sub">MXN · Costo promedio</div>
</div>
</div>
<div class="summary-card">
<div class="summary-card__icon summary-card__icon--alert">
<svg viewBox="0 0 24 24"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
</div>
<div class="summary-card__body">
<div class="summary-card__label">Alertas Activas</div>
<div class="summary-card__value">23</div>
<div class="summary-card__delta summary-card__delta--down">12 críticas</div>
</div>
</div>
<div class="summary-card">
<div class="summary-card__icon summary-card__icon--time">
<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>
</div>
<div class="summary-card__body">
<div class="summary-card__label">Última Actualización</div>
<div class="summary-card__value" style="font-size:1.1rem;">Hoy 09:47</div>
<div class="summary-card__sub">Sincronizado con central</div>
</div>
</div>
</div>
<!-- Tabs Row -->
<div class="tabs-row" role="tablist" aria-label="Módulos de Inventario">
<button class="tab-btn is-active" role="tab" aria-selected="true" aria-controls="panel-stock" onclick="switchTab('stock')">
Stock Actual <span class="tab-btn__badge">4,817</span>
</button>
<button class="tab-btn" role="tab" aria-selected="false" aria-controls="panel-entradas" onclick="switchTab('entradas')">
Entradas <span class="tab-btn__badge">14</span>
</button>
<button class="tab-btn" role="tab" aria-selected="false" aria-controls="panel-salidas" onclick="switchTab('salidas')">
Salidas
</button>
<button class="tab-btn" role="tab" aria-selected="false" aria-controls="panel-traspasos" onclick="switchTab('traspasos')">
Traspasos <span class="tab-btn__badge">3</span>
</button>
<button class="tab-btn" role="tab" aria-selected="false" aria-controls="panel-ajustes" onclick="switchTab('ajustes')">
Ajustes
</button>
<button class="tab-btn" role="tab" aria-selected="false" aria-controls="panel-conteos" onclick="switchTab('conteos')">
Conteos
</button>
<button class="tab-btn" role="tab" aria-selected="false" aria-controls="panel-alertas" onclick="switchTab('alertas')">
Alertas <span class="tab-btn__badge tab-btn__badge--alert">23</span>
</button>
</div>
<!-- Tab Panels -->
<div class="tab-panels" id="tab-panels">
<!-- ===================================================================
TAB 1 — STOCK ACTUAL
=================================================================== -->
<div class="tab-panel is-active" id="panel-stock" role="tabpanel">
<div class="toolbar">
<div class="search-box">
<svg viewBox="0 0 24 24" stroke-linecap="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input type="text" id="productSearch" placeholder="Buscar por SKU, nombre, marca…" />
</div>
<select class="select-filter">
<option value="">Todas las marcas</option>
<option>Gates</option><option>SKF</option><option>Bosch</option>
<option>Monroe</option><option>NGK</option>
</select>
<select class="select-filter">
<option value="">Todas las categorías</option>
<option>Motor</option><option>Frenos</option><option>Suspensión</option>
<option>Eléctrico</option><option>Filtros</option>
</select>
<select class="select-filter">
<option value="">Estado stock</option>
<option>OK</option><option>Bajo</option><option>Sobrestock</option>
</select>
<div class="toolbar__spacer"></div>
<button class="btn btn--ghost btn--sm">
<svg viewBox="0 0 24 24"><polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"/></svg>
Filtros
</button>
<button class="btn btn--ghost btn--sm">
<svg viewBox="0 0 24 24"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
Columnas
</button>
<button class="btn btn--primary btn--sm" onclick="showCreateModal()">
<svg viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
Nuevo Producto
</button>
</div>
<div class="table-wrapper">
<table class="data-table" id="stockTable">
<thead>
<tr>
<th>Barcode</th>
<th>No. Parte</th>
<th>Nombre</th>
<th>Marca</th>
<th style="text-align:right">Stock</th>
<th style="text-align:right">Costo</th>
<th style="text-align:right">Precio 1</th>
<th style="text-align:right">Precio 2</th>
<th style="text-align:right">Precio 3</th>
<th>Ubicación</th>
<th>Acciones</th>
</tr>
</thead>
<tbody id="productTableBody">
</tbody>
</table>
<div class="table-footer">
<div id="productPagination"></div>
</div>
</div>
</div>
<!-- ===================================================================
TAB 2 — ENTRADAS
=================================================================== -->
<div class="tab-panel" id="panel-entradas" role="tabpanel">
<div class="toolbar">
<div class="search-box">
<svg viewBox="0 0 24 24" stroke-linecap="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input type="text" placeholder="Buscar por proveedor, folio…" />
</div>
<select class="select-filter">
<option value="">Todos los estados</option>
<option>Recibido</option><option>Pendiente</option><option>Parcial</option>
</select>
<input type="date" class="select-filter" value="2026-04-01" />
<div class="toolbar__spacer"></div>
<button class="btn btn--primary" onclick="showPurchaseModal()">
<svg viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
Nueva Entrada
</button>
</div>
<div class="table-wrapper">
<table class="data-table">
<thead>
<tr>
<th>Folio</th>
<th>Fecha</th>
<th>Proveedor</th>
<th style="text-align:right"># Productos</th>
<th style="text-align:right">Total</th>
<th>Estado</th>
<th>Recibió</th>
<th>Acciones</th>
</tr>
</thead>
<tbody>
<tr>
<td class="td--mono">ENT-2026-0312</td>
<td>01/04/2026</td>
<td class="td--primary">Distribuidora AutoMax S.A.</td>
<td style="text-align:right">48</td>
<td style="text-align:right" class="td--amount">$38,420.00</td>
<td><span class="badge badge--complete">Recibido</span></td>
<td>H. García</td>
<td><button class="btn btn--ghost btn--sm">Ver</button></td>
</tr>
<tr>
<td class="td--mono">ENT-2026-0311</td>
<td>31/03/2026</td>
<td class="td--primary">Refacciones Nacionales RENA</td>
<td style="text-align:right">22</td>
<td style="text-align:right" class="td--amount">$14,880.00</td>
<td><span class="badge badge--pending">Pendiente</span></td>
<td></td>
<td><button class="btn btn--primary btn--sm">Recibir</button></td>
</tr>
<tr>
<td class="td--mono">ENT-2026-0310</td>
<td>30/03/2026</td>
<td class="td--primary">Gates México Distribución</td>
<td style="text-align:right">75</td>
<td style="text-align:right" class="td--amount">$92,150.00</td>
<td><span class="badge badge--complete">Recibido</span></td>
<td>M. Torres</td>
<td><button class="btn btn--ghost btn--sm">Ver</button></td>
</tr>
<tr>
<td class="td--mono">ENT-2026-0309</td>
<td>29/03/2026</td>
<td class="td--primary">SKF de México S. de R.L.</td>
<td style="text-align:right">31</td>
<td style="text-align:right" class="td--amount">$27,600.00</td>
<td><span class="badge badge--partial">Parcial</span></td>
<td>H. García</td>
<td><button class="btn btn--secondary btn--sm">Completar</button></td>
</tr>
<tr>
<td class="td--mono">ENT-2026-0308</td>
<td>28/03/2026</td>
<td class="td--primary">Bosch Automotive Parts</td>
<td style="text-align:right">120</td>
<td style="text-align:right" class="td--amount">$145,900.00</td>
<td><span class="badge badge--complete">Recibido</span></td>
<td>L. Ramírez</td>
<td><button class="btn btn--ghost btn--sm">Ver</button></td>
</tr>
</tbody>
</table>
<div class="table-footer">
<span>Mostrando 15 de 14 entradas este mes</span>
<div class="pagination">
<button class="page-btn is-active">1</button>
<button class="page-btn">2</button>
<button class="page-btn">3</button>
</div>
</div>
</div>
</div>
<!-- ===================================================================
TAB 3 — SALIDAS
=================================================================== -->
<div class="tab-panel" id="panel-salidas" role="tabpanel">
<div class="toolbar">
<div class="search-box">
<svg viewBox="0 0 24 24" stroke-linecap="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input type="text" placeholder="Buscar salidas…" />
</div>
<select class="select-filter">
<option value="">Todos los tipos</option>
<option>Venta</option><option>Garantía</option><option>Devolución</option><option>Traspaso</option>
</select>
<select class="select-filter">
<option value="">Todos los estados</option>
<option>Completado</option><option>En proceso</option><option>Cancelado</option>
</select>
<div class="toolbar__spacer"></div>
</div>
<div class="table-wrapper">
<table class="data-table">
<thead>
<tr>
<th>Folio</th>
<th>Fecha</th>
<th>Tipo</th>
<th style="text-align:right"># Productos</th>
<th>Destino / Referencia</th>
<th>Estado</th>
<th>Autorizó</th>
</tr>
</thead>
<tbody>
<tr>
<td class="td--mono">SAL-2026-1044</td>
<td>01/04/2026</td>
<td><span class="badge badge--ok" style="text-transform:none;font-size:var(--text-caption)">Venta</span></td>
<td style="text-align:right">5</td>
<td class="td--primary">Ticket #T-9821 — Cliente: Taller Ramos</td>
<td><span class="badge badge--complete">Completado</span></td>
<td>H. García</td>
</tr>
<tr>
<td class="td--mono">SAL-2026-1043</td>
<td>01/04/2026</td>
<td><span class="badge badge--pending" style="text-transform:none;font-size:var(--text-caption)">Garantía</span></td>
<td style="text-align:right">2</td>
<td class="td--primary">Nota crédito NCR-112 — Autoservicio</td>
<td><span class="badge badge--complete">Completado</span></td>
<td>M. Torres</td>
</tr>
<tr>
<td class="td--mono">SAL-2026-1042</td>
<td>31/03/2026</td>
<td><span class="badge badge--ok" style="text-transform:none;font-size:var(--text-caption)">Venta</span></td>
<td style="text-align:right">18</td>
<td class="td--primary">Ticket #T-9820 — Cliente: FleetAuto</td>
<td><span class="badge badge--complete">Completado</span></td>
<td>L. Ramírez</td>
</tr>
<tr>
<td class="td--mono">SAL-2026-1041</td>
<td>31/03/2026</td>
<td><span class="badge badge--transit" style="text-transform:none;font-size:var(--text-caption)">Traspaso</span></td>
<td style="text-align:right">12</td>
<td class="td--primary">Traspaso TRP-2026-044 → Sucursal Norte</td>
<td><span class="badge badge--transit">En tránsito</span></td>
<td>H. García</td>
</tr>
<tr>
<td class="td--mono">SAL-2026-1040</td>
<td>30/03/2026</td>
<td><span class="badge badge--ok" style="text-transform:none;font-size:var(--text-caption)">Venta</span></td>
<td style="text-align:right">7</td>
<td class="td--primary">Ticket #T-9818 — Mostrador</td>
<td><span class="badge badge--complete">Completado</span></td>
<td>M. Torres</td>
</tr>
<tr>
<td class="td--mono">SAL-2026-1039</td>
<td>30/03/2026</td>
<td><span class="badge badge--damage" style="text-transform:none;font-size:var(--text-caption)">Devolución</span></td>
<td style="text-align:right">3</td>
<td class="td--primary">Dev. proveedor ENT-2026-0305</td>
<td><span class="badge badge--cancelled">Cancelado</span></td>
<td>H. García</td>
</tr>
</tbody>
</table>
<div class="table-footer">
<span>Mostrando 16 de 312 salidas este mes</span>
<div class="pagination">
<button class="page-btn">&lsaquo;</button>
<button class="page-btn is-active">1</button>
<button class="page-btn">2</button>
<button class="page-btn">3</button>
<button class="page-btn">&rsaquo;</button>
</div>
</div>
</div>
</div>
<!-- ===================================================================
TAB 4 — TRASPASOS
=================================================================== -->
<div class="tab-panel" id="panel-traspasos" role="tabpanel">
<div class="toolbar">
<div class="search-box">
<svg viewBox="0 0 24 24" stroke-linecap="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input type="text" placeholder="Buscar traspasos…" />
</div>
<select class="select-filter">
<option value="">Todas las sucursales</option>
<option>Sucursal Norte</option><option>Sucursal Sur</option><option>Sucursal Oriente</option>
</select>
<select class="select-filter">
<option value="">Todos los estados</option>
<option>En tránsito</option><option>Recibido</option><option>Pendiente</option>
</select>
<div class="toolbar__spacer"></div>
<button class="btn btn--primary" onclick="showTransferModal()">
<svg viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
Nuevo Traspaso
</button>
</div>
<div class="table-wrapper">
<table class="data-table">
<thead>
<tr>
<th>Folio</th>
<th>Fecha</th>
<th>Origen</th>
<th>Destino</th>
<th style="text-align:right"># Productos</th>
<th>Estado</th>
<th>Solicitó</th>
<th>Acciones</th>
</tr>
</thead>
<tbody>
<tr>
<td class="td--mono">TRP-2026-044</td>
<td>31/03/2026</td>
<td class="td--primary">Sucursal Centro</td>
<td>Sucursal Norte</td>
<td style="text-align:right">12</td>
<td><span class="badge badge--transit">En tránsito</span></td>
<td>H. García</td>
<td><button class="btn btn--primary btn--sm">Confirmar</button></td>
</tr>
<tr>
<td class="td--mono">TRP-2026-043</td>
<td>29/03/2026</td>
<td class="td--primary">Sucursal Sur</td>
<td>Sucursal Centro</td>
<td style="text-align:right">25</td>
<td><span class="badge badge--complete">Recibido</span></td>
<td>L. Ramírez</td>
<td><button class="btn btn--ghost btn--sm">Ver</button></td>
</tr>
<tr>
<td class="td--mono">TRP-2026-042</td>
<td>28/03/2026</td>
<td class="td--primary">Sucursal Centro</td>
<td>Sucursal Oriente</td>
<td style="text-align:right">8</td>
<td><span class="badge badge--pending">Pendiente</span></td>
<td>M. Torres</td>
<td><button class="btn btn--secondary btn--sm">Preparar</button></td>
</tr>
<tr>
<td class="td--mono">TRP-2026-041</td>
<td>27/03/2026</td>
<td class="td--primary">Sucursal Norte</td>
<td>Sucursal Centro</td>
<td style="text-align:right">40</td>
<td><span class="badge badge--complete">Recibido</span></td>
<td>H. García</td>
<td><button class="btn btn--ghost btn--sm">Ver</button></td>
</tr>
</tbody>
</table>
<div class="table-footer">
<span>4 traspasos activos</span>
<div class="pagination">
<button class="page-btn is-active">1</button>
</div>
</div>
</div>
</div>
<!-- ===================================================================
TAB 5 — AJUSTES
=================================================================== -->
<div class="tab-panel" id="panel-ajustes" role="tabpanel">
<div class="toolbar">
<div class="search-box">
<svg viewBox="0 0 24 24" stroke-linecap="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input type="text" placeholder="Buscar ajustes…" />
</div>
<select class="select-filter">
<option value="">Todos los tipos</option>
<option>Merma</option><option>Daño</option><option>Corrección</option>
</select>
<div class="toolbar__spacer"></div>
<button class="btn btn--primary" onclick="showAdjustmentModal()">
<svg viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
Nuevo Ajuste
</button>
</div>
<div class="table-wrapper">
<table class="data-table">
<thead>
<tr>
<th>Folio</th>
<th>Fecha</th>
<th>Tipo</th>
<th>Producto</th>
<th style="text-align:right">Cantidad</th>
<th>Motivo</th>
<th>Autorizó</th>
</tr>
</thead>
<tbody>
<tr>
<td class="td--mono">AJU-2026-088</td>
<td>01/04/2026</td>
<td><span class="badge badge--damage">Daño</span></td>
<td class="td--primary">Filtro de Aceite F026407006</td>
<td style="text-align:right;color:var(--color-error)">3</td>
<td>Daño en almacenamiento, caja aplastada</td>
<td>H. García</td>
</tr>
<tr>
<td class="td--mono">AJU-2026-087</td>
<td>31/03/2026</td>
<td><span class="badge badge--shrinkage">Merma</span></td>
<td class="td--primary">Aceite Motor 5W-30 1L</td>
<td style="text-align:right;color:var(--color-error)">6</td>
<td>Derrame detectado durante conteo físico</td>
<td>M. Torres</td>
</tr>
<tr>
<td class="td--mono">AJU-2026-086</td>
<td>30/03/2026</td>
<td><span class="badge badge--correction">Corrección</span></td>
<td class="td--primary">Rodamiento SKF 6204</td>
<td style="text-align:right;color:var(--color-success)">+4</td>
<td>Error de captura en recepción ENT-0302</td>
<td>Gerente General</td>
</tr>
<tr>
<td class="td--mono">AJU-2026-085</td>
<td>29/03/2026</td>
<td><span class="badge badge--damage">Daño</span></td>
<td class="td--primary">Amortiguador Monroe G8114</td>
<td style="text-align:right;color:var(--color-error)">2</td>
<td>Daño por caída en bodega</td>
<td>H. García</td>
</tr>
<tr>
<td class="td--mono">AJU-2026-084</td>
<td>28/03/2026</td>
<td><span class="badge badge--correction">Corrección</span></td>
<td class="td--primary">Bujía NGK LFR6A (caja 4)</td>
<td style="text-align:right;color:var(--color-success)">+16</td>
<td>Unidades halladas en lote sin registrar</td>
<td>Gerente General</td>
</tr>
</tbody>
</table>
<div class="table-footer">
<span>5 ajustes este mes</span>
<div class="pagination">
<button class="page-btn is-active">1</button>
</div>
</div>
</div>
</div>
<!-- ===================================================================
TAB 6 — CONTEOS
=================================================================== -->
<div class="tab-panel" id="panel-conteos" role="tabpanel">
<div class="toolbar">
<div class="search-box">
<svg viewBox="0 0 24 24" stroke-linecap="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input type="text" placeholder="Buscar conteos…" />
</div>
<select class="select-filter">
<option value="">Todas las zonas</option>
<option>Zona A</option><option>Zona B</option><option>Zona C</option><option>Zona D</option><option>Zona E</option>
</select>
<select class="select-filter">
<option value="">Todos los estados</option>
<option>Completado</option><option>En proceso</option><option>Programado</option>
</select>
<div class="toolbar__spacer"></div>
<button class="btn btn--primary" onclick="showCountModal()">
<svg viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
Programar Conteo
</button>
</div>
<div class="table-wrapper">
<table class="data-table">
<thead>
<tr>
<th>Folio</th>
<th>Fecha</th>
<th>Zona</th>
<th style="text-align:right">Contados</th>
<th style="text-align:right">Diferencias</th>
<th>Estado</th>
<th>Realizó</th>
<th>Acciones</th>
</tr>
</thead>
<tbody>
<tr>
<td class="td--mono">CNT-2026-018</td>
<td>01/04/2026</td>
<td class="td--primary">Zona C — Eléctrico</td>
<td style="text-align:right">312</td>
<td style="text-align:right;color:var(--color-error)">7</td>
<td><span class="badge badge--partial">En proceso</span></td>
<td>H. García</td>
<td><button class="btn btn--primary btn--sm">Continuar</button></td>
</tr>
<tr>
<td class="td--mono">CNT-2026-017</td>
<td>28/03/2026</td>
<td class="td--primary">Zona A — Motor</td>
<td style="text-align:right">856</td>
<td style="text-align:right;color:var(--color-success)">0</td>
<td><span class="badge badge--complete">Completado</span></td>
<td>L. Ramírez</td>
<td><button class="btn btn--ghost btn--sm">Ver</button></td>
</tr>
<tr>
<td class="td--mono">CNT-2026-016</td>
<td>25/03/2026</td>
<td class="td--primary">Zona B — Suspensión</td>
<td style="text-align:right">544</td>
<td style="text-align:right;color:var(--color-error)">12</td>
<td><span class="badge badge--complete">Completado</span></td>
<td>M. Torres</td>
<td><button class="btn btn--ghost btn--sm">Ver</button></td>
</tr>
<tr>
<td class="td--mono">CNT-2026-015</td>
<td>10/04/2026</td>
<td class="td--primary">Zona D — Filtros</td>
<td style="text-align:right"></td>
<td style="text-align:right"></td>
<td><span class="badge badge--pending">Programado</span></td>
<td>H. García</td>
<td><button class="btn btn--secondary btn--sm">Iniciar</button></td>
</tr>
<tr>
<td class="td--mono">CNT-2026-014</td>
<td>20/03/2026</td>
<td class="td--primary">Zona E — Frenos</td>
<td style="text-align:right">628</td>
<td style="text-align:right;color:var(--color-warning)">+3</td>
<td><span class="badge badge--complete">Completado</span></td>
<td>L. Ramírez</td>
<td><button class="btn btn--ghost btn--sm">Ver</button></td>
</tr>
</tbody>
</table>
<div class="table-footer">
<span>Mostrando 15 de 18 conteos en 2026</span>
<div class="pagination">
<button class="page-btn is-active">1</button>
<button class="page-btn">2</button>
<button class="page-btn">3</button>
<button class="page-btn">4</button>
</div>
</div>
</div>
</div>
<!-- ===================================================================
TAB 7 — ALERTAS
=================================================================== -->
<div class="tab-panel" id="panel-alertas" role="tabpanel">
<div id="alertsContent">
<!-- Low Stock -->
<div class="section-heading">
<span class="section-heading__title">Stock Bajo</span>
<div class="section-heading__line"></div>
<span class="badge badge--low">12 críticas</span>
</div>
<div class="alerts-grid" style="margin-bottom: var(--space-7)">
<div class="alert-card alert-card--critical">
<div class="alert-card__icon">
<svg viewBox="0 0 24 24"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
</div>
<div class="alert-card__body">
<div class="alert-card__title">Bujía Bosch BKR6EIX — Stock Crítico</div>
<div class="alert-card__desc">SKU BOC-0258 · Zona C-08-2 · Mínimo requerido: 10 unidades</div>
<div class="alert-card__meta">
<span class="alert-card__count">3</span>
<span class="alert-card__count-label">unidades restantes</span>
<button class="btn btn--primary btn--sm">Generar OC</button>
</div>
</div>
</div>
<div class="alert-card alert-card--critical">
<div class="alert-card__icon">
<svg viewBox="0 0 24 24"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
</div>
<div class="alert-card__body">
<div class="alert-card__title">Rodamiento SKF 6204 — Stock Bajo</div>
<div class="alert-card__desc">SKU SKF-6204 · Zona B-05-1 · Mínimo requerido: 15 unidades</div>
<div class="alert-card__meta">
<span class="alert-card__count">8</span>
<span class="alert-card__count-label">unidades restantes</span>
<button class="btn btn--primary btn--sm">Generar OC</button>
</div>
</div>
</div>
<div class="alert-card alert-card--critical">
<div class="alert-card__icon">
<svg viewBox="0 0 24 24"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
</div>
<div class="alert-card__body">
<div class="alert-card__title">Filtro de Aceite Bosch F026 — Crítico</div>
<div class="alert-card__desc">SKU BOC-F026 · Zona D-01-2 · Mínimo requerido: 20 unidades</div>
<div class="alert-card__meta">
<span class="alert-card__count">5</span>
<span class="alert-card__count-label">unidades restantes</span>
<button class="btn btn--primary btn--sm">Generar OC</button>
</div>
</div>
</div>
</div>
<!-- Overstock -->
<div class="section-heading">
<span class="section-heading__title">Sobrestock</span>
<div class="section-heading__line"></div>
<span class="badge badge--over">4 productos</span>
</div>
<div class="alerts-grid" style="margin-bottom: var(--space-7)">
<div class="alert-card alert-card--warning">
<div class="alert-card__icon">
<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
</div>
<div class="alert-card__body">
<div class="alert-card__title">Amortiguador Monroe G8114 — Sobrestock</div>
<div class="alert-card__desc">SKU MON-G8114 · Zona B-14-5 · Máximo permitido: 40 unidades</div>
<div class="alert-card__meta">
<span class="alert-card__count">67</span>
<span class="alert-card__count-label">unidades (+27 sobre máx)</span>
<button class="btn btn--ghost btn--sm">Ver opciones</button>
</div>
</div>
</div>
<div class="alert-card alert-card--warning">
<div class="alert-card__icon">
<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
</div>
<div class="alert-card__body">
<div class="alert-card__title">Aceite 10W-40 5L — Sobrestock</div>
<div class="alert-card__desc">SKU ACE-10W5L · Zona D-09-1 · Máximo: 80 unidades</div>
<div class="alert-card__meta">
<span class="alert-card__count">134</span>
<span class="alert-card__count-label">unidades (+54 sobre máx)</span>
<button class="btn btn--ghost btn--sm">Ver opciones</button>
</div>
</div>
</div>
</div>
<!-- Vencimientos -->
<div class="section-heading">
<span class="section-heading__title">Próximos a Vencer</span>
<div class="section-heading__line"></div>
<span class="badge badge--over">3 lotes</span>
</div>
<div class="alerts-grid" style="margin-bottom: var(--space-7)">
<div class="alert-card alert-card--warning">
<div class="alert-card__icon">
<svg viewBox="0 0 24 24"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>
</div>
<div class="alert-card__body">
<div class="alert-card__title">Líquido de Frenos DOT 4 — Lote AB-2022</div>
<div class="alert-card__desc">SKU FRE-DOT4 · Vence el 15/06/2026 · 24 unidades afectadas</div>
<div class="alert-card__meta">
<span class="alert-card__count">75</span>
<span class="alert-card__count-label">días restantes</span>
<button class="btn btn--ghost btn--sm">Marcar prioritario</button>
</div>
</div>
</div>
</div>
<!-- Órdenes Pendientes -->
<div class="section-heading">
<span class="section-heading__title">Órdenes de Compra Pendientes</span>
<div class="section-heading__line"></div>
<span class="badge badge--pending">4 órdenes</span>
</div>
<div class="alerts-grid">
<div class="alert-card alert-card--accent">
<div class="alert-card__icon">
<svg viewBox="0 0 24 24"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/></svg>
</div>
<div class="alert-card__body">
<div class="alert-card__title">OC-2026-0084 — Gates México</div>
<div class="alert-card__desc">72 productos · Emitida 28/03/2026 · Entrega estimada 05/04/2026</div>
<div class="alert-card__meta">
<span class="alert-card__count">$88,400</span>
<span class="alert-card__count-label">MXN pendiente</span>
<button class="btn btn--ghost btn--sm">Seguimiento</button>
</div>
</div>
</div>
<div class="alert-card alert-card--accent">
<div class="alert-card__icon">
<svg viewBox="0 0 24 24"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/></svg>
</div>
<div class="alert-card__body">
<div class="alert-card__title">OC-2026-0083 — Bosch Automotive</div>
<div class="alert-card__desc">120 productos · Emitida 27/03/2026 · Entrega estimada 07/04/2026</div>
<div class="alert-card__meta">
<span class="alert-card__count">$142,000</span>
<span class="alert-card__count-label">MXN pendiente</span>
<button class="btn btn--ghost btn--sm">Seguimiento</button>
</div>
</div>
</div>
<div class="alert-card alert-card--info">
<div class="alert-card__icon">
<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
</div>
<div class="alert-card__body">
<div class="alert-card__title">OC-2026-0082 — SKF de México</div>
<div class="alert-card__desc">31 productos · Entrega parcial recibida · Pendiente: 8 artículos</div>
<div class="alert-card__meta">
<span class="alert-card__count">8</span>
<span class="alert-card__count-label">artículos faltantes</span>
<button class="btn btn--ghost btn--sm">Reclamar</button>
</div>
</div>
</div>
</div>
</div><!-- /alertsContent -->
</div>
</div><!-- /tab-panels -->
</main>
</div><!-- /app-shell -->
<!-- =========================================================================
SCRIPTS
========================================================================= -->
<script>
/* ------------------------------------------------------------------
Theme switcher
------------------------------------------------------------------ */
function setTheme(theme) {
document.documentElement.setAttribute('data-theme', theme);
document.querySelectorAll('.theme-btn').forEach(function(btn) {
btn.classList.toggle('is-active', btn.dataset.themeTarget === theme);
});
// Persist preference
try { localStorage.setItem('nexus-theme', theme); } catch(e) {}
}
// Restore on load
(function() {
var saved;
try { saved = localStorage.getItem('nexus-theme'); } catch(e) {}
if (saved === 'industrial' || saved === 'modern') {
setTheme(saved);
}
})();
/* ------------------------------------------------------------------
Tab switcher
------------------------------------------------------------------ */
var TAB_MAP = {
stock: { btn: 0, panel: 'panel-stock' },
entradas: { btn: 1, panel: 'panel-entradas' },
salidas: { btn: 2, panel: 'panel-salidas' },
traspasos: { btn: 3, panel: 'panel-traspasos' },
ajustes: { btn: 4, panel: 'panel-ajustes' },
conteos: { btn: 5, panel: 'panel-conteos' },
alertas: { btn: 6, panel: 'panel-alertas' },
};
var tabBtns = document.querySelectorAll('.tab-btn');
var tabPanels = document.querySelectorAll('.tab-panel');
function switchTab(name) {
var target = TAB_MAP[name];
if (!target) return;
// Deactivate all
tabBtns.forEach(function(b) { b.classList.remove('is-active'); b.setAttribute('aria-selected', 'false'); });
tabPanels.forEach(function(p) { p.classList.remove('is-active'); });
// Activate target
tabBtns[target.btn].classList.add('is-active');
tabBtns[target.btn].setAttribute('aria-selected', 'true');
document.getElementById(target.panel).classList.add('is-active');
// Scroll panels container back to top
document.getElementById('tab-panels').scrollTop = 0;
}
/* ------------------------------------------------------------------
Live clock (status bar)
------------------------------------------------------------------ */
(function updateClock() {
var now = new Date();
var hh = String(now.getHours()).padStart(2, '0');
var mm = String(now.getMinutes()).padStart(2, '0');
var el = document.getElementById('live-clock');
if (el) el.textContent = hh + ':' + mm;
setTimeout(updateClock, 30000);
})();
</script>
<!-- ===== MODALS ===== -->
<!-- Create Item Modal -->
<div class="inv-modal-overlay" id="createModal">
<div class="inv-modal">
<div class="inv-modal__header">
<h3>Nuevo Producto</h3>
<button class="inv-modal__close" onclick="closeCreateModal()">&times;</button>
</div>
<div class="inv-modal__body">
<div class="inv-form-grid">
<div class="inv-field"><label>No. Parte *</label><input type="text" id="newPartNumber" placeholder="Ej: GAT-50104" /></div>
<div class="inv-field"><label>Nombre *</label><input type="text" id="newName" placeholder="Nombre del producto" /></div>
<div class="inv-field"><label>Marca</label><input type="text" id="newBrand" placeholder="Marca" /></div>
<div class="inv-field"><label>Barcode</label><input type="text" id="newBarcode" placeholder="Auto-generado si vacío" /></div>
<div class="inv-field"><label>Costo</label><input type="number" id="newCost" step="0.01" placeholder="0.00" /></div>
<div class="inv-field"><label>Precio 1</label><input type="number" id="newPrice1" step="0.01" placeholder="0.00" /></div>
<div class="inv-field"><label>Precio 2</label><input type="number" id="newPrice2" step="0.01" placeholder="0.00" /></div>
<div class="inv-field"><label>Precio 3</label><input type="number" id="newPrice3" step="0.01" placeholder="0.00" /></div>
<div class="inv-field"><label>Stock Mínimo</label><input type="number" id="newMinStock" placeholder="0" /></div>
<div class="inv-field"><label>Stock Inicial</label><input type="number" id="newInitialStock" placeholder="0" /></div>
<div class="inv-field"><label>Ubicación</label><input type="text" id="newLocation" placeholder="Ej: A-12-3" /></div>
</div>
<div id="createResult" style="margin-top:var(--space-3);min-height:1.5em;"></div>
</div>
<div class="inv-modal__footer">
<button class="btn btn--ghost" onclick="closeCreateModal()">Cancelar</button>
<button class="btn btn--primary" onclick="createItem()">Crear Producto</button>
</div>
</div>
</div>
<!-- Purchase Modal -->
<div class="inv-modal-overlay" id="purchaseModal">
<div class="inv-modal">
<div class="inv-modal__header">
<h3>Registrar Compra / Entrada</h3>
<button class="inv-modal__close" onclick="closePurchaseModal()">&times;</button>
</div>
<div class="inv-modal__body">
<div class="inv-form-grid">
<div class="inv-field"><label>ID Producto *</label><input type="number" id="purchaseItemId" placeholder="ID inventario" /></div>
<div class="inv-field"><label>Cantidad *</label><input type="number" id="purchaseQty" placeholder="Cantidad" /></div>
<div class="inv-field"><label>Costo Unitario *</label><input type="number" id="purchaseCost" step="0.01" placeholder="0.00" /></div>
<div class="inv-field"><label>Factura Proveedor</label><input type="text" id="purchaseInvoice" placeholder="No. factura" /></div>
<div class="inv-field inv-field--full"><label>Notas</label><input type="text" id="purchaseNotes" placeholder="Notas adicionales" /></div>
</div>
<div id="purchaseResult" style="margin-top:var(--space-3);min-height:1.5em;"></div>
</div>
<div class="inv-modal__footer">
<button class="btn btn--ghost" onclick="closePurchaseModal()">Cancelar</button>
<button class="btn btn--primary" onclick="recordPurchase()">Registrar Compra</button>
</div>
</div>
</div>
<!-- Transfer Modal -->
<div class="inv-modal-overlay" id="transferModal">
<div class="inv-modal">
<div class="inv-modal__header">
<h3>Nuevo Traspaso</h3>
<button class="inv-modal__close" onclick="closeTransferModal()">&times;</button>
</div>
<div class="inv-modal__body">
<div class="inv-form-grid">
<div class="inv-field"><label>ID Producto *</label><input type="number" id="transferItemId" placeholder="ID inventario" /></div>
<div class="inv-field"><label>Cantidad *</label><input type="number" id="transferQty" placeholder="Cantidad" /></div>
<div class="inv-field"><label>Sucursal Origen *</label><input type="number" id="transferFrom" placeholder="ID sucursal origen" /></div>
<div class="inv-field"><label>Sucursal Destino *</label><input type="number" id="transferTo" placeholder="ID sucursal destino" /></div>
<div class="inv-field inv-field--full"><label>Notas</label><input type="text" id="transferNotes" placeholder="Notas adicionales" /></div>
</div>
<div id="transferResult" style="margin-top:var(--space-3);min-height:1.5em;"></div>
</div>
<div class="inv-modal__footer">
<button class="btn btn--ghost" onclick="closeTransferModal()">Cancelar</button>
<button class="btn btn--primary" onclick="recordTransfer()">Registrar Traspaso</button>
</div>
</div>
</div>
<!-- Adjustment Modal -->
<div class="inv-modal-overlay" id="adjustmentModal">
<div class="inv-modal">
<div class="inv-modal__header">
<h3>Nuevo Ajuste</h3>
<button class="inv-modal__close" onclick="closeAdjustmentModal()">&times;</button>
</div>
<div class="inv-modal__body">
<div class="inv-form-grid">
<div class="inv-field"><label>ID Producto *</label><input type="number" id="adjustItemId" placeholder="ID inventario" /></div>
<div class="inv-field"><label>Cantidad * (negativo=salida)</label><input type="number" id="adjustQty" placeholder="Ej: -3 o +5" /></div>
<div class="inv-field inv-field--full"><label>Razón / Motivo *</label><input type="text" id="adjustReason" placeholder="Motivo del ajuste (obligatorio)" /></div>
</div>
<div id="adjustResult" style="margin-top:var(--space-3);min-height:1.5em;"></div>
</div>
<div class="inv-modal__footer">
<button class="btn btn--ghost" onclick="closeAdjustmentModal()">Cancelar</button>
<button class="btn btn--primary" onclick="recordAdjustment()">Registrar Ajuste</button>
</div>
</div>
</div>
<!-- Physical Count Modal -->
<div class="inv-modal-overlay" id="countModal">
<div class="inv-modal inv-modal--wide">
<div class="inv-modal__header">
<h3>Conteo Físico</h3>
<button class="inv-modal__close" onclick="closeCountModal()">&times;</button>
</div>
<div class="inv-modal__body">
<div id="countLines"></div>
<button class="btn btn--ghost btn--sm" onclick="addCountLine()" style="margin-top:var(--space-2);">+ Agregar Línea</button>
<div id="countResults" style="margin-top:var(--space-4);"></div>
</div>
<div class="inv-modal__footer">
<button class="btn btn--ghost" onclick="closeCountModal()">Cerrar</button>
<button class="btn btn--primary" onclick="startPhysicalCount()">Iniciar Conteo</button>
</div>
</div>
</div>
<!-- History Modal -->
<div class="inv-modal-overlay" id="historyModal">
<div class="inv-modal inv-modal--wide">
<div class="inv-modal__header">
<h3>Historial de Movimientos</h3>
<button class="inv-modal__close" onclick="closeHistoryModal()">&times;</button>
</div>
<div class="inv-modal__body" id="historyContent">
</div>
<div class="inv-modal__footer">
<button class="btn btn--ghost" onclick="closeHistoryModal()">Cerrar</button>
</div>
</div>
</div>
<!-- Offline Banner -->
<div id="offlineBanner" class="banner banner--warning" style="display:none;position:fixed;top:0;left:0;right:0;z-index:9999;border-radius:0;animation:none;">
<span class="banner__icon"></span>
<span class="banner__text" id="offlineBannerText"><strong>Modo offline</strong> — Funciones limitadas. Solo consultas en cache disponibles.</span>
<button class="banner__dismiss" onclick="document.getElementById('offlineBanner').style.display='none'" aria-label="Cerrar">&times;</button>
</div>
<script src="/pos/static/js/app-init.js"></script>
<script src="/pos/static/js/inventory.js"></script>
<script src="/pos/static/js/offline-banner.js"></script>
</body>
</html>