Files
labre-web/.impeccable/design.json
T
LakG 57b07b9b82 Rediseño impeccable: brand mark, páginas 403/404, DESIGN.md + PRODUCT.md
Rediseño hecho en sesión aparte con el skill impeccable. Se registran
las especificaciones y ajustes visuales al sistema ya en producción.

Añade:
- BrandMark.astro con el escudo/logo del laboratorio.
- Favicon actualizado (svg + ico).
- Páginas propias 403 y 404 consistentes con el sistema visual.
- DESIGN.md y PRODUCT.md documentando decisiones.
- .impeccable/design.json con el design system tokenizado.

Ajusta componentes existentes (modales, autocomplete, layout, login,
solicitudes, mis-préstamos, middleware) para alinearse a los tokens
del design system.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-08-16 15:19:57 -07:00

204 lines
17 KiB
JSON
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.
{
"schemaVersion": 2,
"generatedAt": "2026-08-16T00:00:00Z",
"title": "Design System: LabPréstamos",
"extensions": {
"colorMeta": {
"verde-institucional": {
"role": "primary",
"displayName": "Verde Institucional",
"canonical": "oklch(48.5% 0.12 154.8)",
"tonalRamp": [
"oklch(15% 0.12 154.8)",
"oklch(28% 0.12 154.8)",
"oklch(40% 0.12 154.8)",
"oklch(52% 0.12 154.8)",
"oklch(65% 0.12 154.8)",
"oklch(76% 0.12 154.8)",
"oklch(86% 0.12 154.8)",
"oklch(95% 0.12 154.8)"
]
},
"dorado-uabc": {
"role": "secondary",
"displayName": "Dorado UABC",
"canonical": "oklch(72.8% 0.148 74.4)",
"tonalRamp": [
"oklch(15% 0.148 74.4)",
"oklch(28% 0.148 74.4)",
"oklch(40% 0.148 74.4)",
"oklch(52% 0.148 74.4)",
"oklch(65% 0.148 74.4)",
"oklch(76% 0.148 74.4)",
"oklch(86% 0.148 74.4)",
"oklch(95% 0.148 74.4)"
]
},
"superficie": {
"role": "neutral",
"displayName": "Superficie",
"canonical": "oklch(97.3% 0.004 157.2)",
"tonalRamp": [
"oklch(15% 0.004 157.2)",
"oklch(28% 0.004 157.2)",
"oklch(40% 0.004 157.2)",
"oklch(52% 0.004 157.2)",
"oklch(65% 0.004 157.2)",
"oklch(76% 0.004 157.2)",
"oklch(86% 0.004 157.2)",
"oklch(95% 0.004 157.2)"
]
},
"tinta": {
"role": "neutral",
"displayName": "Tinta",
"canonical": "oklch(33.5% 0.033 260.9)",
"tonalRamp": [
"oklch(15% 0.033 260.9)",
"oklch(28% 0.033 260.9)",
"oklch(40% 0.033 260.9)",
"oklch(52% 0.033 260.9)",
"oklch(65% 0.033 260.9)",
"oklch(76% 0.033 260.9)",
"oklch(86% 0.033 260.9)",
"oklch(95% 0.033 260.9)"
]
},
"peligro": {
"role": "danger",
"displayName": "Peligro",
"canonical": "oklch(54.4% 0.186 26)",
"tonalRamp": [
"oklch(15% 0.186 26)",
"oklch(28% 0.186 26)",
"oklch(40% 0.186 26)",
"oklch(52% 0.186 26)",
"oklch(65% 0.186 26)",
"oklch(76% 0.186 26)",
"oklch(86% 0.186 26)",
"oklch(95% 0.186 26)"
]
}
},
"typographyMeta": {
"headline": { "displayName": "Headline", "purpose": "Page-level h1 — dashboard/section titles, login title." },
"title": { "displayName": "Title", "purpose": "Card and section headers within a page." },
"body": { "displayName": "Body", "purpose": "Default text size across the whole system: table cells, descriptions, list content." },
"label": { "displayName": "Label", "purpose": "Form field labels, always paired with htmlFor/id." },
"caption": { "displayName": "Caption", "purpose": "Metadata: matrícula, inventory numbers, timestamps, field hints." }
},
"shadows": [
{ "name": "floating-chrome", "value": "0 10px 30px -8px rgba(0,0,0,0.25)", "purpose": "Mobile dock nav — soft ambient shadow signaling it floats above the scrolling page." },
{ "name": "overlay-notification", "value": "0 16px 40px -12px rgba(0,0,0,0.25)", "purpose": "Toast stack — same ambient quality, slightly heavier, paired with backdrop-blur-xl." }
],
"motion": [
{ "name": "toast-entrance", "value": "cubic-bezier(0.22, 1, 0.36, 1)", "purpose": "260ms translate+scale+fade entrance for toast notifications." },
{ "name": "chrome-transition", "value": "cubic-bezier(0, 0, 0.2, 1)", "purpose": "150-200ms default ease-out for sidebar collapse, hover states, dock icon transitions." }
],
"breakpoints": [
{ "name": "md", "value": "768px" }
]
},
"components": [
{
"name": "Primary Button",
"kind": "button",
"refersTo": "button-primary",
"description": "Default call to action: submit, approve, continue with Google.",
"html": "<button class=\"ds-btn ds-btn-primary\">Enviar solicitud</button>",
"css": ".ds-btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; min-height: 44px; padding: 10px 16px; border-radius: 8px; font-weight: 500; font-size: 0.875rem; border: none; cursor: pointer; touch-action: manipulation; transition: filter 150ms ease-out, background-color 150ms ease-out; } .ds-btn-primary { background: #00723F; color: #ffffff; } .ds-btn-primary:hover { filter: brightness(1.1); } .ds-btn-primary:focus-visible { outline: 2px solid #00723F; outline-offset: 2px; } .ds-btn-primary:disabled { opacity: 0.5; pointer-events: none; }"
},
{
"name": "Secondary Button",
"kind": "button",
"refersTo": "button-secondary",
"description": "Sparingly used accent action — filtering, non-primary confirms.",
"html": "<button class=\"ds-btn ds-btn-secondary\">Filtrar</button>",
"css": ".ds-btn-secondary { display: inline-flex; align-items: center; justify-content: center; gap: 8px; min-height: 44px; padding: 10px 16px; border-radius: 8px; font-weight: 500; font-size: 0.875rem; border: none; cursor: pointer; touch-action: manipulation; background: #DD971A; color: #ffffff; transition: filter 150ms ease-out; } .ds-btn-secondary:hover { filter: brightness(1.1); } .ds-btn-secondary:focus-visible { outline: 2px solid #00723F; outline-offset: 2px; }"
},
{
"name": "Ghost Button",
"kind": "button",
"refersTo": "button-ghost",
"description": "Low-commitment counterpart to Primary — cancel, clear filters.",
"html": "<button class=\"ds-btn ds-btn-ghost\">Cancelar</button>",
"css": ".ds-btn-ghost { display: inline-flex; align-items: center; justify-content: center; gap: 8px; min-height: 44px; padding: 10px 16px; border-radius: 8px; font-weight: 500; font-size: 0.875rem; cursor: pointer; touch-action: manipulation; background: transparent; color: #2D3748; border: 1px solid color-mix(in oklab, #2D3748 15%, transparent); transition: background-color 150ms ease-out; } .ds-btn-ghost:hover { background: color-mix(in oklab, #2D3748 5%, transparent); } .ds-btn-ghost:focus-visible { outline: 2px solid #00723F; outline-offset: 2px; }"
},
{
"name": "Status Pill",
"kind": "chip",
"refersTo": "badge",
"description": "Tinted-fill status indicator used for every préstamo/material estado; solid-fill only for the confirmed Vencido exception.",
"html": "<span class=\"ds-pill ds-pill-primary\">Disponible</span> <span class=\"ds-pill ds-pill-secondary\">Mantenimiento</span> <span class=\"ds-pill ds-pill-danger-solid\">Vencido</span>",
"css": ".ds-pill { display: inline-flex; align-items: center; border-radius: 9999px; padding: 2px 10px; font-size: 0.75rem; font-weight: 600; white-space: nowrap; } .ds-pill-primary { background: color-mix(in oklab, #00723F 13%, transparent); color: #00723F; } .ds-pill-secondary { background: color-mix(in oklab, #DD971A 15%, transparent); color: #c78614; } .ds-pill-danger-solid { background: #C53030; color: #ffffff; }"
},
{
"name": "Card",
"kind": "card",
"refersTo": "card",
"description": "Flat white container — the system's default surface for content, forms, and KPI tiles. No shadow, hairline ink-mix border only.",
"html": "<div class=\"ds-card\"><h3 class=\"ds-card-title\">Inicia sesión</h3><p class=\"ds-card-body\">Accede con tu cuenta institucional.</p></div>",
"css": ".ds-card { background: #ffffff; border-radius: 8px; padding: 24px; border: 1px solid color-mix(in oklab, #2D3748 10%, transparent); } .ds-card-title { font-size: 1.125rem; font-weight: 600; margin: 0 0 4px; color: #2D3748; } .ds-card-body { font-size: 0.875rem; opacity: 0.7; margin: 0; color: #2D3748; }"
},
{
"name": "Input Field",
"kind": "input",
"refersTo": "input",
"description": "Labeled text field with hairline border and single-color focus outline (no glow, no border-color shift).",
"html": "<div class=\"ds-field\"><label class=\"ds-label\" for=\"demo-input\">Cantidad</label><input id=\"demo-input\" class=\"ds-input\" type=\"number\" value=\"1\" /></div>",
"css": ".ds-label { display: block; font-size: 0.875rem; font-weight: 500; margin-bottom: 4px; color: color-mix(in oklab, #2D3748 90%, transparent); } .ds-input { width: 100%; min-height: 44px; border-radius: 8px; padding: 10px 12px; background: #ffffff; border: 1px solid color-mix(in oklab, #2D3748 20%, transparent); font-size: 0.875rem; touch-action: manipulation; transition: border-color 150ms, box-shadow 150ms; } .ds-input:focus-visible { outline: 2px solid #00723F; outline-offset: 2px; }"
},
{
"name": "Mobile Dock Nav Item",
"kind": "nav",
"refersTo": "nav-dock-item",
"description": "Signature component: icon-only floating pill navigation for the alumno/admin mobile layout, replacing a conventional bottom tab bar.",
"html": "<nav class=\"ds-dock\"><a href=\"#\" class=\"ds-dock-item ds-dock-item-active\" aria-label=\"Inicio\"><svg width=\"22\" height=\"22\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M2.25 12l8.954-8.955a1.5 1.5 0 012.122 0L22.28 12M4.5 9.75v10.125A1.125 1.125 0 005.625 21H9.75v-6h4.5v6h4.125A1.125 1.125 0 0019.5 19.875V9.75\"/></svg></a><a href=\"#\" class=\"ds-dock-item\" aria-label=\"Catálogo\"><svg width=\"22\" height=\"22\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M3.75 6A2.25 2.25 0 016 3.75h2.25A2.25 2.25 0 0110.5 6v2.25a2.25 2.25 0 01-2.25 2.25H6A2.25 2.25 0 013.75 8.25V6z\"/></svg></a></nav>",
"css": ".ds-dock { display: inline-flex; align-items: center; gap: 4px; border-radius: 9999px; padding: 8px; backdrop-filter: blur(8px); background: rgba(255,255,255,0.95); box-shadow: 0 10px 30px -8px rgba(0,0,0,0.25); border: 1px solid color-mix(in oklab, #2D3748 10%, transparent); } .ds-dock-item { display: grid; place-items: center; width: 44px; height: 44px; border-radius: 9999px; color: color-mix(in oklab, #2D3748 70%, transparent); transition: background-color 150ms, color 150ms, transform 150ms; text-decoration: none; } .ds-dock-item:hover { background: color-mix(in oklab, #2D3748 5%, transparent); color: #2D3748; } .ds-dock-item:active { transform: scale(0.95); } .ds-dock-item-active { background: #00723F; color: #ffffff; }"
},
{
"name": "Toast",
"kind": "custom",
"refersTo": "toast",
"description": "Signature component: floating top-center notification with a colored circular icon chip, survives page reload via a sessionStorage queue.",
"html": "<div class=\"ds-toast\"><span class=\"ds-toast-icon\"><svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M4.5 12.75l6 6 9-13.5\"/></svg></span><span class=\"ds-toast-text\"><span class=\"ds-toast-title\">Solicitud enviada</span><span class=\"ds-toast-desc\">Multímetro digital · pendiente de aprobación</span></span></div>",
"css": ".ds-toast { display: flex; align-items: flex-start; gap: 12px; border-radius: 16px; padding: 12px 16px; background: rgba(255,255,255,0.85); backdrop-filter: blur(20px); box-shadow: 0 16px 40px -12px rgba(0,0,0,0.25); border: 1px solid color-mix(in oklab, #2D3748 10%, transparent); color: #2D3748; max-width: 26rem; } .ds-toast-icon { flex-shrink: 0; display: grid; place-items: center; width: 36px; height: 36px; border-radius: 9999px; background: #00723F; color: #ffffff; } .ds-toast-title { display: block; font-weight: 600; font-size: 0.875rem; } .ds-toast-desc { display: block; font-size: 0.75rem; opacity: 0.7; margin-top: 2px; }"
}
],
"narrative": {
"northStar": "La Bitácora Digital",
"overview": "LabPréstamos is the printed loan sheet and the Excel logbook it used to feed, collapsed into one live surface. Every visual decision defends that lineage: nothing decorative, nothing that would feel out of place next to an official UABC form, but nothing that feels like a cold spreadsheet either. The system is cálido pero confiable — warm but reliable — and it earns the \"warm\" half narrowly: a gold accent, soft rounded corners, and gentle motion sit on top of an otherwise flat, administrative base.\n\nThe page itself stays flat and quiet — white cards on a pale green-grey surface, hairline borders instead of shadows, tabular numbers lined up like a real ledger. Depth is reserved for the two things that are genuinely floating above the page: the toast notifications and the mobile navigation dock. That asymmetry is deliberate — it is how the system tells the eye \"this is the document\" from \"this is the chrome.\"\n\nTwo audiences read this bitácora differently. The alumno's default device is the phone — the catalog, the request modal, the pill-shaped floating dock are all tuned for thumbs. The admin's default device is the desktop — dense tables, a persistent sidebar, KPI tiles. Neither view degrades on the other's device; every screen ships both a table and a card-list rendering.",
"keyCharacteristics": [
"Flat administrative base (white cards, hairline ink-tinted borders, no ambient shadow)",
"Shadow appears only on floating overlay chrome — the mobile dock and toasts — never on the page plane",
"Every status is a tinted pill: 1215% color wash background, full-strength text",
"Tabular numbers everywhere a quantity, date, or stock figure appears",
"One typeface (Inter Variable) carrying every role through weight and size alone",
"Motion is a courtesy, not a performance: motion-safe:-gated, specific-property transitions, no transition-all"
],
"rules": [
{ "name": "The Ink-Mix Border Rule", "body": "Every hairline border and divider is color-mix(in oklab, var(--color-tinta) N%, transparent), never a literal gray hex. A border is always \"ink, diluted,\" so it stays coherent with body text at any opacity.", "section": "colors" },
{ "name": "The Vencido Exception", "body": "Every status pill uses the tinted-fill pattern except an overdue loan (\"Vencido\"), which gets a solid peligro fill with white text — on both the table badge and, on mobile, a light danger wash across the entire card background. This is the system's one permitted alarm.", "section": "colors" },
{ "name": "The Tabular Numbers Rule", "body": "Any figure that represents a count — cantidad, stock (disponible/total), KPI values, dates — is rendered with font-variant-numeric: tabular-nums. Numbers must align like a ledger column.", "section": "typography" },
{ "name": "The Table/Card Swap Rule", "body": "Every data-dense admin view ships two complete renderings of the same data: a table for md:block and a card list for md:hidden. This is a structural swap, not a responsive squeeze.", "section": "layout" },
{ "name": "The Flat Page, Floating Chrome Rule", "body": "If an element is part of the document (a card, a table, a form), it stays flat with a hairline border. If an element floats above the document regardless of scroll (the dock, a toast), it gets a soft ambient shadow plus backdrop-blur.", "section": "elevation" }
],
"dos": [
"Do use color-mix(in oklab, var(--color-tinta) N%, transparent) for any new border or divider — never a literal gray.",
"Do keep shadow exclusive to floating overlay chrome (toasts, the mobile dock).",
"Do use the tinted-pill pattern (1215% background, full-strength text) for any new status or state indicator.",
"Do apply font-variant-numeric: tabular-nums to any new numeric quantity, stock figure, or date.",
"Do ship both a md:block table and a md:hidden card-list rendering for any new data-dense admin view.",
"Do gate all motion with motion-safe: and animate specific properties, never transition-all.",
"Do give every interactive control a 44px minimum tap target and touch-action: manipulation."
],
"donts": [
"Don't add a shadow to .card, .btn, or .input — the system's flatness on the page plane is deliberate.",
"Don't introduce a second typeface. Inter Variable carries every role through weight and size.",
"Don't give a status pill a solid saturated fill — the tinted wash is the rule, and Vencido is the one confirmed exception, not a precedent to extend.",
"Don't reach for rounded-2xl outside the login mark and toasts; it is reserved for \"first impression / interruption\" moments.",
"Don't replace the mobile bottom dock with a hamburger drawer, or the desktop sidebar with a top bar — the device-appropriate nav pattern per breakpoint is deliberate."
]
}
}