Files
Autoparts-DB/docs/design/design-system/pages/clientes.html
Lucy 46360b6827 feat: agregar design system completo con 2 temas (Industrial + Moderno)
- Tokens CSS con variables para ambos temas (dark/light)
- 21 componentes reutilizables (buttons, cards, tables, modals, etc.)
- 10 pantallas POS (login, catálogo, POS, inventario, clientes, facturación, contabilidad, dashboard, configuración, reportes)
- Preview interactivo con selector de tema
- Generado por el equipo de Hugo (Milo-UX, Iris-UI, Zara-Frontend)
2026-04-01 01:41:04 +00:00

2301 lines
80 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>Nexus Autoparts — Clientes</title>
<link rel="stylesheet" href="../tokens/tokens.css" />
<style>
/* =====================================================================
BASE RESET & BODY
===================================================================== */
*, *::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);
font-weight: var(--font-weight-regular);
background-color: var(--color-bg-base);
color: var(--color-text-primary);
transition: background-color var(--duration-normal) var(--ease-in-out),
color var(--duration-normal) var(--ease-in-out);
display: flex;
flex-direction: column;
overflow: hidden;
}
/* Dot-grid on body for modern theme */
[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 (fixed, 36px)
===================================================================== */
.theme-bar {
display: flex;
align-items: center;
justify-content: space-between;
height: 36px;
padding: 0 var(--space-5);
background-color: var(--color-surface-3);
border-bottom: 1px solid var(--color-border);
font-size: var(--text-caption);
font-weight: var(--font-weight-semibold);
letter-spacing: var(--tracking-wider);
text-transform: uppercase;
color: var(--color-text-muted);
flex-shrink: 0;
z-index: var(--z-sticky);
}
[data-theme="industrial"] .theme-bar {
background-color: #111111;
border-bottom-color: var(--color-primary-muted);
}
.theme-bar__brand {
display: flex;
align-items: center;
gap: var(--space-3);
color: var(--color-text-accent);
font-family: var(--font-heading);
font-weight: var(--heading-weight-primary);
font-size: 0.8rem;
letter-spacing: var(--tracking-widest);
}
.theme-bar__brand-dot {
width: 7px;
height: 7px;
background-color: var(--color-success);
border-radius: var(--radius-full);
box-shadow: 0 0 6px var(--color-success);
animation: pulse-dot 2.5s ease-in-out infinite;
}
@keyframes pulse-dot {
0%, 100% { opacity: 1; }
50% { opacity: 0.4; }
}
.theme-bar__center {
display: flex;
align-items: center;
gap: var(--space-6);
color: var(--color-text-muted);
font-size: var(--text-caption);
}
.theme-bar__right {
display: flex;
align-items: center;
gap: var(--space-4);
}
.theme-bar__user {
display: flex;
align-items: center;
gap: var(--space-2);
color: var(--color-text-secondary);
}
.theme-bar__user-avatar {
width: 20px;
height: 20px;
border-radius: var(--radius-full);
background-color: var(--color-primary);
color: var(--color-text-inverse);
display: flex;
align-items: center;
justify-content: center;
font-size: 0.6rem;
font-weight: var(--font-weight-bold);
}
[data-theme="industrial"] .theme-bar__user-avatar {
color: #000;
}
/* Theme switcher pill */
.theme-switcher {
display: flex;
align-items: center;
background-color: var(--color-surface-1);
border: 1px solid var(--color-border);
border-radius: var(--radius-full);
padding: 2px;
gap: 2px;
}
.theme-btn {
display: flex;
align-items: center;
gap: var(--space-1);
padding: 3px var(--space-3);
border: none;
border-radius: var(--radius-full);
font-family: var(--font-body);
font-size: 0.68rem;
font-weight: var(--font-weight-semibold);
letter-spacing: var(--tracking-wide);
text-transform: uppercase;
cursor: pointer;
transition: var(--transition-fast);
background: transparent;
color: var(--color-text-muted);
}
.theme-btn.active {
background-color: var(--color-primary);
color: var(--color-text-inverse);
box-shadow: var(--shadow-sm);
}
[data-theme="industrial"] .theme-btn.active {
color: #000;
}
/* =====================================================================
APP SHELL — below theme bar
===================================================================== */
.app-shell {
display: flex;
flex: 1;
overflow: hidden;
}
/* =====================================================================
SIDEBAR NAVIGATION (~220px)
===================================================================== */
.sidebar {
width: 220px;
flex-shrink: 0;
display: flex;
flex-direction: column;
background-color: 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);
}
[data-theme="industrial"] .sidebar {
background-color: #161616;
border-right-color: var(--color-border);
}
.sidebar__logo {
display: flex;
align-items: center;
gap: var(--space-3);
padding: var(--space-5) var(--space-5) var(--space-4);
border-bottom: 1px solid var(--color-border);
}
.sidebar__logo-icon {
width: 32px;
height: 32px;
background-color: var(--color-primary);
border-radius: var(--radius-md);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
[data-theme="industrial"] .sidebar__logo-icon {
border-radius: 0;
clip-path: polygon(0 0, calc(100% - 6px) 0, 100% 6px, 100% 100%, 0 100%);
}
.sidebar__logo-icon svg {
color: var(--color-text-inverse);
}
[data-theme="industrial"] .sidebar__logo-icon svg {
color: #000;
}
.sidebar__logo-text {
font-family: var(--font-heading);
font-weight: var(--heading-weight-primary);
font-size: 0.95rem;
letter-spacing: var(--tracking-widest);
text-transform: uppercase;
color: var(--color-text-primary);
line-height: 1.1;
}
.sidebar__logo-sub {
font-size: var(--text-caption);
color: var(--color-text-muted);
font-weight: var(--font-weight-regular);
letter-spacing: var(--tracking-wide);
}
.sidebar__section-label {
padding: var(--space-4) var(--space-5) var(--space-2);
font-size: 0.65rem;
font-weight: var(--font-weight-semibold);
letter-spacing: var(--tracking-widest);
text-transform: uppercase;
color: var(--color-text-disabled);
}
.sidebar__nav {
list-style: none;
padding: var(--space-2) 0;
flex: 1;
}
.nav-item {
display: block;
}
.nav-link {
display: flex;
align-items: center;
gap: var(--space-3);
padding: var(--space-2) var(--space-5);
height: 38px;
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);
white-space: nowrap;
}
.nav-link:hover {
background-color: var(--color-primary-muted);
color: var(--color-text-primary);
}
.nav-link.active {
background-color: var(--color-primary-muted);
color: var(--color-primary);
border-left-color: var(--color-primary);
font-weight: var(--font-weight-semibold);
}
[data-theme="industrial"] .nav-link.active {
background-color: rgba(245, 166, 35, 0.10);
}
.nav-link__icon {
width: 16px;
height: 16px;
flex-shrink: 0;
opacity: 0.7;
}
.nav-link.active .nav-link__icon {
opacity: 1;
}
.nav-link__badge {
margin-left: auto;
background-color: var(--color-primary);
color: var(--color-text-inverse);
font-size: 0.6rem;
font-weight: var(--font-weight-bold);
padding: 1px 6px;
border-radius: var(--radius-full);
min-width: 18px;
text-align: center;
}
[data-theme="industrial"] .nav-link__badge {
color: #000;
}
.sidebar__footer {
padding: var(--space-4) var(--space-5);
border-top: 1px solid var(--color-border);
font-size: var(--text-caption);
color: var(--color-text-muted);
}
/* =====================================================================
MAIN CONTENT AREA
===================================================================== */
.main-content {
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-5) var(--space-6);
background-color: var(--color-bg-elevated);
border-bottom: 1px solid var(--color-border);
flex-shrink: 0;
}
[data-theme="industrial"] .page-header {
background-color: var(--color-surface-1);
border-bottom-color: var(--color-border);
}
[data-theme="modern"] .page-header {
background-color: rgba(255,255,255,0.92);
backdrop-filter: blur(8px);
}
.page-header__title {
font-family: var(--font-heading);
font-size: var(--text-h5);
font-weight: var(--heading-weight-primary);
letter-spacing: var(--heading-tracking-h5);
color: var(--color-text-primary);
text-transform: uppercase;
}
.page-header__subtitle {
font-size: var(--text-caption);
color: var(--color-text-muted);
margin-top: 2px;
font-weight: var(--font-weight-regular);
}
.page-header__actions {
display: flex;
align-items: center;
gap: var(--space-3);
}
/* Buttons */
.btn {
display: inline-flex;
align-items: center;
gap: var(--space-2);
padding: 0 var(--space-5);
height: 36px;
border-radius: var(--radius-md);
font-family: var(--font-body);
font-size: var(--text-body-sm);
font-weight: var(--font-weight-semibold);
cursor: pointer;
border: 1.5px solid transparent;
transition: var(--transition-fast);
text-decoration: none;
white-space: nowrap;
letter-spacing: var(--tracking-normal);
}
.btn-primary {
background-color: var(--btn-primary-bg);
color: var(--btn-primary-text);
border-color: var(--btn-primary-border);
}
.btn-primary:hover {
background-color: var(--btn-primary-bg-hover);
box-shadow: var(--shadow-md);
transform: translateY(-1px);
}
.btn-primary:active {
background-color: var(--btn-primary-bg-active);
transform: translateY(0);
}
.btn-secondary {
background-color: var(--btn-secondary-bg);
color: var(--btn-secondary-text);
border-color: var(--btn-secondary-border);
}
.btn-secondary:hover {
background-color: var(--btn-secondary-bg-hover);
}
.btn-ghost {
background-color: var(--btn-ghost-bg);
color: var(--btn-ghost-text);
border-color: var(--btn-ghost-border);
}
.btn-ghost:hover {
background-color: var(--color-primary-muted);
color: var(--color-primary);
border-color: var(--color-primary);
}
.btn-sm {
height: 30px;
padding: 0 var(--space-4);
font-size: var(--text-caption);
}
[data-theme="modern"] .btn {
border-radius: var(--radius-lg);
}
/* =====================================================================
SUMMARY CARDS
===================================================================== */
.summary-bar {
display: flex;
gap: var(--space-4);
padding: var(--space-5) var(--space-6);
background-color: transparent;
flex-shrink: 0;
overflow-x: auto;
}
.summary-card {
flex: 1;
min-width: 160px;
background-color: var(--color-bg-elevated);
border: 1px solid var(--color-border);
border-radius: var(--radius-lg);
padding: var(--space-4) var(--space-5);
display: flex;
flex-direction: column;
gap: var(--space-2);
transition: var(--transition-normal);
}
[data-theme="industrial"] .summary-card {
background-color: var(--color-surface-1);
border-radius: 0;
clip-path: polygon(0 0, calc(100% - 10px) 0, 100% 10px, 100% 100%, 0 100%);
}
.summary-card:hover {
border-color: var(--color-border-accent);
box-shadow: var(--shadow-md);
}
[data-theme="industrial"] .summary-card:hover {
box-shadow: var(--shadow-accent);
}
.summary-card__label {
font-size: var(--text-caption);
color: var(--color-text-muted);
text-transform: uppercase;
letter-spacing: var(--tracking-wider);
font-weight: var(--font-weight-semibold);
}
.summary-card__value {
font-family: var(--font-heading);
font-size: var(--text-h4);
font-weight: var(--heading-weight-primary);
color: var(--color-text-primary);
letter-spacing: var(--tracking-snug);
line-height: 1;
}
.summary-card__delta {
display: flex;
align-items: center;
gap: var(--space-1);
font-size: var(--text-caption);
color: var(--color-success);
}
.summary-card__delta.neg {
color: var(--color-error);
}
.summary-card__icon {
width: 32px;
height: 32px;
border-radius: var(--radius-md);
background-color: var(--color-primary-muted);
display: flex;
align-items: center;
justify-content: center;
color: var(--color-primary);
align-self: flex-start;
margin-bottom: var(--space-1);
}
[data-theme="industrial"] .summary-card__icon {
border-radius: 0;
}
/* =====================================================================
CONTENT SPLIT (list + detail)
===================================================================== */
.content-split {
display: flex;
flex: 1;
overflow: hidden;
gap: 0;
}
/* =====================================================================
LEFT PANEL — Customer List (60%)
===================================================================== */
.panel-list {
display: flex;
flex-direction: column;
width: 60%;
min-width: 0;
border-right: 1px solid var(--color-border);
overflow: hidden;
}
/* Search & filter row */
.list-toolbar {
display: flex;
align-items: center;
gap: var(--space-3);
padding: var(--space-4) var(--space-5);
background-color: var(--color-surface-1);
border-bottom: 1px solid var(--color-border);
flex-shrink: 0;
}
[data-theme="modern"] .list-toolbar {
background-color: rgba(248, 249, 255, 0.95);
}
.search-wrap {
position: relative;
flex: 1;
}
.search-icon {
position: absolute;
left: var(--space-3);
top: 50%;
transform: translateY(-50%);
color: var(--color-text-muted);
pointer-events: none;
}
.search-input {
width: 100%;
height: 38px;
padding: 0 var(--space-4) 0 38px;
background-color: var(--color-bg-overlay);
border: 1.5px solid var(--color-border);
border-radius: var(--radius-md);
font-family: var(--font-body);
font-size: var(--text-body-sm);
color: var(--color-text-primary);
outline: none;
transition: var(--transition-fast);
}
.search-input::placeholder {
color: var(--color-text-muted);
}
.search-input:focus {
border-color: var(--color-border-focus);
box-shadow: var(--shadow-focus);
}
[data-theme="modern"] .search-input {
border-radius: var(--radius-lg);
background-color: #fff;
}
.filter-select {
height: 38px;
padding: 0 var(--space-4);
background-color: var(--color-bg-overlay);
border: 1.5px solid var(--color-border);
border-radius: var(--radius-md);
font-family: var(--font-body);
font-size: var(--text-body-sm);
color: var(--color-text-primary);
outline: none;
cursor: pointer;
transition: var(--transition-fast);
}
.filter-select:focus {
border-color: var(--color-border-focus);
box-shadow: var(--shadow-focus);
}
[data-theme="modern"] .filter-select {
border-radius: var(--radius-lg);
background-color: #fff;
}
/* Customer Table */
.table-wrap {
flex: 1;
overflow-y: auto;
scrollbar-width: thin;
scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track);
}
.customers-table {
width: 100%;
border-collapse: collapse;
font-size: var(--text-body-sm);
}
.customers-table thead {
position: sticky;
top: 0;
z-index: 2;
}
.customers-table thead tr {
background-color: var(--color-surface-2);
border-bottom: 2px solid var(--color-border-strong);
}
[data-theme="industrial"] .customers-table thead tr {
background-color: #1d1d1d;
}
.customers-table th {
padding: var(--space-3) var(--space-4);
text-align: left;
font-size: 0.65rem;
font-weight: var(--font-weight-semibold);
letter-spacing: var(--tracking-widest);
text-transform: uppercase;
color: var(--color-text-muted);
white-space: nowrap;
}
.customers-table th:first-child { padding-left: var(--space-5); }
.customers-table th:last-child { padding-right: var(--space-5); }
.customers-table tbody tr {
border-bottom: 1px solid var(--color-border);
cursor: pointer;
transition: var(--transition-fast);
}
.customers-table tbody tr:hover {
background-color: var(--color-primary-muted);
}
.customers-table tbody tr.selected {
background-color: var(--color-primary-muted);
border-left: 3px solid var(--color-primary);
}
.customers-table td {
padding: var(--space-3) var(--space-4);
vertical-align: middle;
color: var(--color-text-primary);
white-space: nowrap;
}
.customers-table td:first-child { padding-left: var(--space-5); }
.customers-table td:last-child { padding-right: var(--space-5); }
.cell-num {
color: var(--color-text-muted);
font-size: var(--text-caption);
}
.cell-name {
font-weight: var(--font-weight-semibold);
color: var(--color-text-primary);
}
.cell-name-sub {
font-size: var(--text-caption);
color: var(--color-text-muted);
font-weight: var(--font-weight-regular);
}
.cell-rfc {
font-family: var(--font-mono);
font-size: var(--text-caption);
color: var(--color-text-secondary);
letter-spacing: 0.03em;
}
.cell-credit {
font-family: var(--font-mono);
font-size: var(--text-body-sm);
color: var(--color-success);
}
.cell-credit.low {
color: var(--color-warning);
}
.cell-credit.none {
color: var(--color-error);
}
.cell-date {
font-size: var(--text-caption);
color: var(--color-text-muted);
}
/* Status badges */
.badge {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 2px 8px;
border-radius: var(--radius-full);
font-size: 0.65rem;
font-weight: var(--font-weight-semibold);
letter-spacing: var(--tracking-wider);
text-transform: uppercase;
white-space: nowrap;
}
.badge--active {
background-color: rgba(34, 197, 94, 0.15);
color: var(--color-success);
border: 1px solid rgba(34, 197, 94, 0.3);
}
.badge--inactive {
background-color: rgba(163, 163, 163, 0.15);
color: var(--color-text-muted);
border: 1px solid var(--color-border);
}
.badge--warning {
background-color: rgba(234, 179, 8, 0.15);
color: var(--color-warning);
border: 1px solid rgba(234, 179, 8, 0.3);
}
.badge-dot {
width: 5px;
height: 5px;
border-radius: var(--radius-full);
background-color: currentColor;
}
/* Tipo chip */
.tipo-chip {
display: inline-block;
padding: 2px 7px;
border-radius: var(--radius-sm);
font-size: 0.62rem;
font-weight: var(--font-weight-semibold);
letter-spacing: var(--tracking-wide);
text-transform: uppercase;
}
.tipo-chip--taller {
background-color: rgba(245, 166, 35, 0.12);
color: var(--color-warning);
border: 1px solid rgba(245, 166, 35, 0.3);
}
[data-theme="modern"] .tipo-chip--taller {
background-color: rgba(255, 107, 53, 0.10);
color: var(--color-primary);
border-color: rgba(255, 107, 53, 0.25);
}
.tipo-chip--mostrador {
background-color: rgba(99, 102, 241, 0.12);
color: #818cf8;
border: 1px solid rgba(99, 102, 241, 0.3);
}
.tipo-chip--mayoreo {
background-color: rgba(34, 197, 94, 0.10);
color: var(--color-success);
border: 1px solid rgba(34, 197, 94, 0.3);
}
/* Table pagination footer */
.table-footer {
display: flex;
align-items: center;
justify-content: space-between;
padding: var(--space-3) var(--space-5);
background-color: var(--color-surface-1);
border-top: 1px solid var(--color-border);
flex-shrink: 0;
}
.table-footer__info {
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);
cursor: pointer;
transition: var(--transition-fast);
}
.page-btn:hover {
background-color: var(--color-primary-muted);
border-color: var(--color-primary);
color: var(--color-primary);
}
.page-btn.active {
background-color: var(--color-primary);
border-color: var(--color-primary);
color: var(--color-text-inverse);
font-weight: var(--font-weight-semibold);
}
[data-theme="industrial"] .page-btn.active {
color: #000;
}
/* =====================================================================
RIGHT PANEL — Customer Detail (40%)
===================================================================== */
.panel-detail {
width: 40%;
min-width: 0;
display: flex;
flex-direction: column;
background-color: var(--color-bg-elevated);
overflow-y: auto;
scrollbar-width: thin;
scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track);
}
[data-theme="industrial"] .panel-detail {
background-color: var(--color-surface-1);
}
[data-theme="modern"] .panel-detail {
background-color: rgba(248, 249, 255, 0.95);
}
/* Empty state */
.detail-empty {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: var(--space-4);
color: var(--color-text-disabled);
padding: var(--space-10);
text-align: center;
}
.detail-empty__icon {
width: 56px;
height: 56px;
border-radius: var(--radius-xl);
border: 2px dashed var(--color-border-strong);
display: flex;
align-items: center;
justify-content: center;
color: var(--color-text-disabled);
}
.detail-empty__text {
font-size: var(--text-body-sm);
color: var(--color-text-muted);
}
/* Detail header */
.detail-header {
padding: var(--space-5) var(--space-5) var(--space-4);
border-bottom: 1px solid var(--color-border);
flex-shrink: 0;
background-color: var(--color-surface-2);
display: flex;
align-items: flex-start;
gap: var(--space-4);
}
[data-theme="industrial"] .detail-header {
background-color: #1d1d1d;
}
[data-theme="modern"] .detail-header {
background-color: rgba(240, 242, 255, 0.8);
}
/* Customer Avatar */
.customer-avatar {
width: 56px;
height: 56px;
border-radius: var(--radius-lg);
background-color: var(--color-primary);
display: flex;
align-items: center;
justify-content: center;
font-family: var(--font-heading);
font-weight: var(--heading-weight-primary);
font-size: 1.3rem;
color: var(--color-text-inverse);
flex-shrink: 0;
letter-spacing: -0.02em;
box-shadow: var(--shadow-md);
}
[data-theme="industrial"] .customer-avatar {
border-radius: 0;
color: #000;
clip-path: polygon(0 0, calc(100% - 10px) 0, 100% 10px, 100% 100%, 0 100%);
}
.detail-header__info {
flex: 1;
min-width: 0;
}
.detail-header__name {
font-family: var(--font-heading);
font-size: var(--text-h5);
font-weight: var(--heading-weight-primary);
color: var(--color-text-primary);
letter-spacing: var(--heading-tracking-h5);
text-transform: uppercase;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.detail-header__rfc {
font-family: var(--font-mono);
font-size: var(--text-caption);
color: var(--color-text-accent);
letter-spacing: 0.06em;
margin-top: 2px;
}
.detail-header__meta {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: var(--space-2);
margin-top: var(--space-2);
}
.detail-header__actions {
display: flex;
flex-direction: column;
gap: var(--space-2);
align-items: flex-end;
flex-shrink: 0;
}
/* Detail body sections */
.detail-section {
padding: var(--space-4) var(--space-5);
border-bottom: 1px solid var(--color-border);
}
.detail-section:last-child {
border-bottom: none;
}
.detail-section__title {
font-size: 0.65rem;
font-weight: var(--font-weight-semibold);
letter-spacing: var(--tracking-widest);
text-transform: uppercase;
color: var(--color-text-muted);
margin-bottom: var(--space-3);
}
/* Info rows */
.info-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: var(--space-3);
}
.info-row {
display: flex;
flex-direction: column;
gap: 2px;
}
.info-row--full {
grid-column: 1 / -1;
}
.info-label {
font-size: var(--text-caption);
color: var(--color-text-muted);
text-transform: uppercase;
letter-spacing: var(--tracking-wider);
font-weight: var(--font-weight-semibold);
}
.info-value {
font-size: var(--text-body-sm);
color: var(--color-text-primary);
font-weight: var(--font-weight-regular);
}
.info-value--mono {
font-family: var(--font-mono);
font-size: var(--text-caption);
letter-spacing: 0.04em;
}
.info-value--accent {
color: var(--color-text-accent);
font-weight: var(--font-weight-semibold);
}
/* Credit block */
.credit-block {
display: flex;
flex-direction: column;
gap: var(--space-3);
}
.credit-metrics {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: var(--space-3);
}
.credit-metric {
background-color: var(--color-surface-2);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
padding: var(--space-3) var(--space-3);
text-align: center;
}
[data-theme="industrial"] .credit-metric {
border-radius: 0;
}
.credit-metric__label {
font-size: 0.62rem;
color: var(--color-text-muted);
text-transform: uppercase;
letter-spacing: var(--tracking-wider);
font-weight: var(--font-weight-semibold);
}
.credit-metric__value {
font-family: var(--font-mono);
font-size: var(--text-body-sm);
font-weight: var(--font-weight-bold);
color: var(--color-text-primary);
margin-top: 3px;
}
.credit-metric__value.available { color: var(--color-success); }
.credit-metric__value.used { color: var(--color-warning); }
/* Credit progress bar */
.credit-progress {
display: flex;
flex-direction: column;
gap: var(--space-1);
}
.credit-progress__labels {
display: flex;
justify-content: space-between;
font-size: var(--text-caption);
color: var(--color-text-muted);
}
.progress-bar {
height: 8px;
background-color: var(--color-surface-3);
border-radius: var(--radius-full);
overflow: hidden;
}
.progress-bar__fill {
height: 100%;
background-color: var(--color-warning);
border-radius: var(--radius-full);
transition: width var(--duration-slow) var(--ease-out);
}
.progress-bar__fill.low { background-color: var(--color-success); }
.progress-bar__fill.high { background-color: var(--color-error); }
/* Quick action buttons */
.quick-actions {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: var(--space-2);
}
.action-btn {
display: flex;
flex-direction: column;
align-items: center;
gap: var(--space-1);
padding: var(--space-3) var(--space-2);
background-color: var(--color-surface-2);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
color: var(--color-text-secondary);
cursor: pointer;
transition: var(--transition-fast);
font-family: var(--font-body);
font-size: var(--text-caption);
font-weight: var(--font-weight-semibold);
text-align: center;
}
[data-theme="industrial"] .action-btn {
border-radius: 0;
}
.action-btn:hover {
background-color: var(--color-primary-muted);
border-color: var(--color-primary);
color: var(--color-primary);
}
.action-btn--primary {
background-color: var(--btn-primary-bg);
border-color: var(--btn-primary-bg);
color: var(--btn-primary-text);
}
[data-theme="industrial"] .action-btn--primary {
color: #000;
}
.action-btn--primary:hover {
background-color: var(--btn-primary-bg-hover);
border-color: var(--btn-primary-bg-hover);
color: var(--btn-primary-text);
}
[data-theme="industrial"] .action-btn--primary:hover {
color: #000;
}
.action-btn__icon {
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
}
/* Purchase history mini table */
.history-table {
width: 100%;
border-collapse: collapse;
font-size: var(--text-caption);
}
.history-table thead tr {
background-color: var(--color-surface-2);
border-bottom: 1px solid var(--color-border-strong);
}
.history-table th {
padding: var(--space-2) var(--space-3);
text-align: left;
font-size: 0.6rem;
font-weight: var(--font-weight-semibold);
letter-spacing: var(--tracking-widest);
text-transform: uppercase;
color: var(--color-text-muted);
white-space: nowrap;
}
.history-table tbody tr {
border-bottom: 1px solid var(--color-border);
transition: var(--transition-fast);
}
.history-table tbody tr:hover {
background-color: var(--color-primary-muted);
}
.history-table td {
padding: var(--space-2) var(--space-3);
vertical-align: middle;
}
.history-table td.folio {
font-family: var(--font-mono);
font-size: 0.7rem;
color: var(--color-text-accent);
letter-spacing: 0.04em;
}
.history-table td.total {
font-family: var(--font-mono);
font-weight: var(--font-weight-semibold);
color: var(--color-text-primary);
}
.history-table td.date {
color: var(--color-text-muted);
}
/* Status mini badges */
.mbadge {
display: inline-flex;
align-items: center;
padding: 1px 6px;
border-radius: var(--radius-full);
font-size: 0.6rem;
font-weight: var(--font-weight-semibold);
text-transform: uppercase;
letter-spacing: 0.03em;
}
.mbadge--paid {
background-color: rgba(34,197,94,0.12);
color: var(--color-success);
}
.mbadge--pending {
background-color: rgba(234,179,8,0.12);
color: var(--color-warning);
}
.mbadge--overdue {
background-color: rgba(239,68,68,0.12);
color: var(--color-error);
}
/* =====================================================================
RESPONSIVE
===================================================================== */
@media (max-width: 1024px) {
.sidebar {
width: 56px;
overflow: visible;
}
.sidebar__logo-text,
.sidebar__logo-sub,
.sidebar__section-label,
.nav-link__badge {
display: none;
}
.nav-link {
justify-content: center;
padding: var(--space-2);
border-left: none;
border-bottom: 3px solid transparent;
}
.nav-link.active {
border-left: none;
border-bottom-color: var(--color-primary);
}
.sidebar__logo {
justify-content: center;
padding: var(--space-4) var(--space-2);
}
.summary-card__delta { display: none; }
}
@media (max-width: 900px) {
.content-split {
flex-direction: column;
}
.panel-list {
width: 100%;
border-right: none;
border-bottom: 1px solid var(--color-border);
max-height: 55%;
}
.panel-detail {
width: 100%;
max-height: 45%;
}
.summary-bar {
padding: var(--space-3) var(--space-4);
gap: var(--space-3);
}
}
@media (max-width: 640px) {
.page-header__actions .btn:not(.btn-primary) {
display: none;
}
.summary-card {
min-width: 140px;
}
.customers-table th.hide-mobile,
.customers-table td.hide-mobile {
display: none;
}
.info-grid {
grid-template-columns: 1fr;
}
.credit-metrics {
grid-template-columns: 1fr 1fr;
}
}
</style>
</head>
<body>
<!-- ====================================================================
THEME SWITCHER BAR
==================================================================== -->
<div class="theme-bar">
<div class="theme-bar__brand">
<span class="theme-bar__brand-dot"></span>
<span>Nexus Autoparts</span>
</div>
<div class="theme-bar__center">
<span>Sucursal Principal</span>
<span>Turno: Matutino — Hugo M.</span>
</div>
<div class="theme-bar__right">
<div class="theme-switcher">
<button class="theme-btn active" id="btn-industrial" onclick="setTheme('industrial')">
<!-- gear icon -->
<svg width="10" height="10" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2"><circle cx="8" cy="8" r="2.5"/><path d="M8 2v1M8 13v1M2 8H1m14 0h-1M3.5 3.5l.7.7M11.8 11.8l.7.7M3.5 12.5l.7-.7M11.8 4.2l.7-.7"/></svg>
Industrial
</button>
<button class="theme-btn" id="btn-modern" onclick="setTheme('modern')">
<!-- sun icon -->
<svg width="10" height="10" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2"><circle cx="8" cy="8" r="3"/><line x1="8" y1="1" x2="8" y2="3"/><line x1="8" y1="13" x2="8" y2="15"/><line x1="1" y1="8" x2="3" y2="8"/><line x1="13" y1="8" x2="15" y2="8"/></svg>
Modern
</button>
</div>
<div class="theme-bar__user">
<div class="theme-bar__user-avatar">HM</div>
<span>Hugo M.</span>
</div>
</div>
</div>
<!-- ====================================================================
APP SHELL
==================================================================== -->
<div class="app-shell">
<!-- SIDEBAR -->
<aside class="sidebar">
<div class="sidebar__logo">
<div class="sidebar__logo-icon">
<!-- car/wrench icon -->
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
<path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/>
</svg>
</div>
<div>
<div class="sidebar__logo-text">Nexus</div>
<div class="sidebar__logo-sub">Autoparts POS</div>
</div>
</div>
<div class="sidebar__section-label">Módulos</div>
<ul class="sidebar__nav">
<li class="nav-item">
<a href="#" class="nav-link">
<svg class="nav-link__icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round">
<rect x="1" y="1" width="6" height="6" rx="1"/><rect x="9" y="1" width="6" height="6" rx="1"/>
<rect x="1" y="9" width="6" height="6" rx="1"/><rect x="9" y="9" width="6" height="6" rx="1"/>
</svg>
Dashboard
</a>
</li>
<li class="nav-item">
<a href="#" class="nav-link">
<svg class="nav-link__icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round">
<rect x="1" y="3" width="14" height="11" rx="1.5"/>
<path d="M5 3V2m6 1V2"/>
<path d="M1 7h14"/>
</svg>
POS
<span class="nav-link__badge">1</span>
</a>
</li>
<li class="nav-item">
<a href="#" class="nav-link">
<svg class="nav-link__icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round">
<path d="M2 4h12M2 8h8M2 12h10"/>
</svg>
Catálogo
</a>
</li>
<li class="nav-item">
<a href="#" class="nav-link">
<svg class="nav-link__icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round">
<rect x="2" y="3" width="12" height="11" rx="1"/><path d="M5 3V1m6 2V1M6 9l2 2 4-4"/>
</svg>
Inventario
</a>
</li>
<li class="nav-item">
<a href="clientes.html" class="nav-link active">
<svg class="nav-link__icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round">
<circle cx="6" cy="5" r="3"/><path d="M1 14c0-2.76 2.24-5 5-5s5 2.24 5 5"/>
<path d="M13 6l2 2-3.5 3.5"/>
</svg>
Clientes
</a>
</li>
<li class="nav-item">
<a href="#" class="nav-link">
<svg class="nav-link__icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round">
<rect x="2" y="2" width="12" height="12" rx="1"/><path d="M5 6h6M5 9h4"/>
</svg>
Facturación
<span class="nav-link__badge">3</span>
</a>
</li>
<li class="nav-item">
<a href="#" class="nav-link">
<svg class="nav-link__icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round">
<path d="M8 1v14M1 8h14"/>
<circle cx="8" cy="8" r="7"/>
</svg>
Contabilidad
</a>
</li>
<li class="nav-item">
<a href="#" class="nav-link">
<svg class="nav-link__icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round">
<path d="M2 11V14h3l8-8-3-3L2 11z"/><path d="M12 3l1 1"/>
</svg>
Reportes
</a>
</li>
<li class="nav-item">
<a href="#" class="nav-link">
<svg class="nav-link__icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round">
<circle cx="8" cy="8" r="2.5"/>
<path d="M8 2v1M8 13v1M2 8H1m14 0h-1M3.5 3.5l.7.7M11.8 11.8l.7.7M3.5 12.5l.7-.7M11.8 4.2l.7-.7"/>
</svg>
Configuración
</a>
</li>
</ul>
<div class="sidebar__footer">
v1.0.0 — 2026
</div>
</aside>
<!-- MAIN CONTENT -->
<div class="main-content">
<!-- Page Header -->
<div class="page-header">
<div>
<div class="page-header__title">Gestión de Clientes</div>
<div class="page-header__subtitle">Directorio, crédito y historial de compras</div>
</div>
<div class="page-header__actions">
<button class="btn btn-ghost">
<svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M2 5h12M4 8h8M6 11h4"/></svg>
Filtros
</button>
<button class="btn btn-ghost">
<svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M14 10v3a1 1 0 01-1 1H3a1 1 0 01-1-1v-3M8 1v9M4 6l4 4 4-4"/></svg>
Exportar
</button>
<button class="btn btn-primary" onclick="openNewCustomerModal()">
<svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.2"><line x1="8" y1="2" x2="8" y2="14"/><line x1="2" y1="8" x2="14" y2="8"/></svg>
Nuevo Cliente
</button>
</div>
</div>
<!-- Summary Cards -->
<div class="summary-bar">
<div class="summary-card">
<div class="summary-card__icon">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round">
<circle cx="6" cy="5" r="2.5"/><path d="M1 13.5c0-2.5 2.24-4.5 5-4.5s5 2 5 4.5"/>
<path d="M11 4a2.5 2.5 0 010 5M14.5 13.5c0-2-1.5-3.5-3.5-4"/>
</svg>
</div>
<div class="summary-card__label">Total Clientes</div>
<div class="summary-card__value">1,284</div>
<div class="summary-card__delta">
<svg width="10" height="10" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="2"><path d="M6 9V3M3 6l3-3 3 3"/></svg>
+18 este mes
</div>
</div>
<div class="summary-card">
<div class="summary-card__icon">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round">
<circle cx="6" cy="5" r="2.5"/><path d="M1 13.5c0-2.5 2.24-4.5 5-4.5s5 2 5 4.5"/>
<path d="M12 8l1.5 1.5L16 7"/>
</svg>
</div>
<div class="summary-card__label">Clientes Activos</div>
<div class="summary-card__value">1,047</div>
<div class="summary-card__delta">
<svg width="10" height="10" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="2"><path d="M6 9V3M3 6l3-3 3 3"/></svg>
81.5% del total
</div>
</div>
<div class="summary-card">
<div class="summary-card__icon">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round">
<circle cx="8" cy="8" r="6.5"/>
<path d="M8 4.5v1.25M8 10.25v1.25"/>
<path d="M5.75 6.5c0-.83.67-1.5 1.5-1.5h1c.83 0 1.5.67 1.5 1.5S9.08 8 8 8s-2 .67-2 1.5.67 1.5 1.5 1.5h1.5c.83 0 1.5-.67 1.5-1.5"/>
</svg>
</div>
<div class="summary-card__label">Crédito Total Otorgado</div>
<div class="summary-card__value">$4.2M</div>
<div class="summary-card__delta">
<svg width="10" height="10" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="2"><path d="M6 9V3M3 6l3-3 3 3"/></svg>
+$320K vs mes anterior
</div>
</div>
<div class="summary-card">
<div class="summary-card__icon" style="background-color: rgba(239,68,68,0.12); color: var(--color-error);">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round">
<path d="M2 4h12l-1.5 8H3.5L2 4z"/>
<path d="M5 4V3a1 1 0 011-1h4a1 1 0 011 1v1"/>
</svg>
</div>
<div class="summary-card__label">Cuentas por Cobrar</div>
<div class="summary-card__value" style="color: var(--color-error);">$847K</div>
<div class="summary-card__delta neg">
<svg width="10" height="10" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="2"><path d="M6 3v6M3 6l3 3 3-3"/></svg>
+$65K vs mes anterior
</div>
</div>
</div>
<!-- Content Split -->
<div class="content-split">
<!-- ============================================================
LEFT PANEL — Customer List
============================================================ -->
<div class="panel-list">
<!-- Toolbar / Search -->
<div class="list-toolbar">
<div class="search-wrap">
<span class="search-icon">
<svg width="15" height="15" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
<circle cx="7" cy="7" r="4.5"/><path d="M10.5 10.5L14 14"/>
</svg>
</span>
<input type="text" class="search-input" placeholder="Buscar por nombre, RFC, teléfono…" id="searchInput" oninput="filterCustomers()" />
</div>
<select class="filter-select" onchange="filterCustomers()" id="tipoFilter">
<option value="">Todos los tipos</option>
<option value="Taller">Taller</option>
<option value="Mostrador">Mostrador</option>
<option value="Mayoreo">Mayoreo</option>
</select>
<select class="filter-select" onchange="filterCustomers()" id="estadoFilter">
<option value="">Todos los estados</option>
<option value="Activo">Activo</option>
<option value="Inactivo">Inactivo</option>
<option value="Mora">En mora</option>
</select>
</div>
<!-- Table -->
<div class="table-wrap themed-scrollbar">
<table class="customers-table" id="customersTable">
<thead>
<tr>
<th>#</th>
<th>Nombre</th>
<th class="hide-mobile">RFC</th>
<th class="hide-mobile">Teléfono</th>
<th class="hide-mobile">Email</th>
<th>Tipo</th>
<th>Crédito Disp.</th>
<th class="hide-mobile">Última Compra</th>
<th>Estado</th>
</tr>
</thead>
<tbody id="customersBody">
<!-- Rows rendered by JS -->
</tbody>
</table>
</div>
<!-- Pagination -->
<div class="table-footer">
<div class="table-footer__info" id="tableInfo">Mostrando 115 de 1,284 clientes</div>
<div class="pagination">
<button class="page-btn">&#8249;</button>
<button class="page-btn active">1</button>
<button class="page-btn">2</button>
<button class="page-btn">3</button>
<span style="color:var(--color-text-muted);font-size:var(--text-caption);padding:0 4px;"></span>
<button class="page-btn">86</button>
<button class="page-btn">&#8250;</button>
</div>
</div>
</div>
<!-- ============================================================
RIGHT PANEL — Customer Detail
============================================================ -->
<div class="panel-detail themed-scrollbar" id="detailPanel">
<!-- Empty state (shown when no customer selected) -->
<div class="detail-empty" id="detailEmpty">
<div class="detail-empty__icon">
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
<circle cx="9" cy="7" r="4"/><path d="M3 21v-2a4 4 0 014-4h4a4 4 0 014 4v2"/>
<line x1="19" y1="8" x2="19" y2="14"/><line x1="22" y1="11" x2="16" y2="11"/>
</svg>
</div>
<div class="detail-empty__text">Selecciona un cliente<br>para ver su detalle</div>
</div>
<!-- Detail content (hidden until a row is selected) -->
<div id="detailContent" style="display:none; flex-direction:column; flex:1;">
<!-- Header -->
<div class="detail-header">
<div class="customer-avatar" id="detailAvatar">MA</div>
<div class="detail-header__info">
<div class="detail-header__name" id="detailName">MIGUEL ÁNGEL TORRES</div>
<div class="detail-header__rfc" id="detailRFC">TOAM820115HDF</div>
<div class="detail-header__meta">
<span class="tipo-chip tipo-chip--taller" id="detailTipo">Taller</span>
<span class="badge badge--active" id="detailStatus"><span class="badge-dot"></span>Activo</span>
</div>
</div>
<div class="detail-header__actions">
<button class="btn btn-sm btn-ghost" onclick="closeDetail()">
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="2"><path d="M1 1l10 10M11 1L1 11"/></svg>
</button>
</div>
</div>
<!-- Contact Info -->
<div class="detail-section">
<div class="detail-section__title">Información de Contacto</div>
<div class="info-grid">
<div class="info-row info-row--full">
<span class="info-label">Dirección</span>
<span class="info-value" id="detailAddress">Av. Insurgentes Sur 1602, Col. Crédito Constructor, CDMX</span>
</div>
<div class="info-row">
<span class="info-label">Teléfono</span>
<span class="info-value info-value--mono" id="detailPhone">+52 55 1234-5678</span>
</div>
<div class="info-row">
<span class="info-label">Email</span>
<span class="info-value" id="detailEmail" style="font-size:var(--text-caption);">m.torres@tallerstar.mx</span>
</div>
<div class="info-row">
<span class="info-label">Cliente desde</span>
<span class="info-value info-value--mono" id="detailSince">14 Mar 2019</span>
</div>
<div class="info-row">
<span class="info-label">Últ. Compra</span>
<span class="info-value info-value--mono" id="detailLastPurchase">28 Mar 2026</span>
</div>
</div>
</div>
<!-- Credit Info -->
<div class="detail-section">
<div class="detail-section__title">Crédito</div>
<div class="credit-block">
<div class="credit-metrics">
<div class="credit-metric">
<div class="credit-metric__label">Límite</div>
<div class="credit-metric__value" id="detailCreditLimit">$80,000</div>
</div>
<div class="credit-metric">
<div class="credit-metric__label">Disponible</div>
<div class="credit-metric__value available" id="detailCreditAvail">$48,500</div>
</div>
<div class="credit-metric">
<div class="credit-metric__label">Utilizado</div>
<div class="credit-metric__value used" id="detailCreditUsed">$31,500</div>
</div>
</div>
<div class="credit-progress">
<div class="credit-progress__labels">
<span>Utilización de crédito</span>
<span id="detailCreditPct">39%</span>
</div>
<div class="progress-bar">
<div class="progress-bar__fill low" id="detailCreditBar" style="width: 39%;"></div>
</div>
</div>
</div>
</div>
<!-- Quick Actions -->
<div class="detail-section">
<div class="detail-section__title">Acciones Rápidas</div>
<div class="quick-actions">
<button class="action-btn action-btn--primary">
<span class="action-btn__icon">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
<circle cx="5.5" cy="12" r="1.5"/><circle cx="11.5" cy="12" r="1.5"/>
<path d="M1 2h2l1.5 7h7l1.5-5H5"/>
</svg>
</span>
Nueva Venta
</button>
<button class="action-btn">
<span class="action-btn__icon">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round">
<path d="M2 11V14h3l8-8-3-3L2 11z"/>
</svg>
</span>
Editar
</button>
<button class="action-btn">
<span class="action-btn__icon">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round">
<rect x="2" y="2" width="12" height="12" rx="1"/><path d="M5 6h6M5 9h4"/>
</svg>
</span>
Estado de Cuenta
</button>
<button class="action-btn">
<span class="action-btn__icon">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round">
<path d="M8 1v14M1 8h14"/>
<circle cx="8" cy="8" r="6"/>
</svg>
</span>
Historial
</button>
</div>
</div>
<!-- Purchase History -->
<div class="detail-section" style="flex:1; padding-bottom: var(--space-5);">
<div class="detail-section__title">Historial de Compras (últimas 10)</div>
<table class="history-table">
<thead>
<tr>
<th>Fecha</th>
<th>Folio</th>
<th>Total</th>
<th>Estado</th>
</tr>
</thead>
<tbody id="historyBody">
<!-- rendered by JS -->
</tbody>
</table>
</div>
</div><!-- /detailContent -->
</div><!-- /panel-detail -->
</div><!-- /content-split -->
</div><!-- /main-content -->
</div><!-- /app-shell -->
<!-- ====================================================================
JAVASCRIPT
==================================================================== -->
<script>
/* ------------------------------------------------------------------
THEME SWITCHER
------------------------------------------------------------------ */
function setTheme(theme) {
document.documentElement.setAttribute('data-theme', theme);
document.getElementById('btn-industrial').classList.toggle('active', theme === 'industrial');
document.getElementById('btn-modern').classList.toggle('active', theme === 'modern');
}
/* ------------------------------------------------------------------
SAMPLE DATA
------------------------------------------------------------------ */
const customers = [
{
id: 1, num: '00001',
name: 'Taller Star Automotriz', initials: 'TS',
rfc: 'TSA820115HDF', phone: '55 1234-5678', email: 'ventas@tallerstar.mx',
tipo: 'Taller', credit: 48500, creditLimit: 80000,
lastPurchase: '28 Mar 2026', estado: 'Activo',
address: 'Av. Insurgentes Sur 1602, Col. Crédito Constructor, CDMX',
since: '14 Mar 2019',
history: [
{ date: '28 Mar 2026', folio: 'NX-20498', total: '$4,820.00', status: 'Pagado' },
{ date: '22 Mar 2026', folio: 'NX-20341', total: '$1,250.50', status: 'Pagado' },
{ date: '15 Mar 2026', folio: 'NX-20188', total: '$9,670.00', status: 'Pendiente' },
{ date: '07 Mar 2026', folio: 'NX-19982', total: '$3,100.00', status: 'Pagado' },
{ date: '28 Feb 2026', folio: 'NX-19740', total: '$6,450.00', status: 'Pagado' },
{ date: '14 Feb 2026', folio: 'NX-19510', total: '$2,890.00', status: 'Vencido' },
{ date: '05 Feb 2026', folio: 'NX-19301', total: '$5,220.00', status: 'Pagado' },
{ date: '25 Ene 2026', folio: 'NX-19050', total: '$780.00', status: 'Pagado' },
{ date: '18 Ene 2026', folio: 'NX-18890', total: '$11,340.00', status: 'Pagado' },
{ date: '10 Ene 2026', folio: 'NX-18720', total: '$4,100.00', status: 'Pagado' },
]
},
{
id: 2, num: '00002',
name: 'Refacciones El Trueno', initials: 'RT',
rfc: 'RTE930720HDF', phone: '55 9876-5432', email: 'compras@eltrueno.com',
tipo: 'Mayoreo', credit: 120000, creditLimit: 200000,
lastPurchase: '27 Mar 2026', estado: 'Activo',
address: 'Blvd. Adolfo López Mateos 2855, Álvaro Obregón, CDMX',
since: '02 Jun 2017',
history: [
{ date: '27 Mar 2026', folio: 'NX-20481', total: '$28,500.00', status: 'Pendiente' },
{ date: '20 Mar 2026', folio: 'NX-20290', total: '$15,670.00', status: 'Pagado' },
{ date: '12 Mar 2026', folio: 'NX-20110', total: '$42,300.00', status: 'Pagado' },
{ date: '04 Mar 2026', folio: 'NX-19930', total: '$8,900.00', status: 'Pagado' },
{ date: '25 Feb 2026', folio: 'NX-19720', total: '$33,100.00', status: 'Pagado' },
{ date: '16 Feb 2026', folio: 'NX-19480', total: '$21,450.00', status: 'Pagado' },
{ date: '07 Feb 2026', folio: 'NX-19240', total: '$9,800.00', status: 'Pagado' },
{ date: '28 Ene 2026', folio: 'NX-19010', total: '$47,200.00', status: 'Pagado' },
{ date: '19 Ene 2026', folio: 'NX-18840', total: '$18,660.00', status: 'Pagado' },
{ date: '10 Ene 2026', folio: 'NX-18650', total: '$12,400.00', status: 'Pagado' },
]
},
{
id: 3, num: '00003',
name: 'Karla Mendoza Jiménez', initials: 'KM',
rfc: 'MEJK891004MDF', phone: '55 5551-2233', email: 'karla.m@gmail.com',
tipo: 'Mostrador', credit: 0, creditLimit: 5000,
lastPurchase: '25 Mar 2026', estado: 'Activo',
address: 'Calle Fresno 44, Col. San Marcos, Xochimilco, CDMX',
since: '10 Ene 2023',
history: [
{ date: '25 Mar 2026', folio: 'NX-20445', total: '$340.00', status: 'Pagado' },
{ date: '10 Mar 2026', folio: 'NX-20080', total: '$780.00', status: 'Pagado' },
{ date: '18 Feb 2026', folio: 'NX-19560', total: '$210.00', status: 'Pagado' },
{ date: '05 Feb 2026', folio: 'NX-19290', total: '$1,200.00',status: 'Pagado' },
{ date: '20 Ene 2026', folio: 'NX-18920', total: '$450.00', status: 'Pagado' },
{ date: '03 Ene 2026', folio: 'NX-18600', total: '$890.00', status: 'Pagado' },
{ date: '15 Dic 2025', folio: 'NX-18100', total: '$620.00', status: 'Pagado' },
{ date: '01 Dic 2025', folio: 'NX-17890', total: '$330.00', status: 'Pagado' },
{ date: '18 Nov 2025', folio: 'NX-17620', total: '$1,100.00',status: 'Pagado' },
{ date: '05 Nov 2025', folio: 'NX-17390', total: '$780.00', status: 'Pagado' },
]
},
{
id: 4, num: '00004',
name: 'Distribuidora Central Norte', initials: 'DC',
rfc: 'DCN760315B24', phone: '55 8888-0011', email: 'pedidos@cnorte.mx',
tipo: 'Mayoreo', credit: 65000, creditLimit: 300000,
lastPurchase: '26 Mar 2026', estado: 'Mora',
address: 'Calz. de los Misterios 1420, Gustavo A. Madero, CDMX',
since: '30 Ago 2014',
history: [
{ date: '26 Mar 2026', folio: 'NX-20470', total: '$55,200.00', status: 'Pendiente' },
{ date: '15 Mar 2026', folio: 'NX-20140', total: '$38,900.00', status: 'Vencido' },
{ date: '05 Mar 2026', folio: 'NX-19960', total: '$22,100.00', status: 'Vencido' },
{ date: '18 Feb 2026', folio: 'NX-19500', total: '$41,700.00', status: 'Pagado' },
{ date: '06 Feb 2026', folio: 'NX-19270', total: '$29,800.00', status: 'Pagado' },
{ date: '25 Ene 2026', folio: 'NX-19040', total: '$63,400.00', status: 'Pagado' },
{ date: '14 Ene 2026', folio: 'NX-18810', total: '$17,600.00', status: 'Pagado' },
{ date: '03 Ene 2026', folio: 'NX-18580', total: '$34,900.00', status: 'Pagado' },
{ date: '22 Dic 2025', folio: 'NX-18200', total: '$48,100.00', status: 'Pagado' },
{ date: '10 Dic 2025', folio: 'NX-17980', total: '$26,300.00', status: 'Pagado' },
]
},
{
id: 5, num: '00005',
name: 'Taller Rápido Orozco', initials: 'TR',
rfc: 'ORCH751122HMC', phone: '55 7744-3322', email: 'rapidorozco@outlook.com',
tipo: 'Taller', credit: 18000, creditLimit: 25000,
lastPurchase: '24 Mar 2026', estado: 'Activo',
address: 'Calle Morelos 88, Col. Centro, Naucalpan, Edo. Méx.',
since: '05 May 2021',
history: [
{ date: '24 Mar 2026', folio: 'NX-20430', total: '$3,450.00', status: 'Pagado' },
{ date: '17 Mar 2026', folio: 'NX-20210', total: '$1,880.00', status: 'Pagado' },
{ date: '09 Mar 2026', folio: 'NX-20040', total: '$6,100.00', status: 'Pendiente' },
{ date: '01 Mar 2026', folio: 'NX-19870', total: '$2,200.00', status: 'Pagado' },
{ date: '22 Feb 2026', folio: 'NX-19660', total: '$4,760.00', status: 'Pagado' },
{ date: '12 Feb 2026', folio: 'NX-19420', total: '$920.00', status: 'Pagado' },
{ date: '02 Feb 2026', folio: 'NX-19200', total: '$3,340.00', status: 'Pagado' },
{ date: '24 Ene 2026', folio: 'NX-18990', total: '$1,560.00', status: 'Pagado' },
{ date: '15 Ene 2026', folio: 'NX-18800', total: '$5,280.00', status: 'Pagado' },
{ date: '06 Ene 2026', folio: 'NX-18610', total: '$2,990.00', status: 'Pagado' },
]
},
{
id: 6, num: '00006',
name: 'Servicios Automotrices Luna', initials: 'SL',
rfc: 'SAL880903HDF', phone: '55 3311-7766', email: 'luna.serv@yahoo.com',
tipo: 'Taller', credit: 4500, creditLimit: 15000,
lastPurchase: '23 Mar 2026', estado: 'Activo',
address: 'Av. Taxqueña 1201, Coyoacán, CDMX',
since: '12 Sep 2020',
history: [
{ date: '23 Mar 2026', folio: 'NX-20410', total: '$2,100.00', status: 'Pagado' },
{ date: '14 Mar 2026', folio: 'NX-20170', total: '$880.00', status: 'Pagado' },
{ date: '06 Mar 2026', folio: 'NX-19990', total: '$3,650.00', status: 'Pagado' },
{ date: '25 Feb 2026', folio: 'NX-19730', total: '$1,220.00', status: 'Pagado' },
{ date: '15 Feb 2026', folio: 'NX-19490', total: '$4,400.00', status: 'Pagado' },
{ date: '05 Feb 2026', folio: 'NX-19260', total: '$760.00', status: 'Pagado' },
{ date: '26 Ene 2026', folio: 'NX-19030', total: '$2,980.00', status: 'Pagado' },
{ date: '16 Ene 2026', folio: 'NX-18820', total: '$1,450.00', status: 'Pagado' },
{ date: '07 Ene 2026', folio: 'NX-18630', total: '$3,100.00', status: 'Pagado' },
{ date: '28 Dic 2025', folio: 'NX-18240', total: '$590.00', status: 'Pagado' },
]
},
{
id: 7, num: '00007',
name: 'Autoservicio El Piston', initials: 'AP',
rfc: 'AEP920601HDF', phone: '55 2299-1144', email: 'elpiston@hotmail.com',
tipo: 'Mostrador', credit: 3200, creditLimit: 10000,
lastPurchase: '21 Mar 2026', estado: 'Inactivo',
address: 'Calle Hidalgo 557, Tlalnepantla, Edo. Méx.',
since: '20 Feb 2022',
history: [
{ date: '21 Mar 2026', folio: 'NX-20380', total: '$1,800.00', status: 'Pagado' },
{ date: '08 Mar 2026', folio: 'NX-20020', total: '$940.00', status: 'Pagado' },
{ date: '18 Feb 2026', folio: 'NX-19520', total: '$2,600.00', status: 'Pagado' },
{ date: '05 Feb 2026', folio: 'NX-19290', total: '$780.00', status: 'Pagado' },
{ date: '23 Ene 2026', folio: 'NX-19010', total: '$3,400.00', status: 'Pagado' },
{ date: '12 Ene 2026', folio: 'NX-18790', total: '$560.00', status: 'Pagado' },
{ date: '02 Ene 2026', folio: 'NX-18560', total: '$1,230.00', status: 'Pagado' },
{ date: '20 Dic 2025', folio: 'NX-18160', total: '$2,100.00', status: 'Pagado' },
{ date: '09 Dic 2025', folio: 'NX-17960', total: '$870.00', status: 'Pagado' },
{ date: '28 Nov 2025', folio: 'NX-17740', total: '$1,540.00', status: 'Pagado' },
]
},
{
id: 8, num: '00008',
name: 'Mega Partes Industriales', initials: 'MP',
rfc: 'MPI840718B56', phone: '55 6600-9988', email: 'compras@megapartes.mx',
tipo: 'Mayoreo', credit: 200000, creditLimit: 500000,
lastPurchase: '29 Mar 2026', estado: 'Activo',
address: 'Av. 5 de Mayo 3800, Zona Industrial, Tlalnepantla, Edo. Méx.',
since: '08 Nov 2012',
history: [
{ date: '29 Mar 2026', folio: 'NX-20495', total: '$88,400.00', status: 'Pendiente' },
{ date: '23 Mar 2026', folio: 'NX-20415', total: '$62,100.00', status: 'Pagado' },
{ date: '16 Mar 2026', folio: 'NX-20230', total: '$105,800.00', status: 'Pagado' },
{ date: '08 Mar 2026', folio: 'NX-20050', total: '$47,300.00', status: 'Pagado' },
{ date: '28 Feb 2026', folio: 'NX-19750', total: '$93,600.00', status: 'Pagado' },
{ date: '19 Feb 2026', folio: 'NX-19540', total: '$38,700.00', status: 'Pagado' },
{ date: '09 Feb 2026', folio: 'NX-19310', total: '$71,200.00', status: 'Pagado' },
{ date: '30 Ene 2026', folio: 'NX-19080', total: '$56,900.00', status: 'Pagado' },
{ date: '21 Ene 2026', folio: 'NX-18870', total: '$43,500.00', status: 'Pagado' },
{ date: '12 Ene 2026', folio: 'NX-18680', total: '$82,100.00', status: 'Pagado' },
]
},
{
id: 9, num: '00009',
name: 'Taller Mecánico Pérez Hnos.', initials: 'TP',
rfc: 'PHM950228HDF', phone: '55 4433-6677', email: 'perezhermanos@gmail.com',
tipo: 'Taller', credit: 12000, creditLimit: 20000,
lastPurchase: '20 Mar 2026', estado: 'Activo',
address: 'Calle 5 No. 234, Col. Agrícola Oriental, Iztacalco, CDMX',
since: '14 Jul 2020',
history: [
{ date: '20 Mar 2026', folio: 'NX-20360', total: '$5,600.00', status: 'Pagado' },
{ date: '11 Mar 2026', folio: 'NX-20100', total: '$2,340.00', status: 'Pendiente' },
{ date: '02 Mar 2026', folio: 'NX-19900', total: '$7,800.00', status: 'Pagado' },
{ date: '21 Feb 2026', folio: 'NX-19640', total: '$1,450.00', status: 'Pagado' },
{ date: '11 Feb 2026', folio: 'NX-19400', total: '$3,900.00', status: 'Pagado' },
{ date: '01 Feb 2026', folio: 'NX-19180', total: '$6,200.00', status: 'Pagado' },
{ date: '23 Ene 2026', folio: 'NX-18970', total: '$2,890.00', status: 'Pagado' },
{ date: '14 Ene 2026', folio: 'NX-18780', total: '$4,100.00', status: 'Pagado' },
{ date: '05 Ene 2026', folio: 'NX-18590', total: '$1,780.00', status: 'Pagado' },
{ date: '27 Dic 2025', folio: 'NX-18210', total: '$8,400.00', status: 'Pagado' },
]
},
{
id: 10, num: '00010',
name: 'Import Autoparts Villanueva', initials: 'IV',
rfc: 'IAV010315B34', phone: '55 9900-1122', email: 'ventas@importav.mx',
tipo: 'Mayoreo', credit: 95000, creditLimit: 150000,
lastPurchase: '28 Mar 2026', estado: 'Activo',
address: 'Blvd. Manuel Ávila Camacho 600, Naucalpan, Edo. Méx.',
since: '22 Mar 2015',
history: [
{ date: '28 Mar 2026', folio: 'NX-20490', total: '$34,500.00', status: 'Pendiente' },
{ date: '21 Mar 2026', folio: 'NX-20370', total: '$22,800.00', status: 'Pagado' },
{ date: '13 Mar 2026', folio: 'NX-20160', total: '$48,900.00', status: 'Pagado' },
{ date: '05 Mar 2026', folio: 'NX-19950', total: '$16,700.00', status: 'Pagado' },
{ date: '24 Feb 2026', folio: 'NX-19700', total: '$39,200.00', status: 'Pagado' },
{ date: '14 Feb 2026', folio: 'NX-19460', total: '$27,600.00', status: 'Pagado' },
{ date: '04 Feb 2026', folio: 'NX-19220', total: '$11,400.00', status: 'Pagado' },
{ date: '26 Ene 2026', folio: 'NX-19000', total: '$53,800.00', status: 'Pagado' },
{ date: '17 Ene 2026', folio: 'NX-18810', total: '$24,100.00', status: 'Pagado' },
{ date: '08 Ene 2026', folio: 'NX-18620', total: '$31,600.00', status: 'Pagado' },
]
},
{
id: 11, num: '00011',
name: 'Centro Automotriz Garza', initials: 'CG',
rfc: 'GAR780904HNL', phone: '81 2244-5566', email: 'garza.auto@prodigy.net',
tipo: 'Taller', credit: 9000, creditLimit: 30000,
lastPurchase: '18 Mar 2026', estado: 'Activo',
address: 'Av. Constitución 1888, Monterrey, N.L.',
since: '07 Feb 2018',
history: [
{ date: '18 Mar 2026', folio: 'NX-20280', total: '$7,200.00', status: 'Pagado' },
{ date: '08 Mar 2026', folio: 'NX-20030', total: '$3,400.00', status: 'Pagado' },
{ date: '26 Feb 2026', folio: 'NX-19760', total: '$9,100.00', status: 'Pendiente' },
{ date: '16 Feb 2026', folio: 'NX-19510', total: '$4,800.00', status: 'Pagado' },
{ date: '06 Feb 2026', folio: 'NX-19270', total: '$6,550.00', status: 'Pagado' },
{ date: '27 Ene 2026', folio: 'NX-19040', total: '$2,100.00', status: 'Pagado' },
{ date: '17 Ene 2026', folio: 'NX-18820', total: '$8,300.00', status: 'Pagado' },
{ date: '08 Ene 2026', folio: 'NX-18630', total: '$3,670.00', status: 'Pagado' },
{ date: '29 Dic 2025', folio: 'NX-18250', total: '$11,400.00', status: 'Pagado' },
{ date: '18 Dic 2025', folio: 'NX-18020', total: '$5,890.00', status: 'Pagado' },
]
},
{
id: 12, num: '00012',
name: 'Refacciones El Farol', initials: 'RF',
rfc: 'REF011120B45', phone: '33 5577-8899', email: 'elfarol.ref@gmail.com',
tipo: 'Mostrador', credit: 7500, creditLimit: 10000,
lastPurchase: '17 Mar 2026', estado: 'Inactivo',
address: 'Calz. Independencia Sur 2340, Guadalajara, Jal.',
since: '15 Oct 2021',
history: [
{ date: '17 Mar 2026', folio: 'NX-20260', total: '$2,500.00', status: 'Pendiente' },
{ date: '06 Mar 2026', folio: 'NX-20010', total: '$1,800.00', status: 'Pagado' },
{ date: '23 Feb 2026', folio: 'NX-19680', total: '$3,200.00', status: 'Pagado' },
{ date: '12 Feb 2026', folio: 'NX-19440', total: '$900.00', status: 'Pagado' },
{ date: '01 Feb 2026', folio: 'NX-19200', total: '$4,100.00', status: 'Pagado' },
{ date: '21 Ene 2026', folio: 'NX-18960', total: '$1,550.00', status: 'Pagado' },
{ date: '11 Ene 2026', folio: 'NX-18770', total: '$2,800.00', status: 'Pagado' },
{ date: '02 Ene 2026', folio: 'NX-18540', total: '$680.00', status: 'Pagado' },
{ date: '21 Dic 2025', folio: 'NX-18170', total: '$3,600.00', status: 'Pagado' },
{ date: '10 Dic 2025', folio: 'NX-17970', total: '$1,200.00', status: 'Pagado' },
]
},
];
let selectedCustomerId = null;
let filteredCustomers = [...customers];
/* ------------------------------------------------------------------
RENDER TABLE
------------------------------------------------------------------ */
function renderTable(data) {
const tbody = document.getElementById('customersBody');
tbody.innerHTML = '';
if (data.length === 0) {
tbody.innerHTML = `<tr><td colspan="9" style="text-align:center;padding:var(--space-8);color:var(--color-text-muted);">Sin resultados para la búsqueda.</td></tr>`;
return;
}
data.forEach(c => {
const pct = Math.round(((c.creditLimit - c.credit) / c.creditLimit) * 100);
const creditClass = pct >= 80 ? 'none' : pct >= 60 ? 'low' : '';
const creditFormatted = new Intl.NumberFormat('es-MX', { style:'currency', currency:'MXN', minimumFractionDigits:0 }).format(c.credit);
let estadoBadge = '';
if (c.estado === 'Activo') estadoBadge = `<span class="badge badge--active"><span class="badge-dot"></span>Activo</span>`;
else if (c.estado === 'Inactivo') estadoBadge = `<span class="badge badge--inactive"><span class="badge-dot"></span>Inactivo</span>`;
else estadoBadge = `<span class="badge badge--warning"><span class="badge-dot"></span>Mora</span>`;
const tipoClass = c.tipo === 'Taller' ? 'tipo-chip--taller' : c.tipo === 'Mayoreo' ? 'tipo-chip--mayoreo' : 'tipo-chip--mostrador';
const isSelected = c.id === selectedCustomerId;
const tr = document.createElement('tr');
tr.className = isSelected ? 'selected' : '';
tr.onclick = () => selectCustomer(c.id);
tr.innerHTML = `
<td class="cell-num">${c.num}</td>
<td>
<div class="cell-name">${c.name}</div>
<div class="cell-name-sub hide-mobile">${c.email}</div>
</td>
<td class="cell-rfc hide-mobile">${c.rfc}</td>
<td class="hide-mobile">${c.phone}</td>
<td class="hide-mobile" style="font-size:var(--text-caption);color:var(--color-text-secondary);">${c.email}</td>
<td><span class="tipo-chip ${tipoClass}">${c.tipo}</span></td>
<td class="cell-credit ${creditClass}">${creditFormatted}</td>
<td class="cell-date hide-mobile">${c.lastPurchase}</td>
<td>${estadoBadge}</td>
`;
tbody.appendChild(tr);
});
}
/* ------------------------------------------------------------------
FILTER
------------------------------------------------------------------ */
function filterCustomers() {
const q = document.getElementById('searchInput').value.toLowerCase();
const tipo = document.getElementById('tipoFilter').value;
const estado = document.getElementById('estadoFilter').value;
filteredCustomers = customers.filter(c => {
const matchQ = !q || c.name.toLowerCase().includes(q) || c.rfc.toLowerCase().includes(q) || c.phone.includes(q) || c.email.toLowerCase().includes(q);
const matchT = !tipo || c.tipo === tipo;
const matchE = !estado || c.estado === estado;
return matchQ && matchT && matchE;
});
renderTable(filteredCustomers);
document.getElementById('tableInfo').textContent = `Mostrando ${filteredCustomers.length} de ${customers.length} clientes`;
}
/* ------------------------------------------------------------------
SELECT CUSTOMER — populate detail panel
------------------------------------------------------------------ */
function selectCustomer(id) {
const c = customers.find(x => x.id === id);
if (!c) return;
selectedCustomerId = id;
// Toggle empty/content
document.getElementById('detailEmpty').style.display = 'none';
const detail = document.getElementById('detailContent');
detail.style.display = 'flex';
// Avatar
document.getElementById('detailAvatar').textContent = c.initials;
// Header
document.getElementById('detailName').textContent = c.name.toUpperCase();
document.getElementById('detailRFC').textContent = c.rfc;
// Tipo chip
const tipoEl = document.getElementById('detailTipo');
tipoEl.textContent = c.tipo;
tipoEl.className = `tipo-chip tipo-chip--${c.tipo.toLowerCase()}`;
// Status badge
const statEl = document.getElementById('detailStatus');
if (c.estado === 'Activo') {
statEl.className = 'badge badge--active';
statEl.innerHTML = '<span class="badge-dot"></span>Activo';
} else if (c.estado === 'Inactivo') {
statEl.className = 'badge badge--inactive';
statEl.innerHTML = '<span class="badge-dot"></span>Inactivo';
} else {
statEl.className = 'badge badge--warning';
statEl.innerHTML = '<span class="badge-dot"></span>En Mora';
}
// Contact
document.getElementById('detailAddress').textContent = c.address;
document.getElementById('detailPhone').textContent = c.phone;
document.getElementById('detailEmail').textContent = c.email;
document.getElementById('detailSince').textContent = c.since;
document.getElementById('detailLastPurchase').textContent = c.lastPurchase;
// Credit
const fmt = n => new Intl.NumberFormat('es-MX', { style:'currency', currency:'MXN', minimumFractionDigits:0 }).format(n);
const used = c.creditLimit - c.credit;
const pct = Math.round((used / c.creditLimit) * 100);
document.getElementById('detailCreditLimit').textContent = fmt(c.creditLimit);
document.getElementById('detailCreditAvail').textContent = fmt(c.credit);
document.getElementById('detailCreditUsed').textContent = fmt(used);
document.getElementById('detailCreditPct').textContent = `${pct}%`;
const bar = document.getElementById('detailCreditBar');
bar.style.width = `${pct}%`;
bar.className = `progress-bar__fill ${pct < 40 ? 'low' : pct > 75 ? 'high' : ''}`;
// Purchase History
const hbody = document.getElementById('historyBody');
hbody.innerHTML = '';
c.history.forEach(h => {
const statusClass = h.status === 'Pagado' ? 'mbadge--paid' : h.status === 'Vencido' ? 'mbadge--overdue' : 'mbadge--pending';
const tr = document.createElement('tr');
tr.innerHTML = `
<td class="date">${h.date}</td>
<td class="folio">${h.folio}</td>
<td class="total">${h.total}</td>
<td><span class="mbadge ${statusClass}">${h.status}</span></td>
`;
hbody.appendChild(tr);
});
// Re-render table to update selected row highlight
renderTable(filteredCustomers);
}
function closeDetail() {
selectedCustomerId = null;
document.getElementById('detailEmpty').style.display = 'flex';
document.getElementById('detailContent').style.display = 'none';
renderTable(filteredCustomers);
}
function openNewCustomerModal() {
alert('Modal "Nuevo Cliente" — pendiente de implementación en sprint 2.');
}
/* ------------------------------------------------------------------
INIT
------------------------------------------------------------------ */
renderTable(customers);
// Pre-select first customer on load for demo
selectCustomer(1);
</script>
</body>
</html>