# Transmodal Design System

> Category: Custom · Surface: web · Status: Draft v1
> Source basis: brand wordmarks, institutional photography, brand font (DM Sans), and operator-context brief captured in `context/source-context.md` and `context/figma/`.

Transmodal (Grupo Transmodal) is a Mexican logistics and multimodal transport operator. This system powers the surfaces the company uses to win and run accounts: commercial landing pages, sales proposals, operations dashboards, slide decks, and the social/marketing collateral that recycles those moves. The goal of the system is to make every Transmodal surface read as a serious operator — infrastructure-grade reliability, national coverage, and tech-enabled visibility — without resorting to generic corporate stock photography or hollow "trust" tropes.

## 1. Product Context &amp; Visual Theme

**Posture.** Industrial confidence. Deep navy as the dominant operational surface (the color of the institutional photography in `assets/transmodal-team-photo.png`), brand blue as the structural mark (the wordmark in `assets/logo-grupo-transmodal-azul.png`), one bright accent (lime) reserved for calls to action and live signals — the same accent the brand already uses for the tagline *"Protege lo tuyo."* Whitespace is generous, type is tightly controlled, ornament is rare. The system favors photography of real Transmodal operations (terminals, units, terminals, teams) over illustration.

**Mood references (internal):** the brand's own operations photography; B2B logistics operators such as Maersk, DSV, Lineage; industrial dashboards (Linear, Datadog) for product UI density.

**What this is NOT.** It is not a consumer fintech aesthetic (no soft pastels, no gradient washes). It is not a generic "AI workspace" canvas (no beige/peach). It is not a brutalist or editorial magazine play — Transmodal is critical infrastructure for shippers, and the system has to behave like one.

## 2. Color

All tokens are exposed in `colors_and_type.css` under `:root` and mirrored under `[data-theme="dark"]`. Use the semantic tokens (`--bg`, `--surface`, `--fg`, …) in product code; use the brand scale (`--brand-navy`, `--brand-blue`, …) only for hero treatments, marks, and decorative accents.

### Brand scale (source-of-truth)

| Token | Value (OKLch / hex) | Use |
|---|---|---|
| `--brand-navy-900` | `oklch(18% 0.045 250)` · `#0E2444` | Hero canvas, operational backdrops, dark deck slides |
| `--brand-navy-800` | `oklch(24% 0.055 250)` · `#142E55` | Dark surface, navbars over photography |
| `--brand-navy-700` | `oklch(32% 0.07 250)` · `#1C3D6E` | Dark sidebars, table headers on dark mode |
| `--brand-blue-600` | `oklch(54% 0.13 240)` · `#2580BC` | Primary brand — the wordmark color (`logo-grupo-transmodal-azul.png`) |
| `--brand-blue-500` | `oklch(62% 0.14 235)` · `#3A9BD8` | Hover state for primary, link color on light surfaces |
| `--brand-blue-300` | `oklch(78% 0.09 230)` · `#8FC6E6` | Soft fills, chips, secondary illustration |
| `--brand-cyan-400` | `oklch(82% 0.12 215)` · `#6FD8EF` | Live data accents, route polylines on map |
| `--brand-lime-500` | `oklch(86% 0.20 130)` · `#B6FF3D` | Primary CTA, success state, on-time signal — the tagline color from the brand photo |
| `--brand-lime-700` | `oklch(58% 0.17 135)` · `#5AA22A` | Lime accent on light backgrounds (ensures AA contrast) |

### Neutrals

| Token | Light | Dark | Use |
|---|---|---|---|
| `--bg` | `#F6F8FB` | `#0E2444` | Page canvas |
| `--surface` | `#FFFFFF` | `#142E55` | Cards, panels |
| `--surface-2` | `#EEF2F7` | `#1C3D6E` | Subdued panels, table stripes |
| `--fg` | `#0E2444` | `#F6F8FB` | Primary text |
| `--muted` | `#5C6B82` | `#9FB2CC` | Secondary text, metadata |
| `--border` | `#DCE3EC` | `#23436E` | Hairlines, dividers, input borders |
| `--border-strong` | `#B7C3D3` | `#3A5C8C` | Focus rings, separators on hero |

