/* ============================================================================ Jorge Cuadros & Asociados — design system Warm coastal-professional identity for a Baja California firm. Fraunces (display serif) + Work Sans (UI) + JetBrains Mono (data). Palette: cream paper, deep pine brand, terracotta accent, gold = Servicios, teal = Seguros, aubergine = Fideicomiso. ========================================================================== */ :root { /* neutrals — warm paper family */ --paper: #f5f1e8; --paper-2: #efe9dc; --surface: #fffefb; --surface-2: #faf6ee; --line: #e4dccb; --line-strong: #d3c8b1; /* ink / text */ --ink: #211d17; --ink-soft: #4b4438; --muted: #756c5c; --muted-2: #98907e; /* brand — deep pine teal */ --brand-900: #0c322d; --brand-800: #113f38; --brand-700: #16544a; --brand-600: #1c6b5e; --brand-500: #24897a; --brand-tint: #e2ede9; /* accent — terracotta clay (CTA / focus / links) */ --accent: #bf5a34; --accent-600: #a94c2a; --accent-tint: #f6e4da; /* line-of-business + domains */ --servicios: #9a6a12; /* gold / ochre — utilities */ --servicios-tint: #f2e6c8; --servicios-ink: #6d4a08; --seguros: #0f6f68; /* teal — insurance */ --seguros-tint: #d3ebe7; --seguros-ink: #0a4b46; --fideicomiso: #6d3f60; /* aubergine — trust */ --fideicomiso-tint: #eddced; --fideicomiso-ink: #4a2a41; /* semantic */ --positive: #2f6d3c; --positive-tint: #dcecdd; --negative: #a23a2c; --negative-tint: #f4dcd6; /* shape + motion */ --radius-sm: 6px; --radius: 10px; --radius-lg: 16px; --shadow-sm: 0 1px 2px rgba(33, 29, 23, 0.06), 0 1px 3px rgba(33, 29, 23, 0.05); --shadow: 0 2px 4px rgba(33, 29, 23, 0.05), 0 8px 24px -12px rgba(33, 29, 23, 0.18); --shadow-lg: 0 24px 60px -24px rgba(12, 50, 45, 0.35); --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1); --ease-out-quart: cubic-bezier(0.25, 1, 0.5, 1); --font-display: "Fraunces", "Iowan Old Style", "Palatino Linotype", Georgia, serif; --font-sans: "Work Sans", system-ui, -apple-system, "Segoe UI", sans-serif; --font-mono: "JetBrains Mono", ui-monospace, "SF Mono", "Cascadia Code", Menlo, monospace; --shell-max: 1180px; } * { box-sizing: border-box; } html, body { margin: 0; padding: 0; } /* ---------------------------------------------------------------------------- User-adjustable text size. Every font-size in this stylesheet is expressed in rem, so the whole UI follows the root size and one variable scales it all. --ui-scale is written onto by the pre-hydration script in layout.tsx (read from localStorage, so there is no flash of the wrong size) and updated live by the Aa control in the appbar. A percentage keeps the browser's own base font size honoured instead of hard-coding 16px over it. -------------------------------------------------------------------------- */ html { font-size: calc(100% * var(--ui-scale, 1)); } body { font-family: var(--font-sans); background-color: var(--paper); /* subtle paper grain via layered radial dots */ background-image: radial-gradient( circle at 1px 1px, rgba(33, 29, 23, 0.035) 1px, transparent 0 ); background-size: 22px 22px; color: var(--ink); font-size: 0.9375rem; line-height: 1.55; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; } h1, h2, h3, h4 { font-family: var(--font-display); font-weight: 560; color: var(--ink); letter-spacing: -0.01em; margin: 0; line-height: 1.12; } a { color: var(--accent-600); text-decoration: none; } a:hover { text-decoration: underline; } button { font-family: inherit; cursor: pointer; } :focus-visible { outline: 2.5px solid var(--accent); outline-offset: 2px; border-radius: 4px; } .mono { font-family: var(--font-mono); font-feature-settings: "tnum" 1; } /* ---- layout helpers ---- */ .shell-main { max-width: var(--shell-max); margin: 0 auto; padding: 2.125rem 1.75rem 6rem; } @media (max-width: 640px) { .shell-main { padding: 1.375rem 1rem 4.5rem; } } /* Deployed-build line. Quiet by default — it only needs to be legible when someone is verifying a release or a rollback. */ .shell-footer { max-width: var(--shell-max); margin: 0 auto; padding: 1rem 1.75rem 1.75rem; display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.75rem; font-size: 0.75rem; color: var(--muted-2); border-top: 1px solid var(--line); } .shell-footer-build { font-family: var(--font-mono); font-variant-numeric: tabular-nums; cursor: help; /* Full 40-char commit hashes, and two of them when the tiers disagree. Hex offers no break opportunity, so without this the line pushes the page into horizontal scroll on a phone. */ min-width: 0; overflow-wrap: anywhere; } .shell-footer-warn { color: var(--negative); background: var(--negative-tint); border-radius: var(--radius-sm); padding: 0.0625rem 0.375rem; font-weight: 600; } @media (max-width: 640px) { .shell-footer { padding: 1rem 1rem 1.5rem; } } .eyebrow { font-family: var(--font-sans); text-transform: uppercase; letter-spacing: 0.16em; font-size: 0.6875rem; font-weight: 600; color: var(--muted); } .muted { color: var(--muted); } /* Secondary line inside a row or card — used alongside .muted throughout. */ .small { font-size: 0.8125rem; } /* ============================================================================ App shell / top nav ========================================================================== */ .appbar { position: sticky; top: 0; z-index: 40; background: linear-gradient(180deg, var(--brand-900), var(--brand-800)); color: #f2efe7; border-bottom: 1px solid rgba(0, 0, 0, 0.25); } .appbar-inner { max-width: var(--shell-max); margin: 0 auto; padding: 0 1.75rem; /* min-height, not height: the bar has to grow when the user scales text up. */ min-height: 3.875rem; display: flex; align-items: center; gap: 1.625rem; } @media (max-width: 640px) { .appbar-inner { padding: 0 1rem; gap: 0.875rem; } } .brand { display: flex; align-items: center; gap: 0.75rem; color: #f6f3ec; text-decoration: none; } .brand:hover { text-decoration: none; } .brand-mark { width: 38px; height: 38px; border-radius: 9px; background: #fbf8f0; border: 1px solid rgba(255, 255, 255, 0.18); object-fit: contain; padding: 0.1875rem; box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.2); } .login-brand .brand-mark { width: 46px; height: 46px; border-radius: 10px; } .brand-text { display: flex; flex-direction: column; line-height: 1.05; } .brand-name { font-family: var(--font-display); font-size: 1rem; font-weight: 560; letter-spacing: -0.01em; } .brand-sub { font-size: 0.65625rem; letter-spacing: 0.14em; text-transform: uppercase; color: rgba(242, 239, 231, 0.62); } @media (max-width: 500px) { .brand-sub { display: none; } } .appbar-nav { display: flex; align-items: center; gap: 0.25rem; margin-left: 0.5rem; } .appbar-link { color: rgba(242, 239, 231, 0.78); padding: 0.4375rem 0.75rem; border-radius: 7px; font-size: 0.875rem; font-weight: 500; white-space: nowrap; } .appbar-link:hover { color: #fff; background: rgba(255, 255, 255, 0.08); text-decoration: none; } .appbar-link.active { color: #fff; background: rgba(255, 255, 255, 0.12); } /* Grouped nav entries ("Cobranza", "Admin") */ .appbar-menu { position: relative; } .appbar-menu-trigger { display: inline-flex; align-items: center; gap: 0.375rem; border: 0; background: transparent; font: inherit; font-size: 0.875rem; font-weight: 500; cursor: pointer; } .appbar-caret { width: 0; height: 0; border-left: 4px solid transparent; border-right: 4px solid transparent; border-top: 4.5px solid currentColor; opacity: 0.7; } .appbar-menu-trigger[aria-expanded="true"] { color: #fff; background: rgba(255, 255, 255, 0.12); } .appbar-dropdown { position: absolute; top: calc(100% + 8px); left: 0; min-width: 194px; padding: 0.375rem; display: flex; flex-direction: column; gap: 0.125rem; background: var(--surface); border: 1px solid var(--line); border-radius: 10px; box-shadow: 0 12px 30px rgba(12, 50, 45, 0.22); z-index: 50; } .appbar-dropdown-link { padding: 0.5rem 0.6875rem; border-radius: 7px; font-size: 0.875rem; color: var(--ink); white-space: nowrap; } .appbar-dropdown-link:hover { background: var(--brand-tint); color: var(--brand-800); text-decoration: none; } .appbar-dropdown-link.active { background: var(--brand-tint); color: var(--brand-800); font-weight: 600; box-shadow: inset 2px 0 0 var(--brand-600); } .appbar-dropdown-right { left: auto; right: 0; } .appbar-spacer { flex: 1; } /* Text-size control */ .appbar-scale-trigger { display: inline-flex; align-items: baseline; justify-content: center; min-width: 2.25rem; padding: 0.3125rem 0.5rem; border: 1px solid rgba(255, 255, 255, 0.22); border-radius: 0.5rem; background: rgba(255, 255, 255, 0.06); color: rgba(242, 239, 231, 0.85); font-family: var(--font-sans); font-size: 0.75rem; font-weight: 600; line-height: 1; cursor: pointer; } .appbar-scale-trigger:hover, .appbar-scale-trigger[aria-expanded="true"] { background: rgba(255, 255, 255, 0.14); color: #fff; } .appbar-scale-big { font-size: 1.25rem; } .scale-option { display: flex; align-items: baseline; gap: 0.625rem; width: 100%; border: 0; background: transparent; font-family: var(--font-sans); text-align: left; cursor: pointer; } .scale-option > span:first-child { width: 1.5rem; flex: none; font-weight: 700; line-height: 1; } .scale-option-label { font-size: 0.875rem; } .scale-inline { display: flex; flex-direction: column; gap: 0.375rem; margin-top: 0.75rem; padding-top: 0.75rem; border-top: 1px solid rgba(255, 255, 255, 0.1); } .scale-inline-options { display: flex; align-items: baseline; gap: 0.375rem; padding: 0 0.75rem; } .scale-chip { min-width: 2.75rem; padding: 0.5rem 0.375rem; border: 1px solid rgba(255, 255, 255, 0.2); border-radius: 0.5rem; background: rgba(255, 255, 255, 0.06); color: rgba(242, 239, 231, 0.82); font-family: var(--font-sans); font-weight: 700; line-height: 1; cursor: pointer; } .scale-chip.active { background: rgba(255, 255, 255, 0.18); border-color: rgba(255, 255, 255, 0.4); color: #fff; } /* Mobile menu button + drawer */ .appbar-burger { display: none; width: 38px; height: 38px; padding: 0; border: 1px solid rgba(255, 255, 255, 0.22); border-radius: 9px; background: rgba(255, 255, 255, 0.06); cursor: pointer; place-items: center; } .burger-icon { position: relative; } .burger-icon, .burger-icon::before, .burger-icon::after { display: block; width: 17px; height: 1.8px; border-radius: 2px; background: #f2efe7; transition: transform 0.16s ease, opacity 0.16s ease; } .burger-icon::before, .burger-icon::after { content: ""; position: absolute; } .burger-icon::before { transform: translateY(-5.5px); } .burger-icon::after { transform: translateY(5.5px); } .burger-icon.open { background: transparent; } .burger-icon.open::before { transform: rotate(45deg); } .burger-icon.open::after { transform: rotate(-45deg); } .appbar-drawer { display: none; flex-direction: column; gap: 0.125rem; padding: 0.5rem 1rem 1rem; border-top: 1px solid rgba(255, 255, 255, 0.1); } .appbar-drawer-group { display: flex; flex-direction: column; gap: 0.125rem; margin-top: 0.5rem; } .appbar-drawer-heading { padding: 0.375rem 0.75rem 0.125rem; font-size: 0.65625rem; letter-spacing: 0.14em; text-transform: uppercase; color: rgba(242, 239, 231, 0.45); } .appbar-drawer-link { padding: 0.625rem 0.75rem; border-radius: 8px; font-size: 0.9375rem; color: rgba(242, 239, 231, 0.82); } .appbar-drawer-link:hover { background: rgba(255, 255, 255, 0.08); color: #fff; text-decoration: none; } .appbar-drawer-link.active { background: rgba(255, 255, 255, 0.13); color: #fff; font-weight: 600; } .appbar-drawer-user { margin-top: 0.75rem; padding: 0.625rem 0.75rem 0; border-top: 1px solid rgba(255, 255, 255, 0.1); font-size: 0.78125rem; color: rgba(242, 239, 231, 0.55); } @media (max-width: 980px) { .appbar-nav { display: none; } .appbar-burger { display: grid; } .appbar-drawer { display: flex; } } .appbar-user { display: flex; align-items: center; gap: 0.75rem; font-size: 0.8125rem; color: rgba(242, 239, 231, 0.7); } .appbar-user-name { display: inline-flex; flex-direction: column; line-height: 1.2; } .appbar-user-role { font-size: 0.6875rem; color: rgba(242, 239, 231, 0.45); } /* Below the drawer breakpoint the drawer carries the user's name/role. */ @media (max-width: 980px) { .appbar-user .appbar-user-name { display: none; } } /* ============================================================================ Admin form grid (users, and future CRUD forms) ========================================================================== */ .form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 1rem; } .form-actions { display: flex; gap: 0.625rem; margin-top: 1.125rem; flex-wrap: wrap; } .row-actions { display: flex; gap: 0.5rem; align-items: center; justify-content: flex-end; } .detail-actionbar { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; flex-wrap: wrap; margin-bottom: 0.5rem; } .inline-form-note { font-size: 0.8125rem; color: var(--muted, #6b7280); margin: 0.25rem 0 0.875rem; } .child-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.625rem; } .child-editor { border-top: 1px solid rgba(0, 0, 0, 0.08); margin-top: 0.75rem; padding-top: 0.875rem; } .picker { position: relative; } .picker-selected { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; padding: 0.5rem 0.75rem; border: 1px solid rgba(0, 0, 0, 0.15); border-radius: 8px; } .picker-list { position: absolute; z-index: 20; top: 100%; left: 0; right: 0; margin: 0.25rem 0 0; padding: 0.25rem; list-style: none; background: var(--card-bg, #fff); border: 1px solid rgba(0, 0, 0, 0.15); border-radius: 8px; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12); max-height: 280px; overflow-y: auto; } .picker-item { display: block; width: 100%; text-align: left; padding: 0.5rem 0.625rem; border: 0; background: transparent; border-radius: 6px; cursor: pointer; font: inherit; } .picker-item:hover { background: rgba(0, 0, 0, 0.05); } /* ============================================================================ Buttons ========================================================================== */ .btn { display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem; border-radius: var(--radius-sm); border: 1px solid transparent; padding: 0.5625rem 1rem; font-size: 0.875rem; font-weight: 600; line-height: 1; transition: transform 0.12s var(--ease-out-quart), background 0.15s, box-shadow 0.15s, border-color 0.15s; } .btn:active { transform: translateY(1px); } .btn-primary { background: var(--accent); color: #fff; box-shadow: 0 1px 0 rgba(0, 0, 0, 0.08), inset 0 1px 0 rgba(255, 255, 255, 0.15); } .btn-primary:hover { background: var(--accent-600); text-decoration: none; } .btn-ghost { background: transparent; color: var(--ink-soft); border-color: var(--line-strong); } .btn-ghost:hover { background: var(--surface-2); color: var(--ink); border-color: var(--brand-600); text-decoration: none; } /* Dark appbar keeps the light-on-dark ghost button. */ .appbar .btn-ghost { color: rgba(242, 239, 231, 0.85); border-color: rgba(255, 255, 255, 0.22); } .appbar .btn-ghost:hover { background: rgba(255, 255, 255, 0.1); color: #fff; border-color: rgba(255, 255, 255, 0.35); } .btn-outline { background: var(--surface); color: var(--ink-soft); border-color: var(--line-strong); } .btn-outline:hover { border-color: var(--brand-600); color: var(--brand-700); text-decoration: none; } .btn:disabled { opacity: 0.55; cursor: not-allowed; transform: none; } /* ============================================================================ Cards / panels ========================================================================== */ .card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-lg); box-shadow: var(--shadow-sm); } /* ============================================================================ Badges / chips ========================================================================== */ .badge { display: inline-flex; align-items: center; gap: 0.375rem; padding: 0.1875rem 0.5625rem; border-radius: 999px; font-size: 0.75rem; font-weight: 600; letter-spacing: 0.01em; line-height: 1.4; border: 1px solid transparent; white-space: nowrap; } .badge .dot { width: 7px; height: 7px; border-radius: 50%; } .badge-servicios { background: var(--servicios-tint); color: var(--servicios-ink); border-color: rgba(154, 106, 18, 0.28); } .badge-servicios .dot { background: var(--servicios); } .badge-seguros { background: var(--seguros-tint); color: var(--seguros-ink); border-color: rgba(15, 111, 104, 0.28); } .badge-seguros .dot { background: var(--seguros); } .badge-fideicomiso { background: var(--fideicomiso-tint); color: var(--fideicomiso-ink); border-color: rgba(109, 63, 96, 0.28); } .badge-fideicomiso .dot { background: var(--fideicomiso); } .badge-neutral { background: var(--paper-2); color: var(--muted); border-color: var(--line-strong); } .badge-positive { background: var(--positive-tint); color: var(--positive); border-color: rgba(47, 109, 60, 0.25); } .badge-negative { background: var(--negative-tint); color: var(--negative); border-color: rgba(162, 58, 44, 0.25); } .badge-count { font-family: var(--font-mono); font-feature-settings: "tnum" 1; } /* ============================================================================ Utility animation ========================================================================== */ @keyframes rise { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } .rise { animation: rise 0.5s var(--ease-out-expo) both; } @keyframes spin { to { transform: rotate(360deg); } } .spinner { width: 18px; height: 18px; border-radius: 50%; border: 2.5px solid currentColor; border-top-color: transparent; animation: spin 0.7s linear infinite; display: inline-block; } /* Upload progress (Operaciones ingest) */ .upload-progress { display: flex; flex-direction: column; gap: 6px; padding: 4px 0 8px; } .progress-track { position: relative; overflow: hidden; height: 8px; border-radius: 999px; background: var(--paper-2); } .progress-fill { height: 100%; border-radius: 999px; background: var(--brand-500); transition: width 0.2s linear; } .progress-indeterminate .progress-fill { width: 40% !important; animation: progress-slide 1.2s var(--ease-out-quart) infinite; } @keyframes progress-slide { 0% { transform: translateX(-100%); } 100% { transform: translateX(250%); } } .upload-progress-stats { display: flex; flex-wrap: wrap; gap: 12px; font-size: 12px; color: var(--muted); } @keyframes shimmer { 0% { background-position: -420px 0; } 100% { background-position: 420px 0; } } .skeleton { background: linear-gradient( 90deg, var(--paper-2) 25%, #e8e1d2 37%, var(--paper-2) 63% ); background-size: 840px 100%; animation: shimmer 1.4s linear infinite; border-radius: 6px; } @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; } } /* ============================================================================ Form fields (shared) ========================================================================== */ .field { display: block; margin-bottom: 1.125rem; } .field-label { display: block; font-size: 0.8125rem; font-weight: 600; color: var(--ink-soft); margin-bottom: 0.4375rem; } /* Sub-label under an input: the computed figure behind an override field, or why a field is disabled. Quiet enough not to compete with .field-label. */ .field-hint { display: block; font-size: 0.75rem; line-height: 1.35; color: var(--muted-2); margin-top: 0.3125rem; } .input { width: 100%; font-family: inherit; font-size: 0.9375rem; color: var(--ink); background: var(--surface); border: 1px solid var(--line-strong); border-radius: var(--radius-sm); padding: 0.6875rem 0.8125rem; transition: border-color 0.15s, box-shadow 0.15s; } .input::placeholder { color: var(--muted-2); } .input:disabled, .select:disabled { background: var(--surface-2, var(--surface)); color: var(--muted-2); cursor: not-allowed; } .input:focus { outline: none; border-color: var(--brand-600); box-shadow: 0 0 0 3px var(--brand-tint); } /* ============================================================================ Login screen — split brand / form layout ========================================================================== */ .login-wrap { min-height: 100vh; display: grid; grid-template-columns: 1.05fr 1fr; } @media (max-width: 860px) { .login-wrap { grid-template-columns: 1fr; } } .login-aside { position: relative; background: linear-gradient(155deg, var(--brand-900) 0%, var(--brand-700) 62%, #17544a 100%); color: #f2efe7; padding: 2.75rem 3.25rem; display: flex; flex-direction: column; justify-content: space-between; overflow: hidden; } .login-aside::after { /* faint concentric coastal arcs */ content: ""; position: absolute; right: -180px; bottom: -180px; width: 560px; height: 560px; border-radius: 50%; border: 1px solid rgba(255, 255, 255, 0.08); box-shadow: 0 0 0 60px rgba(255, 255, 255, 0.04), 0 0 0 130px rgba(255, 255, 255, 0.03); pointer-events: none; } @media (max-width: 860px) { .login-aside { padding: 2rem 1.75rem 2.5rem; } .login-aside-mid { margin: 1.875rem 0; } } .login-brand { display: flex; align-items: center; gap: 0.8125rem; position: relative; z-index: 1; } .login-aside-mid { position: relative; z-index: 1; max-width: 460px; } .login-headline { font-family: var(--font-display); color: #fbf8f0; font-size: clamp(30px, 4.6vw, 46px); font-weight: 500; line-height: 1.08; margin: 0.875rem 0 1.25rem; letter-spacing: -0.015em; } .login-headline em { font-style: italic; color: #ecc98d; } .login-lede { font-size: 1rem; line-height: 1.6; color: rgba(242, 239, 231, 0.82); max-width: 420px; } .login-aside-foot { position: relative; z-index: 1; display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; } .login-lob { display: flex; gap: 0.5rem; } .login-foot-note { font-size: 0.78125rem; color: rgba(242, 239, 231, 0.55); } .login-form-panel { display: grid; place-items: center; padding: 2.5rem 1.75rem; background: var(--paper); } .login-form-inner { width: 100%; max-width: 380px; } .login-form-title { font-size: 1.875rem; margin-top: 0.25rem; } .login-error { background: var(--negative-tint); color: var(--negative); border: 1px solid rgba(162, 58, 44, 0.28); border-radius: var(--radius-sm); padding: 0.625rem 0.8125rem; font-size: 0.84375rem; font-weight: 500; margin-bottom: 1.125rem; } .login-submit { width: 100%; padding: 0.75rem 1rem; font-size: 0.9375rem; } /* ============================================================================ Page heading + stats (customer list) ========================================================================== */ .page-head { margin-bottom: 1.625rem; } .page-title { font-size: clamp(28px, 4vw, 38px); font-weight: 500; margin: 0.25rem 0 0; } .stat-strip { display: grid; grid-template-columns: repeat(6, 1fr); gap: 0.0625rem; background: var(--line); border: 1px solid var(--line); border-radius: var(--radius-lg); overflow: hidden; margin-top: 1.375rem; } @media (max-width: 900px) { .stat-strip { grid-template-columns: repeat(3, 1fr); } } @media (max-width: 520px) { .stat-strip { grid-template-columns: repeat(2, 1fr); } } .stat-cell { background: var(--surface); padding: 0.9375rem 1rem 0.875rem; } .stat-cell.accent { background: var(--brand-tint); } .stat-value { font-family: var(--font-display); font-size: 1.5625rem; font-weight: 560; color: var(--ink); font-feature-settings: "tnum" 1; letter-spacing: -0.01em; } .stat-cell.accent .stat-value { color: var(--brand-700); } .stat-label { font-size: 0.71875rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.05em; margin-top: 0.1875rem; font-weight: 600; } /* ============================================================================ Search + filter toolbar ========================================================================== */ .toolbar { display: flex; gap: 0.875rem; align-items: center; flex-wrap: wrap; margin: 1.625rem 0 1.125rem; } .search-box { position: relative; flex: 1 1 320px; } .search-box .search-icon { position: absolute; left: 13px; top: 50%; transform: translateY(-50%); color: var(--muted-2); font-size: 1rem; pointer-events: none; } .search-input { width: 100%; padding-left: 2.375rem; } .seg { display: inline-flex; background: var(--paper-2); border: 1px solid var(--line-strong); border-radius: 999px; padding: 0.1875rem; gap: 0.125rem; } .seg-btn { border: none; background: transparent; color: var(--muted); font-size: 0.8125rem; font-weight: 600; padding: 0.4375rem 0.9375rem; border-radius: 999px; transition: color 0.15s, background 0.15s; white-space: nowrap; } .seg-btn:hover { color: var(--ink); } .seg-btn.active { background: var(--surface); color: var(--brand-700); box-shadow: var(--shadow-sm); } @media (max-width: 560px) { .seg { width: 100%; justify-content: space-between; } .seg-btn { flex: 1; padding: 0.5rem 0.375rem; } } .result-meta { font-size: 0.8125rem; color: var(--muted); margin-bottom: 0.75rem; } /* ============================================================================ Customer list (rows) ========================================================================== */ .cust-list { display: flex; flex-direction: column; gap: 0.625rem; } .cust-row { display: grid; grid-template-columns: 1fr auto; gap: 1rem; align-items: center; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 0.9375rem 1.125rem; text-decoration: none; color: inherit; transition: transform 0.14s var(--ease-out-quart), box-shadow 0.14s, border-color 0.14s; } .cust-row:hover { text-decoration: none; transform: translateY(-1px); box-shadow: var(--shadow); border-color: var(--line-strong); } .cust-main { min-width: 0; } .cust-name { font-family: var(--font-display); font-size: 1.0625rem; font-weight: 560; color: var(--ink); letter-spacing: -0.01em; display: flex; align-items: center; gap: 0.625rem; } .cust-name .inactive-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--muted-2); flex: none; } /* Legacy record with no name anywhere in the source — reads as absent data, not as a customer actually called "(SIN NOMBRE)". */ .cust-name-missing { color: var(--muted-2); font-style: italic; font-weight: 400; } /* Name reconstructed from a secondary legacy table, so staff can tell it apart from a name that was really on the customer record. */ .name-source { font-family: var(--font-sans); font-size: 0.625rem; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted-2); border: 1px solid var(--line-strong); border-radius: 4px; padding: 0.125rem 0.375rem; white-space: nowrap; cursor: help; } .cust-sub { display: flex; flex-wrap: wrap; gap: 0.375rem 1rem; margin-top: 0.3125rem; font-size: 0.8125rem; color: var(--muted); } .cust-sub .sep { color: var(--line-strong); } .cust-side { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; justify-content: flex-end; } @media (max-width: 620px) { .cust-row { grid-template-columns: 1fr; } .cust-side { justify-content: flex-start; } } /* ============================================================================ Pagination ========================================================================== */ .pager { display: flex; align-items: center; justify-content: center; gap: 0.75rem; margin-top: 1.625rem; } .pager-info { font-size: 0.8125rem; color: var(--muted); min-width: 130px; text-align: center; } /* ============================================================================ Empty / error / loading states ========================================================================== */ .state-box { text-align: center; padding: 3.75rem 1.5rem; color: var(--muted); } .state-box h3 { color: var(--ink-soft); font-size: 1.25rem; margin-bottom: 0.375rem; } .state-glyph { font-size: 2.125rem; opacity: 0.5; margin-bottom: 0.625rem; } .state-error { background: var(--negative-tint); border: 1px solid rgba(162, 58, 44, 0.25); color: var(--negative); border-radius: var(--radius); padding: 1rem 1.125rem; font-size: 0.875rem; } .skel-row { height: 74px; border-radius: var(--radius); } /* ============================================================================ Customer detail — hero ========================================================================== */ .back-link { display: inline-flex; align-items: center; gap: 0.375rem; font-size: 0.84375rem; font-weight: 600; color: var(--muted); margin-bottom: 1.125rem; } .back-link:hover { color: var(--brand-700); text-decoration: none; } .detail-hero { background: linear-gradient(150deg, var(--brand-900), var(--brand-700) 88%); color: #f2efe7; border-radius: var(--radius-lg); padding: 1.625rem 1.75rem; position: relative; overflow: hidden; box-shadow: var(--shadow); } .detail-hero::after { content: ""; position: absolute; right: -120px; top: -140px; width: 340px; height: 340px; border-radius: 50%; border: 1px solid rgba(255, 255, 255, 0.08); box-shadow: 0 0 0 44px rgba(255, 255, 255, 0.04); pointer-events: none; } .hero-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 1.125rem; flex-wrap: wrap; position: relative; z-index: 1; } .hero-name { font-family: var(--font-display); font-weight: 500; color: #fbf8f0; font-size: clamp(24px, 3.4vw, 34px); letter-spacing: -0.015em; line-height: 1.1; } .hero-name-missing { font-style: italic; color: rgba(251, 248, 240, 0.55); } .hero-provenance { font-size: 0.78125rem; color: rgba(242, 239, 231, 0.62); margin-top: 0.5rem; font-family: var(--font-mono); } .hero-badges { display: flex; gap: 0.5rem; flex-wrap: wrap; align-items: center; } .badge-on-dark { background: rgba(255, 255, 255, 0.12); color: #f2efe7; border-color: rgba(255, 255, 255, 0.2); } .hero-facts { position: relative; z-index: 1; display: flex; flex-wrap: wrap; gap: 1.625rem; margin-top: 1.375rem; padding-top: 1.125rem; border-top: 1px solid rgba(255, 255, 255, 0.12); } .hero-fact-label { font-size: 0.65625rem; text-transform: uppercase; letter-spacing: 0.1em; color: rgba(242, 239, 231, 0.55); font-weight: 600; } .hero-fact-value { font-size: 0.9375rem; color: #f6f3ec; margin-top: 0.125rem; font-weight: 500; } /* ============================================================================ Section scaffolding ========================================================================== */ .section { margin-top: 2.125rem; } .section-head { display: flex; align-items: baseline; gap: 0.75rem; margin-bottom: 1rem; } .section-rule { width: 4px; align-self: stretch; border-radius: 3px; min-height: 1.375rem; } .section-rule.servicios { background: var(--servicios); } .section-rule.seguros { background: var(--seguros); } .section-rule.cuenta { background: var(--accent); } .section-rule.datos { background: var(--brand-600); } .section-rule.docs { background: var(--muted-2); } .section-title { font-size: 1.375rem; font-weight: 560; } .section-count { font-size: 0.8125rem; color: var(--muted); font-weight: 600; font-family: var(--font-mono); } /* ---- key/value grid (datos del cliente) ---- */ .kv-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1.125rem 1.5rem; padding: 1.375rem 1.5rem; } .kv-label { font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); font-weight: 600; margin-bottom: 0.1875rem; } .kv-value { font-size: 0.90625rem; color: var(--ink); } .kv-value.mono { font-size: 0.875rem; } .kv-block { grid-column: 1 / -1; border-top: 1px dashed var(--line-strong); padding-top: 1rem; margin-top: -0.125rem; } /* ---- property cards ---- */ .prop-card { padding: 1.25rem 1.375rem; } .prop-card + .prop-card { border-top: 1px solid var(--line); } .prop-addr { font-family: var(--font-display); font-size: 1.0625rem; font-weight: 560; color: var(--ink); } .prop-meta { font-size: 0.8125rem; color: var(--muted); margin-top: 0.1875rem; display: flex; gap: 0.875rem; flex-wrap: wrap; } .svc-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 0.625rem; margin-top: 1rem; } .svc-item { border: 1px solid var(--line); border-left: 3px solid var(--servicios); border-radius: var(--radius-sm); background: var(--surface-2); padding: 0.6875rem 0.8125rem; } .svc-item.inactive { opacity: 0.62; border-left-color: var(--muted-2); } .svc-head { display: flex; align-items: center; gap: 0.5rem; justify-content: space-between; } .svc-kind { font-weight: 700; font-size: 0.84375rem; color: var(--servicios-ink); display: flex; align-items: center; gap: 0.4375rem; } .svc-glyph { font-size: 0.875rem; } .svc-detail { margin-top: 0.4375rem; font-size: 0.75rem; color: var(--muted); display: flex; flex-direction: column; gap: 0.125rem; } .svc-detail .mono { color: var(--ink-soft); } .trust-box { margin-top: 1rem; border: 1px solid var(--fideicomiso-tint); background: linear-gradient(0deg, var(--fideicomiso-tint), transparent 140%); border-left: 3px solid var(--fideicomiso); border-radius: var(--radius-sm); padding: 0.8125rem 0.9375rem; } .trust-title { font-size: 0.78125rem; font-weight: 700; color: var(--fideicomiso-ink); text-transform: uppercase; letter-spacing: 0.04em; margin-bottom: 0.5rem; } .trust-facts { display: flex; flex-wrap: wrap; gap: 0.5rem 1.375rem; font-size: 0.8125rem; } /* ---- policy cards ---- */ .policy-card { padding: 1.25rem 1.375rem; } .policy-card + .policy-card { border-top: 1px solid var(--line); } .policy-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; flex-wrap: wrap; } .policy-num { font-family: var(--font-mono); font-size: 1.125rem; font-weight: 600; color: var(--seguros-ink); letter-spacing: -0.01em; } .policy-type-row { display: flex; align-items: center; gap: 0.5rem; margin-top: 0.3125rem; font-size: 0.8125rem; color: var(--muted); flex-wrap: wrap; } .policy-figures { text-align: right; } .policy-total { font-family: var(--font-display); font-size: 1.375rem; font-weight: 560; color: var(--ink); font-feature-settings: "tnum" 1; } .policy-total-label { font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); } .policy-body { margin-top: 1rem; display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 1rem; } .subpanel { background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 0.75rem 0.875rem; } .subpanel-title { font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.07em; color: var(--muted); font-weight: 700; margin-bottom: 0.5625rem; display: flex; justify-content: space-between; } .pay-row { display: flex; align-items: center; justify-content: space-between; gap: 0.625rem; font-size: 0.8125rem; padding: 0.3125rem 0; border-bottom: 1px dashed var(--line); } .pay-row:last-child { border-bottom: none; } .pay-seq { width: 22px; height: 22px; border-radius: 50%; background: var(--seguros-tint); color: var(--seguros-ink); font-size: 0.6875rem; font-weight: 700; display: grid; place-items: center; flex: none; } .mini-list { font-size: 0.84375rem; color: var(--ink-soft); display: flex; flex-direction: column; gap: 0.3125rem; } .mini-list .mini-sub { font-size: 0.75rem; color: var(--muted); } /* ============================================================================ Estado de cuenta ========================================================================== */ .summary-grid { display: grid; /* Min track holds a 7-figure balance (e.g. TRASPASOS PAYPAL's -$7,028,533.44) in full — auto-fill packs fixed-width tracks, so a single-currency card never widens on its own and the min is what has to fit the number. */ grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 0.75rem; margin-bottom: 1.125rem; } .summary-card { border: 1px solid var(--line); border-radius: var(--radius); padding: 0.9375rem 1rem; background: var(--surface); border-top: 3px solid var(--muted-2); } .summary-card.UTILITY { border-top-color: var(--servicios); } .summary-card.INSURANCE { border-top-color: var(--seguros); } .summary-card.TRUST { border-top-color: var(--fideicomiso); } .summary-domain { display: flex; align-items: center; gap: 0.4375rem; font-size: 0.75rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted); } .summary-total { font-family: var(--font-display); font-size: 1.375rem; font-weight: 560; margin-top: 0.5rem; font-feature-settings: "tnum" 1; color: var(--ink); /* Never truncate a balance — a clipped money figure reads as a wrong number. The track width above is what keeps it inside the card. */ } .summary-count { font-size: 0.75rem; color: var(--muted); margin-top: 0.125rem; } .tx-table { width: 100%; border-collapse: collapse; font-size: 0.84375rem; } .tx-table th { text-align: left; font-size: 0.65625rem; text-transform: uppercase; letter-spacing: 0.07em; color: var(--muted); font-weight: 700; padding: 0 0.75rem 0.625rem; border-bottom: 1px solid var(--line); } .tx-table th.num, .tx-table td.num { text-align: right; } .tx-table td { padding: 0.6875rem 0.75rem; border-bottom: 1px solid var(--line); vertical-align: top; } .tx-table tr:last-child td { border-bottom: none; } .tx-table tr:hover td { background: var(--surface-2); } /* Drill-down rows (the chequera's yearly summary) read as pressable. */ .tx-table tr.selected td { background: var(--surface-2); box-shadow: inset 2px 0 0 var(--brand-600); } .tx-domain-cell { white-space: nowrap; } .tx-dot { display: inline-block; width: 8px; height: 8px; border-radius: 2px; margin-right: 0.4375rem; vertical-align: middle; } .tx-dot.UTILITY { background: var(--servicios); } .tx-dot.INSURANCE { background: var(--seguros); } .tx-dot.TRUST { background: var(--fideicomiso); } .tx-amount { font-family: var(--font-mono); font-weight: 600; font-feature-settings: "tnum" 1; white-space: nowrap; } .tx-amount.neg { color: var(--negative); } .tx-amount.pos { color: var(--positive); } .tx-cur { font-size: 0.6875rem; color: var(--muted); font-weight: 500; } .tx-concept { color: var(--ink-soft); } .tx-ref { font-family: var(--font-mono); font-size: 0.78125rem; color: var(--muted); } .tx-scroll { overflow-x: auto; } /* ---- documents ---- */ .doc-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 0.625rem; padding: 1.25rem 1.375rem; } .doc-item { display: flex; align-items: center; gap: 0.6875rem; border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 0.6875rem 0.8125rem; background: var(--surface-2); } .doc-icon { width: 32px; height: 32px; border-radius: 7px; background: var(--paper-2); display: grid; place-items: center; font-size: 0.9375rem; flex: none; color: var(--brand-700); } .doc-type { font-size: 0.84375rem; font-weight: 600; color: var(--ink); } .doc-key { font-size: 0.6875rem; color: var(--muted-2); font-family: var(--font-mono); word-break: break-all; } .empty-inline { padding: 1.375rem 1.5rem; color: var(--muted); font-size: 0.875rem; font-style: italic; } .section-note { font-size: 0.75rem; color: var(--muted); margin-top: 0.625rem; } /* ============================================================================ Policies — vigencia badges ========================================================================== */ .badge.status-active { background: var(--positive-tint); color: var(--positive); border-color: rgba(47, 109, 60, 0.25); } .badge.status-expiring { background: var(--accent-tint); color: var(--accent-600); border-color: rgba(191, 90, 52, 0.28); } .badge.status-expired { background: var(--negative-tint); color: var(--negative); border-color: rgba(162, 58, 44, 0.25); } .badge.status-undated { background: var(--paper-2); color: var(--muted); border-color: var(--line-strong); } /* ============================================================================ Policies — header strips ========================================================================== */ /* Stat cells double as vigencia filters on /polizas. */ .stat-cell-btn { display: block; width: 100%; text-align: left; border: none; cursor: pointer; font: inherit; transition: background 0.15s; } .stat-cell-btn:hover { background: var(--surface-2); } .stat-cell-btn.accent:hover { background: #d7e6e1; } .stat-cell-btn.selected { box-shadow: inset 0 -3px 0 var(--brand-600); } .premium-strip { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; margin-top: 0.875rem; padding: 0 0.125rem; } .premium-caption { font-size: 0.71875rem; text-transform: uppercase; letter-spacing: 0.05em; font-weight: 600; color: var(--muted); } .premium-chip { display: inline-flex; align-items: baseline; gap: 0.5rem; } .premium-chip strong { font-family: var(--font-mono); font-feature-settings: "tnum" 1; font-size: 0.9375rem; color: var(--brand-700); } .premium-chip-sub { font-size: 0.75rem; color: var(--muted); } /* ============================================================================ Policies — secondary filter row ========================================================================== */ .filter-row { display: flex; gap: 0.875rem; align-items: flex-end; flex-wrap: wrap; margin-bottom: 1.125rem; } .filter-field { display: flex; flex-direction: column; gap: 0.3125rem; flex: 1 1 210px; min-width: 0; } .filter-label { font-size: 0.71875rem; text-transform: uppercase; letter-spacing: 0.05em; font-weight: 600; color: var(--muted); } .select { appearance: none; cursor: pointer; padding-right: 2.125rem; background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%), linear-gradient(135deg, var(--muted) 50%, transparent 50%); background-position: calc(100% - 18px) 55%, calc(100% - 13px) 55%; background-size: 5px 5px, 5px 5px; background-repeat: no-repeat; } .filter-clear { flex: 0 0 auto; height: 40px; } /* ============================================================================ Policies — list rows ========================================================================== */ .pol-row .cust-name { flex-wrap: wrap; gap: 0.5625rem; } .pol-number { font-size: 0.9375rem; font-weight: 600; letter-spacing: -0.01em; } .pol-side { text-align: right; display: flex; flex-direction: column; align-items: flex-end; gap: 0.1875rem; flex: 0 0 auto; } .pol-premium { font-family: var(--font-mono); font-feature-settings: "tnum" 1; font-size: 0.9375rem; font-weight: 600; color: var(--ink); } .pol-dates { font-size: 0.75rem; color: var(--muted); white-space: nowrap; } .pol-phrase { font-size: 0.71875rem; font-weight: 600; } .pol-phrase.expiring { color: var(--accent-600); } .pol-phrase.active { color: var(--positive); } @media (max-width: 620px) { .pol-side { align-items: flex-start; text-align: left; margin-top: 0.5rem; } } /* ============================================================================ Policy detail — owner card, linked properties, vehicles ========================================================================== */ .owner-link { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 1.125rem 1.375rem; color: inherit; text-decoration: none; border-radius: var(--radius-lg); transition: background 0.15s; } .owner-link:hover { background: var(--surface-2); } .owner-name { font-family: var(--font-display); font-size: 1.1875rem; font-weight: 560; margin-bottom: 0.1875rem; } .owner-cta { font-size: 0.8125rem; font-weight: 600; color: var(--brand-600); white-space: nowrap; } .linked-props { border-top: 1px solid var(--line); padding: 1rem 1.375rem 1.125rem; } .linked-prop { font-size: 0.875rem; margin-top: 0.25rem; } .veh-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 0.75rem; padding: 1rem; } .veh-card { background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--radius); padding: 0.8125rem 0.9375rem; } .veh-title { font-weight: 600; font-size: 0.90625rem; margin-bottom: 0.375rem; } .veh-facts { display: flex; flex-direction: column; gap: 0.1875rem; font-size: 0.78125rem; color: var(--muted); } /* Policy number on the customer detail card links through to /polizas/[id]. */ .policy-num-link { color: inherit; text-decoration: none; transition: color 0.15s; } .policy-num-link:hover { color: var(--brand-600); } /* ============================================================================ Utilities — service mix strip (doubles as the service-kind filter) ========================================================================== */ .mix-strip { display: flex; align-items: center; gap: 0.625rem; flex-wrap: wrap; margin-top: 0.875rem; padding: 0 0.125rem; } .mix-chip { display: inline-flex; align-items: center; gap: 0.5rem; padding: 0.375rem 0.6875rem; background: var(--surface-2); border: 1px solid var(--line); border-radius: 999px; cursor: pointer; font: inherit; color: inherit; transition: border-color 0.15s, background 0.15s; } .mix-chip:hover { border-color: var(--brand-600); } .mix-chip.selected { border-color: var(--brand-600); box-shadow: inset 0 0 0 1px var(--brand-600); } .mix-glyph { font-size: 0.8125rem; color: var(--brand-600); } .mix-body { display: inline-flex; align-items: baseline; gap: 0.375rem; } .mix-body strong { font-family: var(--font-mono); font-feature-settings: "tnum" 1; font-size: 0.875rem; color: var(--brand-700); } .mix-label { font-size: 0.78125rem; color: var(--muted); } .mix-inactive { font-size: 0.6875rem; color: var(--muted); border-left: 1px solid var(--line); padding-left: 0.5rem; } /* ============================================================================ Utilities — property list rows ========================================================================== */ .prop-row .cust-name { flex-wrap: wrap; gap: 0.5625rem; } .prop-side { text-align: right; display: flex; flex-direction: column; align-items: flex-end; gap: 0.3125rem; flex: 0 0 auto; } .svc-chips { display: flex; gap: 0.3125rem; flex-wrap: wrap; justify-content: flex-end; } .svc-chip { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; border-radius: 7px; background: var(--surface-2); border: 1px solid var(--line); font-size: 0.75rem; color: var(--brand-600); } .svc-chip.inactive { opacity: 0.45; } @media (max-width: 620px) { .prop-side { align-items: flex-start; text-align: left; margin-top: 0.5rem; } .svc-chips { justify-content: flex-start; } } /* Sibling properties on the property detail are navigable. */ .linked-prop.link { display: block; color: inherit; text-decoration: none; transition: color 0.15s; } .linked-prop.link:hover { color: var(--brand-600); } .inline-link { color: var(--brand-600); text-decoration: none; font-weight: 600; } .inline-link:hover { text-decoration: underline; } /* Visually hidden, still read by screen readers (service kind chips). */ .sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -0.0625rem; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; } /* ================================================================ Estado de cuenta (billing / statements) — plan step 6 ================================================================ */ /* A balance is signed: negative means the customer owes the office, positive means they hold a credit. `flat` is a real state (settled to zero), not a fallback, so it gets its own muted treatment rather than inheriting either. */ .bal-amount { font-family: var(--font-mono); font-weight: 700; font-feature-settings: "tnum" 1; white-space: nowrap; } .bal-amount.owing { color: var(--negative); } .bal-amount.credit { color: var(--positive); } .bal-amount.flat { color: var(--muted); } .bal-running { font-family: var(--font-mono); font-size: 0.78125rem; font-feature-settings: "tnum" 1; white-space: nowrap; color: var(--ink-soft); } .bal-running.owing { color: var(--negative); } .bal-running.credit { color: var(--positive); } .bal-row .bal-side { text-align: right; display: flex; flex-direction: column; gap: 0.125rem; align-items: flex-end; min-width: 160px; } .bal-side .bal-amount { font-size: 1rem; } .bal-phrase { font-size: 0.6875rem; font-weight: 600; letter-spacing: 0.03em; text-transform: uppercase; } .bal-phrase.owing { color: var(--negative); } .bal-phrase.credit { color: var(--positive); } .bal-phrase.flat { color: var(--muted); } /* The customer's other-currency balance, shown so a peso figure is never mistaken for the whole picture. */ .bal-other { font-size: 0.71875rem; color: var(--muted); font-family: var(--font-mono); } @media (max-width: 640px) { .bal-row .bal-side { align-items: flex-start; text-align: left; min-width: 0; } } /* Currency cards on the statement double as the movement-table currency switch, so they are buttons, not divs. */ .bal-card { text-align: left; cursor: pointer; font: inherit; border: 1px solid var(--line); transition: border-color 0.15s ease, transform 0.15s ease; } .bal-card:hover { transform: translateY(-1px); } .bal-card.selected { border-color: var(--brand-600); box-shadow: 0 0 0 1px var(--brand-600); } .bal-breakdown { display: grid; grid-template-columns: auto 1fr; gap: 0.0625rem 0.5rem; margin-top: 0.5rem; font-size: 0.75rem; align-items: baseline; } .bal-breakdown-label { color: var(--muted); font-size: 0.71875rem; } /* Ledger-wide charge/credit totals in the page header. */ .ledger-chip { display: flex; align-items: center; gap: 0.875rem; padding: 0.5rem 0.875rem; border: 1px solid var(--line); border-radius: 10px; background: var(--surface-2); } .ledger-chip-cur { font-weight: 700; font-size: 0.75rem; letter-spacing: 0.06em; color: var(--muted); } .ledger-chip-figs { display: flex; flex-direction: column; line-height: 1.3; } .ledger-chip-label { font-size: 0.6875rem; color: var(--muted); } /* Totals for the current movement filter — deliberately above the table, so a filtered view can't be read as if it were the whole ledger. */ .filtered-totals { display: flex; flex-wrap: wrap; gap: 0.625rem; margin-bottom: 0.75rem; } .filtered-total { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.875rem; padding: 0.5625rem 0.875rem; border: 1px solid var(--line); border-radius: 10px; background: var(--surface-2); font-size: 0.78125rem; color: var(--muted); } .filtered-total-cur { font-weight: 700; letter-spacing: 0.06em; color: var(--ink-soft); } .filtered-total-net strong { font-family: var(--font-mono); color: var(--ink); } /* Captured-but-unpaid (legacy NOPAGO). Deliberately not the same treatment as a voided row: the movement is real and still pending, it just doesn't count toward the balance until a check resolves it. */ .tx-outstanding { color: var(--warn, #b45309); font-weight: 600; } /* Charges broken out by concept, with a proportional bar. `.card` carries no padding, so the list pads itself — otherwise the total sits on the border. */ .concept-list { display: flex; flex-direction: column; padding: 0.25rem 1rem; } .concept-row { display: grid; grid-template-columns: minmax(150px, 1.2fr) minmax(60px, 2fr) auto; gap: 0.875rem; align-items: center; padding: 0.5625rem 0; border-bottom: 1px solid var(--line); } .concept-row:last-child { border-bottom: none; } .concept-name { font-size: 0.84375rem; font-weight: 600; display: flex; flex-direction: column; } .concept-count { font-size: 0.71875rem; font-weight: 500; color: var(--muted); } .concept-bar { height: 7px; background: var(--surface-2); border-radius: 4px; overflow: hidden; } .concept-bar span { display: block; height: 100%; border-radius: 4px; background: var(--negative); opacity: 0.55; } .concept-total { text-align: right; font-size: 0.8125rem; } @media (max-width: 640px) { .concept-row { grid-template-columns: 1fr auto; } .concept-bar { display: none; } } /* Cross-link out of a detail hero (statement -> customer file). */ .hero-links { margin-top: 1rem; display: flex; gap: 0.625rem; flex-wrap: wrap; position: relative; z-index: 1; } /* --- Admin DB operations (Operaciones) --- */ .btn-danger { background: var(--negative); color: #fff; } .btn-danger:hover { filter: brightness(0.94); text-decoration: none; } .btn-danger:disabled { opacity: 0.5; cursor: not-allowed; } .ops-log { margin: 0.75rem 0 0; padding: 0.75rem 0.875rem; max-height: 320px; overflow: auto; background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--radius-sm); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.75rem; line-height: 1.5; white-space: pre-wrap; word-break: break-word; } .modal-backdrop { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.4); display: grid; place-items: center; padding: 1.25rem; z-index: 50; } /* ============================================================================ Home dashboard (/inicio) ========================================================================== */ .home { display: flex; flex-direction: column; gap: 2.25rem; padding-top: 0.5rem; } .home-last-seen { margin-top: 0.875rem; font-size: 0.8125rem; } .home-section { display: flex; flex-direction: column; gap: 0.875rem; } .section-head { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; flex-wrap: wrap; } .section-title { font-family: var(--font-display); font-size: 1.25rem; font-weight: 560; margin: 0; color: var(--ink); letter-spacing: -0.005em; } .section-sub { font-size: 0.78125rem; color: var(--muted); } /* KPI cards row — 4 across on wide screens, 2 on tablet, 1 on mobile */ .home-section.kpi-row { display: grid; } .home > .home-section:first-of-type { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.875rem; } @media (max-width: 1080px) { .home > .home-section:first-of-type { grid-template-columns: repeat(2, 1fr); } } @media (max-width: 560px) { .home > .home-section:first-of-type { grid-template-columns: 1fr; } } .kpi-card { display: flex; flex-direction: column; padding: 1.125rem 1.125rem 1rem; text-decoration: none; color: inherit; transition: transform 0.18s var(--ease-out-expo), box-shadow 0.18s; position: relative; } .kpi-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); } .kpi-label { font-size: 0.71875rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); font-weight: 700; } .kpi-primary { font-family: var(--font-display); font-size: 2rem; font-weight: 560; color: var(--ink); margin-top: 0.5rem; font-feature-settings: "tnum" 1; letter-spacing: -0.015em; line-height: 1.1; min-height: 2.25rem; } .kpi-sub { list-style: none; padding: 0; margin: 0.75rem 0 0; display: flex; flex-direction: column; gap: 0.25rem; font-size: 0.78125rem; color: var(--ink-soft); } .kpi-sub li { line-height: 1.35; } .kpi-cta { margin-top: 0.875rem; font-size: 0.75rem; font-weight: 700; color: var(--brand-700); letter-spacing: 0.02em; text-transform: uppercase; } .kpi-card:hover .kpi-cta { color: var(--brand-800); } /* Attention grid — auto-fill so the row of cards stays balanced */ .attention-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 0.875rem; } .attention-card { display: flex; flex-direction: column; gap: 0.375rem; padding: 1rem 1.125rem 1.125rem; text-decoration: none; color: inherit; border-left: 3px solid var(--line-strong); transition: transform 0.18s var(--ease-out-expo), box-shadow 0.18s; position: relative; } .attention-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); } .attention-card.tone-warn { border-left-color: var(--seguros); } .attention-card.tone-info { border-left-color: var(--brand-600); } .attention-card.tone-muted { border-left-color: var(--muted-2); } .attention-head { display: flex; align-items: center; justify-content: space-between; gap: 0.625rem; } .attention-title { font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); font-weight: 700; } .attention-arrow { color: var(--muted-2); font-size: 0.875rem; transition: transform 0.18s var(--ease-out-expo), color 0.18s; } .attention-card:hover .attention-arrow { color: var(--brand-700); transform: translateX(3px); } .attention-primary { font-family: var(--font-display); font-size: 1.625rem; font-weight: 560; color: var(--ink); font-feature-settings: "tnum" 1; letter-spacing: -0.01em; line-height: 1.1; min-height: 1.875rem; margin-top: 0.125rem; } .attention-sub { font-size: 0.78125rem; color: var(--ink-soft); line-height: 1.4; } .attention-meta { font-size: 0.71875rem; color: var(--muted); margin-top: 0.25rem; } /* Currency totals inside an attention card */ .home-currency-totals { display: inline-flex; flex-wrap: wrap; gap: 0.5rem 0.875rem; align-items: baseline; } .home-currency-totals-row { display: inline-flex; align-items: baseline; gap: 0.375rem; } .home-currency-totals-num { font-family: var(--font-display); font-feature-settings: "tnum" 1; font-size: 1.25rem; font-weight: 560; } /* Quick links row */ .quick-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 0.75rem; } .quick-link { display: flex; flex-direction: column; padding: 0.875rem 1rem; text-decoration: none; color: inherit; position: relative; transition: transform 0.18s var(--ease-out-expo), box-shadow 0.18s; } .quick-link:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); } .quick-label { font-family: var(--font-display); font-size: 1.0625rem; font-weight: 560; color: var(--ink); } .quick-sub { font-size: 0.75rem; color: var(--muted); margin-top: 0.125rem; } .quick-arrow { position: absolute; top: 14px; right: 16px; color: var(--muted-2); font-size: 0.875rem; transition: transform 0.18s var(--ease-out-expo), color 0.18s; } .quick-link:hover .quick-arrow { color: var(--brand-700); transform: translateX(3px); } /* Money tone helpers (used in chequera card) */ .money-pos { color: var(--positive); } .money-neg { color: var(--negative); } /* ============================================================================ Reports module ========================================================================== */ .report-catalog { display: flex; flex-direction: column; gap: 1.75rem; margin-top: 1.25rem; } .report-catalog-group { display: flex; flex-direction: column; gap: 0.625rem; } .report-catalog-title { font-family: var(--font-display); font-weight: 500; font-size: 1.25rem; color: var(--brand-800); margin: 0; padding-bottom: 0.375rem; border-bottom: 1px solid var(--line); } .report-catalog-list { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 0.75rem; } .report-catalog-item { margin: 0; } .report-catalog-link { display: flex; flex-direction: column; gap: 0.375rem; padding: 0.875rem 1rem; background: var(--surface); border: 1px solid var(--line); border-radius: 8px; color: inherit; text-decoration: none; transition: border-color 0.18s, transform 0.18s var(--ease-out-expo); } .report-catalog-link:hover { border-color: var(--brand-500); transform: translateY(-1px); } .report-catalog-item-title { font-weight: 600; font-size: 0.9375rem; color: var(--ink); } .report-catalog-item-desc { font-size: 0.8125rem; color: var(--muted); line-height: 1.4; } .report-catalog-item-meta { display: flex; flex-wrap: wrap; gap: 0.375rem; margin-top: 0.25rem; } .report-catalog-tag { font-size: 0.6875rem; background: var(--brand-tint); color: var(--brand-800); padding: 0.125rem 0.5rem; border-radius: 999px; font-family: var(--font-mono); } .report-catalog-tag.muted { background: var(--paper-2); color: var(--muted); } /* Runner */ .report-runner { display: flex; flex-direction: column; gap: 1rem; margin-top: 1.25rem; } .report-filters { display: flex; flex-wrap: wrap; gap: 0.75rem; align-items: flex-end; background: var(--surface); border: 1px solid var(--line); border-radius: 8px; padding: 0.875rem 1rem; } .report-filters-actions { display: flex; align-items: center; gap: 0.5rem; margin-left: auto; } .report-error { background: #fbeae3; color: var(--negative); border: 1px solid #e6b6a4; border-radius: 6px; padding: 0.625rem 0.875rem; font-size: 0.8125rem; } .report-loading { font-size: 0.75rem; color: var(--muted); padding: 0.25rem 0; } .report-result { display: flex; flex-direction: column; gap: 0.75rem; } .report-result-head { display: flex; align-items: flex-end; gap: 1rem; flex-wrap: wrap; } .report-result-meta { flex: 1; min-width: 200px; } .report-output-buttons { display: flex; flex-wrap: wrap; gap: 0.375rem; } .btn-sm { padding: 0.25rem 0.625rem; font-size: 0.75rem; } .report-table-wrap { overflow-x: auto; background: var(--surface); border: 1px solid var(--line); border-radius: 8px; } .report-table { width: 100%; border-collapse: collapse; font-size: 0.8125rem; } .report-table th, .report-table td { padding: 0.5rem 0.75rem; border-bottom: 1px solid var(--line); } .report-table th { background: var(--paper-2); color: var(--ink-soft); font-weight: 600; text-align: left; position: sticky; top: 0; z-index: 1; } .report-table tbody tr:hover { background: var(--paper-2); } .report-totals { background: var(--accent); color: #f5f1e8; font-weight: 600; padding: 0.625rem 0.875rem; } .statement { display: flex; flex-direction: column; gap: 1.25rem; } .statement-head { background: var(--surface); border: 1px solid var(--line); border-radius: 8px; padding: 1rem 1.125rem; } .statement-name { font-family: var(--font-display); font-size: 1.375rem; font-weight: 600; color: var(--ink); margin: 0 0 0.25rem; } .statement-section-title { font-family: var(--font-display); font-size: 1rem; font-weight: 500; color: var(--brand-800); margin: 0 0 0.5rem; } /* Renewal notices (aviso-renovacion) — one card per policy due, see docs/RENEWAL_NOTICES.md for the legacy report this replaces. */ .renewal-letters { display: flex; flex-direction: column; gap: 1.25rem; } .renewal-letter { background: var(--surface); border: 1px solid var(--line); border-radius: 8px; padding: 1.125rem 1.25rem; break-inside: avoid; } .renewal-letter-head { display: flex; justify-content: space-between; align-items: flex-start; border-bottom: 1px solid var(--line); padding-bottom: 0.625rem; margin-bottom: 0.75rem; } .renewal-letter-title { font-family: var(--font-display); font-size: 1.125rem; font-weight: 600; color: var(--ink); margin: 0; } .renewal-letter-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.75rem; margin-bottom: 0.75rem; } .renewal-letter-vehicle { background: var(--paper-2); border-radius: 6px; padding: 0.625rem 0.75rem; margin-bottom: 0.75rem; } .renewal-letter-coverage { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 0.75rem; margin-bottom: 0.75rem; } .renewal-letter-coverage-item { border-left: 2px solid var(--line-strong); padding-left: 0.625rem; } .renewal-letter-value { font-size: 0.875rem; font-weight: 600; color: var(--ink); margin: 0.125rem 0 0; } .renewal-letter-premium { display: flex; gap: 1.25rem; font-size: 0.875rem; border-top: 1px solid var(--line); padding-top: 0.625rem; } .renewal-letter-total { font-weight: 700; color: var(--brand-800); } @media print { .renewal-letter { page-break-inside: avoid; page-break-after: always; } .renewal-letter:last-child { page-break-after: auto; } } /* Context buttons (the inline shortcut on existing pages) */ .context-reports { display: flex; flex-wrap: wrap; gap: 0.375rem; align-items: center; margin-left: auto; } .context-reports-label { font-size: 0.6875rem; color: var(--muted-2); text-transform: uppercase; letter-spacing: 0.06em; margin-right: 0.25rem; font-weight: 500; } .context-report-link { font-size: 0.75rem; padding: 0.25rem 0.625rem; border: 1px solid var(--line); background: var(--surface); color: var(--ink); border-radius: 999px; text-decoration: none; transition: border-color 0.15s, color 0.15s; } .context-report-link:hover { border-color: var(--brand-500); color: var(--brand-700); } /* ============================================================================ Layout + text utilities the screens already assumed Several components were written against these names before any rule defined them, so they rendered as bare inline spans. The visible symptom was the policy OCR review header running together — "Para revisarPágina 1700489616· PAMELA DENISE WAGONERLICENCIASANA" — because JSX drops the newline between sibling elements and the `gap` those call sites pass does nothing without a flex container. ========================================================================== */ .row { display: flex; align-items: center; flex-wrap: wrap; gap: 0.5rem; } .stack { display: flex; flex-direction: column; gap: 1rem; } /* The muted line under a page title, and the same voice reused inline. Only the block form takes a margin — as a flex child it would shift the item off the row's centre line. */ .page-sub { color: var(--muted); font-size: 0.875rem; } p.page-sub { margin: 0.25rem 0 0; } /* A neutral chip. Same shape as `.badge` so the OCR statuses, policy type and carrier read as the labels they are rather than as running prose. */ .tag { display: inline-flex; align-items: center; gap: 0.375rem; padding: 0.1875rem 0.5625rem; border-radius: 999px; font-size: 0.75rem; font-weight: 600; letter-spacing: 0.01em; line-height: 1.4; white-space: nowrap; background: var(--paper-2); color: var(--muted); border: 1px solid var(--line-strong); } /* The warning sibling of `.state-error`, used where a page needs a human to choose between candidates rather than reporting a failure. */ .state-warn { background: var(--servicios-tint); border: 1px solid rgba(154, 106, 18, 0.25); color: var(--servicios-ink); border-radius: var(--radius); padding: 1rem 1.125rem; font-size: 0.875rem; }