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>
This commit is contained in:
2026-08-16 15:19:57 -07:00
parent 927d99c262
commit 57b07b9b82
20 changed files with 596 additions and 27 deletions
+226
View File
@@ -0,0 +1,226 @@
---
name: LabPréstamos
description: Sistema institucional UABC para préstamo de material de laboratorio — la bitácora de papel y Excel, digitalizada.
colors:
verde-institucional: "#00723F"
verde-institucional-hover: "#005f34"
dorado-uabc: "#DD971A"
dorado-uabc-hover: "#c78614"
superficie: "#F4F7F5"
tinta: "#2D3748"
peligro: "#C53030"
typography:
headline:
fontFamily: "Inter Variable, ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif"
fontSize: "1.5rem (2xl) → 1.875rem (3xl) md+"
fontWeight: 600
lineHeight: 1.25
title:
fontFamily: "Inter Variable, ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif"
fontSize: "1.125rem"
fontWeight: 600
lineHeight: 1.4
body:
fontFamily: "Inter Variable, ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif"
fontSize: "0.875rem"
fontWeight: 400
lineHeight: 1.5
label:
fontFamily: "Inter Variable, ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif"
fontSize: "0.875rem"
fontWeight: 500
lineHeight: 1.3
caption:
fontFamily: "Inter Variable, ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif"
fontSize: "0.75rem"
fontWeight: 400
lineHeight: 1.4
rounded:
control: "0.5rem"
emphasis: "1rem"
pill: "9999px"
spacing:
tight: "0.5rem"
base: "1rem"
loose: "1.5rem"
section: "2rem"
components:
button-primary:
backgroundColor: "{colors.verde-institucional}"
textColor: "#ffffff"
rounded: "{rounded.control}"
padding: "10px 16px"
button-secondary:
backgroundColor: "{colors.dorado-uabc}"
textColor: "#ffffff"
rounded: "{rounded.control}"
padding: "10px 16px"
button-ghost:
backgroundColor: "transparent"
textColor: "{colors.tinta}"
rounded: "{rounded.control}"
padding: "10px 16px"
card:
backgroundColor: "#ffffff"
textColor: "{colors.tinta}"
rounded: "{rounded.control}"
padding: "24px"
input:
backgroundColor: "#ffffff"
textColor: "{colors.tinta}"
rounded: "{rounded.control}"
padding: "10px 12px"
---
# Design System: LabPréstamos
## Overview
**Creative North Star: "La Bitácora Digital"**
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.
The 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."
Two 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.
**Key Characteristics:**
- 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`
## Colors
Two institutional hues carry the whole palette under a strict 60/30/10 split — green dominant, gold as a deliberately rare accent, everything else neutral ink and white.
### Primary
- **Verde Institucional** (`#00723F`): the UABC green. Primary buttons, the desktop sidebar's entire background, active nav states, focus rings, "healthy/positive" status pills (disponible, aprobado, devuelto), the login mark. This is the color of the system's authority — it appears on anything that confirms, approves, or orients.
### Secondary
- **Dorado UABC** (`#DD971A`): the institutional gold. Used sparingly and only as an accent — secondary buttons, the "en préstamo" KPI tile, "mantenimiento" status pills, the logo-mark square on the sidebar/mobile header. Never the dominant color of a screen.
### Neutral
- **Superficie** (`#F4F7F5`): the page background — a near-white green-grey, not pure white. Everything else (cards, dialogs, the desktop sidebar's text, dock) sits on top of it.
- **Tinta** (`#2D3748`): body text, and — critically — the **source color for every border in the system**. Borders are never a fixed gray; they're `color-mix(in oklab, var(--color-ink) N%, transparent)` at 820% depending on prominence. This ties every hairline to the same ink token instead of a separate gray scale.
- **Peligro** (`#C53030`): errors, destructive actions, and the one status that is allowed to break the tinted-pill convention (see Named Rules).
### Named Rules
**The Ink-Mix Border Rule.** 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.
**The Vencido Exception.** Every status pill uses the tinted-fill pattern (see Components → Badges) *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: reserve a solid semantic fill for the single state that genuinely needs to interrupt a scan, and only that state.
## Typography
**Body & Display Font:** Inter Variable (with `ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif` fallback)
**Character:** One typeface for the entire system — hierarchy comes from weight and size, never a second family. It reads as a single, consistent institutional voice rather than a "brand font + UI font" split.
### Hierarchy
- **Headline** (600, 1.5rem → 1.875rem at `md:`, 1.25 line-height): page-level `<h1>`s — "Mis préstamos", "Estadísticas", the login screen's title.
- **Title** (600, 1.125rem, 1.4 line-height): section and card headers — "Inicia sesión", "Inventario", empty-state headings.
- **Body** (400, 0.875rem, 1.5 line-height): the default text size for the whole system — table cells, descriptions, list content. Notably small-scale throughout; this is a dense operational tool, not editorial content.
- **Label** (500, 0.875rem): form field labels (`.label`), rendered at 90% ink opacity.
- **Caption** (400, 0.75rem, opacity 6080%): metadata — matrícula, inventory numbers, timestamps, hint text under fields.
### Named Rules
**The Tabular Numbers Rule.** 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, because that is literally what they replace.
## Layout
The system runs on Tailwind's default breakpoint (`md:` = 768px) as the single hard split between the mobile and desktop layouts — there is no intermediate tablet treatment.
**Desktop (≥768px):** a fixed 256px (`w-64`) left sidebar in solid Verde Institucional, full page height. It is collapsible: a hamburger button above the content toggles a `sidebar-collapsed` class on `<html>`, animated with a 200ms `translateX(-100%)`; the choice persists in `localStorage` and is applied via a blocking inline `<script>` in `<head>` before paint, so there is no collapse flash on reload. Content sits in `max-w-6xl` (data-dense admin views) or `max-w-4xl`/`max-w-md` (narrower alumno views), with `p-8` outer padding.
**Mobile (<768px):** no sidebar. A minimal fixed header (logo mark + user identity) sits at the top; navigation lives instead in a floating pill-shaped dock anchored to the bottom-center of the viewport, respecting `env(safe-area-inset-bottom)`. Content padding drops to `p-4` with `pb-28` to clear the dock.
**The Table/Card Swap Rule.** Every data-dense admin view (solicitudes, inventario, reportes) ships two complete renderings of the same data: a `<table>` for `md:block` and a `<ul>` of `.card` items for `md:hidden`. This is a structural swap, not a responsive squeeze — the mobile version is not a scrolled-sideways table, it is a genuinely different layout for the same rows.
## Elevation & Depth
The system is flat by default. Cards, buttons, inputs, and dialogs carry no shadow — only a 1px ink-mix hairline border. Depth is reserved, deliberately, for the two things that are not part of the page: the mobile dock nav and the toast stack, both of which visually float above whatever is scrolling underneath them.
### Shadow Vocabulary
- **Floating chrome** (`box-shadow: 0 10px 30px -8px rgba(0,0,0,0.25)`): the mobile dock nav — a soft, diffuse shadow that reads as "hovering," combined with `backdrop-blur` and a translucent white background.
- **Overlay notification** (`box-shadow: 0 16px 40px -12px rgba(0,0,0,0.25)`): the toast stack — same diffuse quality, slightly heavier, paired with `backdrop-blur-xl` and `bg-white/85`.
### Named Rules
**The Flat Page, Floating Chrome Rule.** 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. Shadow is the visual signal for "this is not part of the page you're reading."
## Shapes
Three radius steps, used by role rather than by component:
- **Control** (`0.5rem`, token `--radius-card`): the default — buttons, cards, inputs, dialogs, table containers. This is the system's baseline corner.
- **Emphasis** (`1rem`, `rounded-2xl`): reserved for two "first impression" surfaces — the login screen's avatar mark and toast notifications. A visibly softer corner than the control radius, used to signal warmth at the exact moments the system greets or interrupts the user.
- **Pill** (`9999px`, `rounded-full`): status badges, the mobile dock and its buttons, the pending-count chip. Anything that is a small, discrete piece of state rather than a container.
Borders are always hairline (1px) and always ink-mix (see Colors → Named Rules); the system has no heavy or decorative border weight.
## Components
### Brand Mark
- A single authored glyph (`BrandMark.astro`, 24×24 viewBox) stands in for the system's identity everywhere a mark is needed: the desktop sidebar header, the mobile header, the login screen, and the 403/404 states. It reads as a loan tag with a punch-hole — a quiet nod to the physical préstamo ticket the system replaces.
- It is a solid silhouette (not an outline stroke like the nav icons), rendered via `currentColor` so it can sit white-on-primary or tinted-on-danger without a second asset.
- It is the product's own mark, not an institutional crest — it never stands in for an official UABC or laboratorio seal.
- The favicon (`public/favicon.svg`) is the same glyph, colored Verde Institucional in light mode and Superficie in dark mode.
### Buttons
- **Shape:** Control radius (0.5rem), 44px minimum height, `touch-action: manipulation` — every button is a comfortable tap target regardless of platform.
- **Primary:** Verde Institucional background, white text. The system's default call to action (submit, approve, continuar con Google).
- **Secondary:** Dorado UABC background, white text. Used sparingly — filtering actions, not primary flows.
- **Ghost:** Transparent background, ink text, hairline ink-mix border (15%). Used for "Cancelar" / "Limpiar" — the low-commitment counterpart to Primary.
- **Hover / Focus:** hover is a uniform `motion-safe:hover:brightness-110` filter across all filled variants (not a swap to a separate hover-color token); focus is a 2px solid outline in Verde Institucional, 2px offset. Disabled drops to 50% opacity and disables pointer events.
### Badges / Status Pills
- **Style:** pill radius, `text-xs`/`text-sm font-semibold`, `px-2` to `px-2.5`, `py-0.5`.
- **The Tinted Pill Rule.** Background = the semantic color at 1215% via `color-mix`; text = the semantic color at full strength. Never a solid fill — with the one confirmed exception below.
- **Semantic mapping:** disponible / aprobado / devuelto → Verde Institucional tint. mantenimiento → Dorado UABC tint (text at the `-hover` shade for contrast). baja / rechazado → ink tint (neutral, ~810%). **Vencido** (overdue) → the sole solid-fill exception: white text on full-strength Peligro, plus a light danger wash across the whole card on mobile.
### Cards / Containers
- **Corner:** Control radius (0.5rem).
- **Background:** white, always — the one surface color that appears identically on both the pale-green page background and the green sidebar.
- **Border:** hairline ink-mix (10%); no shadow (see Elevation).
- **Internal Padding:** `p-6` for standard cards and forms; `p-4` for dense KPI tiles; `p-0` when the card is a table/list wrapper (the table supplies its own cell padding).
### Inputs / Fields
- **Style:** white background, hairline ink-mix border (20%), Control radius, 44px minimum height.
- **Focus:** 2px solid Verde Institucional outline, 2px offset — the same focus treatment as buttons and links, no separate glow or border-color shift.
- **Label:** `.label` class, 0.875rem/500 weight, ink at 90% opacity, always paired via `htmlFor`/`id`.
- **Error:** inline `role="alert"` text in Peligro below the field, not a border-color change.
### Navigation
- **Desktop sidebar:** solid Verde Institucional panel, white text at 85% opacity for inactive items, white/15% background wash for the active item, `aria-current="page"`. Collapsible (see Layout).
- **Mobile dock:** floating pill, `backdrop-blur` + `bg-white/95`, icon-only (24×24 heroicons-outline, `stroke-width: 1.8`, `currentColor`), active item = solid Verde Institucional circle. Sign-out is visually separated by a vertical hairline divider and turns Peligro on hover.
### Toasts (signature component)
- Fixed top-center overlay, `rounded-2xl`, `bg-white/85` + `backdrop-blur-xl`, floating-chrome shadow.
- A circular color chip (36px) leads each toast: Verde Institucional for success, Peligro for error, Dorado UABC for info — each with a small stroke icon.
- Entrance: 260ms `cubic-bezier(0.22, 1, 0.36, 1)` translate+scale+fade; auto-dismisses at 3.8s; tap anywhere to dismiss early; fully respects `prefers-reduced-motion`.
- Survives a `location.reload()` via a `sessionStorage` queue — the system was built assuming most actions end in a reload, and the toast must not be lost.
### Modals
- Native `<dialog>` element (no custom overlay library), Control radius, `backdrop:bg-black/40`, width `min(92vw, 28rem)`.
- Focus moves to the first field on open; closes on backdrop click or the close-icon control (a drawn SVG X, never a `×` character); disabled while a submit is in flight.
## Do's and Don'ts
### Do:
- **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). A new floating element earns the same shadow vocabulary; a page element does not.
- **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 (`transition-colors`, `transition-[filter,...]`), never `transition-all`.
- **Do** give every interactive control a 44px minimum tap target and `touch-action: manipulation`.
- **Do** draw every icon as an SVG (the shared heroicons-outline language, or the `BrandMark` glyph for identity) — close controls, chevrons, and status glyphs included.
### Don't:
- **Don't** stand in a unicode glyph (`×`, ``, `✓`, emoji) for an icon — every icon is a drawn SVG, one consistent stroke and weight.
- **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 system's 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, not a general card radius.
- **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 an established, deliberate split.