### Semantic / state

| Token | Hex | Use |
|---|---|---|
| `--accent` | `#B6FF3D` | Primary CTA, KPI deltas, on-time pill |
| `--success` | `#5AA22A` | Delivered, paid, in-bond cleared |
| `--warning` | `#E08A1F` | Delay risk, pending docs |
| `--danger` | `#D8453B` | Failed delivery, customs hold |
| `--info` | `#2580BC` | Informational badge (same as brand-blue-600) |

**Rules of use.**
- One accent (lime) on screen at a time. If the page already shows a lime CTA, do not also lime-tint a chart series; use cyan or brand-blue instead.
- Brand navy is the *operational* color. Use it as the dominant surface for any view that talks about live operations (tracking, dispatch, terminal status). Brand blue is the *structural* color — wordmark, headers, primary buttons on light surfaces.
- Never combine the orange warning and the lime accent in the same hero composition. They fight.
- Backgrounds must come from this scale — do not import the generic OD warm beige canvas.

## 3. Typography

**Family.** DM Sans, supplied locally in `fonts/` (Regular, Italic, Medium, MediumItalic, Bold, BoldItalic). `colors_and_type.css` binds them with `@font-face` so previews render the brand face, not a fallback. DM Sans pairs cleanly with the wordmark's geometric stroke and reads well at dashboard density.

**Fallback stack:** `"DM Sans", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif`.

**Type scale (rem-based, 16px root):**

| Token | Size | Weight | Line-height | Tracking | Use |
|---|---|---|---|---|---|
| `--type-display` | 4.5rem (72px) | 700 | 1.02 | -0.02em | Hero headline, deck cover |
| `--type-h1` | 3rem (48px) | 700 | 1.08 | -0.02em | Page title, section opener |
| `--type-h2` | 2.25rem (36px) | 700 | 1.15 | -0.01em | Section title |
| `--type-h3` | 1.5rem (24px) | 500 | 1.25 | -0.005em | Card title, table header group |
| `--type-h4` | 1.125rem (18px) | 500 | 1.3 | 0 | Sub-card, dense UI |
| `--type-body` | 1rem (16px) | 400 | 1.55 | 0 | Long-form body |
| `--type-body-sm` | 0.875rem (14px) | 400 | 1.5 | 0 | Table cells, secondary text |
| `--type-caption` | 0.75rem (12px) | 500 | 1.4 | 0.04em uppercase | Eyebrow, metadata |
| `--type-mono` | 0.875rem (14px) | 400 | 1.5 | 0 | Tracking numbers, container IDs, BL #s |

**Numerals.** Tabular by default in tables, dashboards, and KPI cards: `font-variant-numeric: tabular-nums`. Decks may use proportional figures in display headlines for optical balance.

**Mono.** When a literal identifier (container number `MSCU 123456-7`, BL `BLN-04-009123`, route code `MEX→LRD`) is on screen, render it in the `--font-mono` stack (`"JetBrains Mono", "IBM Plex Mono", ui-monospace, Menlo, monospace`).

**Capitalisation.** Eyebrows and tags only in uppercase with tracking +0.04em. Body and headlines stay sentence-case in Spanish (`Cobertura nacional`, not `COBERTURA NACIONAL`). Never block-uppercase a paragraph.

## 4. Spacing

8-pt base with named tokens — never write raw `padding: 7px`.

| Token | px | Use |
|---|---|---|
| `--space-1` | 4 | Icon ↔ text, chip padding |
| `--space-2` | 8 | Form control padding |
| `--space-3` | 12 | Card internal gap, dense list rows |
| `--space-4` | 16 | Default card padding |
| `--space-5` | 24 | Section padding, card-to-card gap |
| `--space-6` | 32 | Block separation in dashboards |
| `--space-7` | 48 | Landing section padding mobile |
| `--space-8` | 64 | Landing section padding desktop |
| `--space-9` | 96 | Hero breathing room |
| `--space-10` | 128 | Slide deck content margin |

**Radius:** `--radius-sm: 4px` (chips, tags), `--radius-md: 8px` (buttons, inputs), `--radius-lg: 12px` (cards), `--radius-xl: 20px` (hero panels, modal). No fully-rounded "pill" containers except for status badges.

**Shadows.** Restrained, single-token elevation:

```
--shadow-1: 0 1px 2px rgba(14,36,68,0.06);
--shadow-2: 0 4px 12px rgba(14,36,68,0.08);
--shadow-3: 0 12px 32px rgba(14,36,68,0.14);
```

`--shadow-1` for resting cards, `--shadow-2` for hover, `--shadow-3` for floating panels (modals, popovers). Dark mode swaps `rgba(0,0,0,…)` with the same alphas.

## 5. Layout & Composition

**Grid.** 12-column at desktop with `max-width: 1280px` page shell, `24px` gutters. Dashboards use a 16-column dense grid inside a 1440px shell. Tablet snaps to 8-column at 1024px. Mobile is a single 16px-margin column.

**Breakpoints.** `sm: 600px`, `md: 768px`, `lg: 1024px`, `xl: 1280px`, `2xl: 1536px`. Use container queries for component-internal reflows (KPI strips, route cards).

**Navigation.**
- **Marketing/landing**: sticky top nav, white surface, brand-blue wordmark left, primary CTA right (`Cotizar embarque`).
- **App / dashboard**: 64px-wide left rail on dark navy holding sectional icons (Embarques, Rastreo, Documentación, Reportes, Cuenta), expandable to 240px with labels. Top utility bar on light surface inside the work area for breadcrumb + filters.
- **Decks/proposals**: 1920×1080 canvas, fixed framework (see `assets/template-deck.html` — TBD when ready). One idea per slide, theme rhythm respected.

**Density.** Dashboards prefer compact rows (40px tall) with `--type-body-sm` and tabular numerics. Marketing pages run loose — at least 96px between hero and the first content section.

**Imagery.** Use real operational photography (terminals, fleet, port, scanners, team). When no real image is available, leave a labelled grey rectangle with the asset slug — never substitute generic stock.

## 6. Components

### Buttons

- **Primary** — lime background (`--accent`), navy text (`#0E2444`), 8px radius, 12/20 padding, 600 weight. Hover: darken 4%. Active: darken 8%. Disabled: 40% opacity, no pointer.
- **Secondary** — navy background (`--brand-navy-900`), white text. Same shape. Hover: lift to `--brand-navy-800`.
- **Tertiary / Ghost** — transparent, brand-blue text, 1.5px border `--brand-blue-600`. Use sparingly for inline actions in tables.
- **Destructive** — `--danger` background, white text. Confirm dialog required for irreversible operations (cancel embarque, anular factura).

### Form controls

Inputs use 1px `--border` border, 8px radius, 12/14 padding, body type. Focus ring: 2px `--brand-blue-500` outline with 2px offset (never the lime — too visually loud for routine focus). Errors flip the border to `--danger` and append helper text in `--danger` below.

### Cards & panels

`--surface`, `--shadow-1`, `--radius-lg`, 24px internal padding. Card header uses `--type-h3`, optional eyebrow above in `--type-caption` muted.

### Tables

Hairline-only — no row striping. Header row 48px tall, `--type-caption` uppercase muted. Body rows 40px tall, tabular numerics for any numeric column. Hover row tint: `color-mix(in oklab, var(--brand-blue-600) 6%, transparent)`. Status pills go in the rightmost column.

### Status pills

Rounded-pill, `--type-caption`, 4/8 padding. Color-coded by state token (`--success`, `--warning`, `--danger`, `--info`). Bold-uppercase the label; keep widths consistent so columns align.

### Map module

Dark navy basemap (Mapbox/dark style), brand-cyan route polylines, lime origin/destination markers, white labels with thin navy halo. Don't tint the basemap with brand-blue — readability dies.

### KPI tile

48–64px display number in `--type-h1`, label below in `--type-caption`, optional delta chip in `--accent` (positive) or `--danger` (negative). Tabular numerics mandatory.

### Modal & sheet

`--surface`, `--shadow-3`, `--radius-xl`. Max-width 560px (forms), 880px (preview). Backdrop: `rgba(14,36,68,0.6)`.

### Toast

Bottom-right stack, 8s default dismiss. Color stripe on the left edge by state token.

### Domain components (logistics-specific)

- **Shipment row** — origin → destination with arrow glyph, container ID in mono, ETA, status pill, owner avatar.
- **Container chip** — mono ID, type code (`40HC`, `20DV`), small color dot for line carrier.
- **Customs status strip** — five-step horizontal stepper (Documentación → Pre-validación → Despacho → Liberación → Entrega) with active state in `--accent`.
- **Route map card** — see Map module.
- **Quote calculator** — left form, right cost breakdown card; primary action bottom-right.

## 7. Motion & Interaction

- Standard easing: `cubic-bezier(0.2, 0.7, 0.1, 1)` (a soft ease-out that feels operational, not playful).
- Durations: `120ms` for color/state changes, `180ms` for translate/opacity, `240ms` for sheet/modal enter, `320ms` max for hero reveals.
- Loading: skeleton blocks in `--surface-2` with a 1.2s shimmer. No spinners on long-running dispatch operations — use a progress bar with the current step label.
- Reduced motion: respect `prefers-reduced-motion: reduce`; fall back to opacity-only transitions, no translates.
- Focus: 2px `--brand-blue-500` ring with 2px offset on every interactive element. Visible on dark surfaces too.
- Hover (pointer only): elevation lift (shadow-1 → shadow-2) plus 1px translateY(-1px) on cards. No hover state on touch devices.

## 8. Voice & Brand

**Language.** Spanish (es-MX) by default. English mirrors only where the customer is bilingual (BL detail pages, shipping line modules). Never machine-translate operational terms; use the carrier/customs term.

**Tone.** Direct, operator-to-operator. We tell shippers what is happening with their cargo and what to do next. No marketing fluff, no "revolucionando la logística" lines, no exclamation marks in product copy.

**Terminology.**
- Use *embarque* for shipment, *unidad* for truck, *contenedor* for container, *patio* for yard, *pedimento* for customs entry.
- Carrier names always in their canonical form (`Maersk`, `MSC`, `CMA CGM`, `Hapag-Lloyd`).
- Status verbs are past-tense events (`Cargado`, `Despachado`, `Entregado`) — not gerunds.

**Brand line.** *Protege lo tuyo* is the active tagline (visible in `assets/transmodal-team-photo.png`). It pairs with the lime accent and should never appear on a non-navy surface.

**Capitalisation.** Sentence case for headlines and buttons. Acronyms (`BL`, `INCOTERM`, `EDI`, `RFC`) stay uppercased. Carrier and city names use their native casing (`Lázaro Cárdenas`, not `LAZARO CARDENAS`).

## 9. Anti-patterns

- ❌ Warm beige / peach / cream / pink page washes. The Transmodal palette is navy + brand-blue + lime; never the OD default cozy canvas.
- ❌ Gradient hero washes (purple-to-pink, blue-to-green). Use solid navy with one accent.
- ❌ Generic emoji icon rows (✨🚀🎯). Use lucide or feather industrial icons (truck, ship, container, gauge, map-pin) — never the cartoon set.
- ❌ Lorem ipsum or invented uptime/SLA stats ("99.9% on-time"). If we don't have the real number, write the metric label and a `—`.
- ❌ The wordmark on a non-navy / non-white surface. Logo only on `#FFFFFF` or `--brand-navy-900`.
- ❌ Lime accent in body copy or chart axes. Lime is reserved for CTAs, success/on-time signals, and the tagline.
- ❌ Inter, Roboto, or Arial as display face. DM Sans is the brand face — bind the local files, do not import from Google Fonts in production (it slows the LCP and leaks routing).
- ❌ Designer/preview chrome inside product surfaces (viewport pickers, theme togglers, "demo only" badges). UI kit examples must look like the real product.
- ❌ Cropping the wordmark, recoloring it outside the two supplied variants, or rotating it. The two canonical files in `assets/` are the only acceptable marks.
- ❌ Photo collages mixing brand photography with stock images. If we use stock, the whole composition is stock; mixing breaks the operator-grade read.
