K1 Design System / Design Tokens
Foundations

Design Tokens

All values are CSS custom properties. Apply data-theme="dark" or "light" on <html> to switch modes.

Color Palette

Brand, semantic, surface, and text tokens. Exact hex values below — no opacity guessing needed.

--color-primary
--color-success
--color-warning
--color-error
--color-info
--color-bg
--color-surface-2
--color-surface-3

Kanban Status

--color-status-nuevo
--color-status-revision
--color-status-asignado
--color-status-escena
--color-status-cerrado

Extended Platform Tokens

Additional tokens for KDispatch-specific UI patterns. Reference in both React and Angular implementations.

Status Background Tokens

--status-nuevo-bg
--status-revision-bg
--status-asignado-bg
--status-escena-bg
--status-cerrado-bg

Priority Tokens

--priority-alta
--priority-media
--priority-baja
--priority-alta-bg
--priority-media-bg
--priority-baja-bg

Resource Tokens

--resource-disponible
--resource-en-camino
--resource-en-escena

Field Tokens

--field-bg
--field-border
--field-text

Shadow Tokens

--shadow-sm
--shadow-md
--shadow-lg
--shadow-panel

Sidebar Tokens

--sidebar-bg
--sidebar-item-hover
--sidebar-item-active
--sidebar-text
--sidebar-text-active

Shadow Levels

Three elevation levels. Use consistently — no mixing.

sm Cards, dropdowns
md Modals, panels
lg Overlay panels

Full CSS Token File

Copy this into your global stylesheet.

CSS — src/styles/tokens.css
/* K1 DESIGN TOKENS — import in angular.json styles[] */
/* Font — Public Sans only */
@import url('https://fonts.googleapis.com/css2?family=Public+Sans:wght@300;400;500;600;700;800&display=swap');

:root {
  /* Spacing (4px grid) */
  --space-1:  4px;   --space-2:  8px;   --space-3: 12px;
  --space-4: 16px;   --space-5: 20px;   --space-6: 24px;
  --space-8: 32px;   --space-10: 40px;  --space-12: 48px;

  /* Typography */
  --font:    'Public Sans', sans-serif;
  --text-xs: 11px;  --text-sm: 12px;  --text-base: 13px;
  --text-md: 14px;  --text-lg: 16px;  --text-xl: 20px;

  /* Heights */
  --h-sm: 32px;  --h-md: 36px;  --h-lg: 40px;  --h-xl: 48px;

  /* Radius */
  --radius-sm: 4px;   --radius-md: 8px;
  --radius-lg: 12px;  --radius-xl: 16px;  --radius-full: 9999px;
}

Sidebar Tokens

Used by AppSidebar in both K-Safety and K-Traffic shells. Responds to theme toggle.

--sidebar-bg
--sidebar-item-hover
--sidebar-item-active
--sidebar-text
--sidebar-text-active
CSS — sidebar usage
.sidebar { background: var(--sidebar-bg); width: var(--sidebar-width); }
.sidebar-item { color: var(--sidebar-text); }
.sidebar-item:hover { background: var(--sidebar-item-hover); }
.sidebar-item.active { background: var(--sidebar-item-active); color: var(--sidebar-text-active); }

Header Tokens

Top chrome bar — height fixed at 64px. Background = page background (not a panel).

--header-bg
--header-border
64
--header-height
64px

Kanban & Board Tokens

Used in KanbanSafetyView and the dispatcher's dispatch board. All change in light mode.

--kanban-bg
--kanban-col
--card-active
--card-hover
--row-bg
--row-hover
--detail-bg

Priority Tokens

Incident priority — always uses these exact hues in both modes.

--priority-alta
--priority-alta-bg
--priority-media
--priority-media-bg
--priority-baja
--priority-baja-bg
ALTA MEDIA BAJA

Severity Tokens — K-Traffic

Road severity scale used in Traffic Management Center views. Separate from incident priority.

--severity-critical
--severity-high
--severity-medium
--severity-low
--severity-info

Product Accent Tokens

Each K1 product module has its own accent used for module labels, active indicators, and status dots.

--product-safety-accent
--product-traffic-accent
--product-vms-accent

Panel & Overlay Tokens

Panel backgrounds, overlay scrims, chip/separator primitives.

--panel-bg
--panel-header-bg
--overlay-bg
--chip
Foundations

Typography

Three fonts: Public Sans (UI default) · Inter (dense data, labels, headers) · JetBrains Mono (IDs, tokens, code). All loaded via Google Fonts + referenced through tokens.

Font Families

Primary UI
Public Sans
var(--font) · all UI elements
Aa Bb Cc Dd Ee Ff Gg
0 1 2 3 4 5 6 7 8 9
Data / Labels
Inter
var(--font-ui) · dense data labels
Aa Bb Cc Dd Ee Ff Gg
0 1 2 3 4 5 6 7 8 9
Code / Mono
JetBrains
var(--font-mono) · IDs, tokens, code
Aa Bb Cc Dd Ee Ff Gg
C5/00051 · #2b7fff
CSS — font tokens
--font:      'Public Sans', sans-serif;  /* default — all UI */
--font-ui:   'Inter', sans-serif;         /* dense data labels */
--font-mono: 'JetBrains Mono', monospace; /* IDs, tokens, code snippets */

Type Scale — Public Sans

Rule: All font-family values must be var(--font). Never hardcode 'Public Sans' — use the token. This ensures a single source of truth.
Token Size LH Weight Preview
--text-3xl 30px 40px 800 Emergency
--text-2xl 24px 32px 700 Dispatcher View
--text-xl 20px 28px 700 Incident Panel
--text-lg 16px 24px 600 Section Header
--text-md 14px 20px 400 Body text. Used for main content descriptions.
--text-base 13px 20px 400 Default UI body text. Inputs, tables, cards.
--text-sm 12px 18px 400 Captions, code snippets, hint text, timestamps.
--text-xs 11px 16px 600 LABEL / META / BADGE TEXT

Font Weight Reference

--fw-regular (400)
Incidente Vial en Tepito
--fw-medium (500)
Incidente Vial en Tepito
--fw-semibold (600)
Incidente Vial en Tepito
--fw-bold (700)
Incidente Vial en Tepito
--fw-extrabold (800)
Incidente Vial en Tepito
Foundations

Spacing & Layout

4px base grid. Every padding, margin, and gap must use a token. No raw pixel values in component code.

Spacing Scale

--space-1
4px · xs
--space-2
8px · sm
--space-3
12px · md-sm
--space-4
16px · md (default padding)
--space-5
20px · md-lg
--space-6
24px · lg
--space-8
32px · xl (section padding)
--space-10
40px · 2xl (page padding)
--space-12
48px · 3xl

Border Radius Scale

--radius-sm
4px
--radius-md
8px
--radius-lg
12px
--radius-xl
16px
--radius-full
9999px

Component Height Reference

Fixed heights for interactive elements. Never deviate from these values.

TokenValueUsage
--h-xs24pxIcon-only mini buttons, tiny badges
--h-sm32pxSmall buttons (btn-sm), toolbar actions, DS chrome
--h-md36pxDefault inputs, selects, textareas (single-line)
--h-lg40pxDefault buttons (p-button), icon buttons
--h-xl48pxLarge buttons, prominent CTAs
--h-header60pxApp header bar
--h-nav56pxSidebar logo row
Foundations

Icons

All icons: inline SVG · 18×18px · stroke="currentColor" · stroke-width 1.3px · stroke-linecap/join: round. Grouped by platform domain. Click any cell to copy the SVG code.

Icon Specification

Size
18 × 18px
viewBox="0 0 18 18"
Stroke
1.3px
currentColor · round caps
Fill
none
Outline style only
SVG Template — copy for all icons
<svg width="18" height="18" fill="none" viewBox="0 0 18 18">
  <path d="M..."
    stroke="currentColor"
    stroke-width="1.3"
    stroke-linecap="round"
    stroke-linejoin="round"
  />
</svg>

<!-- Angular: bind color via CSS class -->
<svg class="k1-icon" width="18" height="18" fill="none" viewBox="0 0 18 18">...</svg>
/* css */
.k1-icon { display: block; flex-shrink: 0; }
.k1-icon-sm { width: 14px; height: 14px; } /* small context */
.k1-icon-lg { width: 20px; height: 20px; } /* large context */

Navigation & Views

Toolbar navigation icons. Always right-positioned tooltip on hover.

Incidents & Dispatch

Incident management, emergency types, and dispatch workflow.

Resources & Units

Emergency vehicles, personnel, and resource management.

Communication & Media

Radio, CCTV, phone, and communication channel icons.

Status & Feedback

System status, alerts, and user feedback icons.

Location & Map

Map, GPS, zones, and geolocation icons.

Data & Reports

Analytics, charts, reports, and data management icons.

System & Settings

Configuration, administration, and system management icons.

UI Actions

General-purpose UI interaction icons used across all components.

PrimeIcons — Required Set

K1 Dispatch uses PrimeIcons as the primary icon library for both PrimeReact (React) and PrimeNG (Angular). Usage: <i class="pi pi-{name}"></i> — inherits currentColor from parent. CDN: primeicons@7

HTML — CDN import
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/primeicons@7/primeicons.css"/>

<!-- React (NPM) -->
npm install primeicons
import 'primeicons/primeicons.css';

<!-- Angular (angular.json) -->
"styles": ["node_modules/primeicons/primeicons.css"]

<!-- Usage -->
<i class="pi pi-send"></i>
<i class="pi pi-exclamation-triangle" style="color:var(--color-error)"></i>
Components

Buttons

Height: 40px (default) · 32px (sm) · 48px (lg). Padding: 0 16px. Radius: 8px. Font: 14px/500. All states explicitly defined.

Variants — All States

Hover the buttons to test interaction states. Each state has an exact CSS definition — no inheritance surprises.

Interactive Preview
Angular — p-button overrides
<!-- Primary -->
<p-button label="Dispatch" styleClass="k1-btn k1-btn-primary"></p-button>
<!-- OR native -->
<button class="k1-btn k1-btn-primary">Dispatch</button>
<!-- Disabled -->
<button class="k1-btn k1-btn-primary" disabled>Disabled</button>

Sizes

Preview
32px
40px
48px
40×40
icon-only
ghost

Buttons with PrimeIcons

Icon placement: leading icon (most common), trailing icon, or icon-only. Use pi pi-{name} inside the button. Size matches text naturally.

Preview — PrimeIcons + k1-btn
React / Angular — icon buttons
{/* React — leading icon */}
<button className="k1-btn k1-btn-primary">
  <i className="pi pi-send" /> Despachar
</button>

<!-- Angular — icon-only -->
<button class="k1-btn k1-btn-icon-only k1-btn-outline">
  <i class="pi pi-cog"></i>
</button>

K1 Dispatch Button

Emergency action only. Gradient red with shadow. Not for general use.

Preview

Props Reference

ClassHeightPaddingFontUsage
k1-btn-primary40px0 16px14px/500Primary CTA, confirm actions
k1-btn-secondary40px0 16px14px/500Secondary actions
k1-btn-outline40px0 16px14px/500Tertiary, cancel
k1-btn-ghost40px0 16px14px/500Inline actions, low emphasis
k1-btn-danger40px0 16px14px/500Destructive — delete, revoke
k1-btn-dispatch40px0 20px14px/700Emergency dispatch ONLY
k1-btn-sm32px0 12px12px/500Compact spaces, table actions
k1-btn-lg48px0 24px14px/500Hero CTAs, form submits
Components

Badges & Status

Font: 11px/600. Padding: 2px 8px. Radius: 4px (badge) / 9999px (pill). All status colors are locked tokens.

Generic Badges

Preview
Primary Success Warning Error Info Neutral Outline
● Online ● Idle ● Offline Alert

Kanban Status Pills

Font: 10px/700 uppercase. Padding: 3px 12px. Radius: 9999px. These are platform-specific — never use for generic labelling.

5 Workflow States
Nuevo Revisión Asignado En Escena Cerrado

Resource Status

Unit States
Disponible En Camino En Escena
Components

Form Controls

All inputs: height 36px · padding 0 12px · radius 8px · border 1px solid --color-border · focus: primary ring. Consistent across every form element.

Text Input — All States

All visible states
Dirección no encontrada en base de datos
Este campo es de solo lectura
Angular — p-inputText
<!-- PrimeNG input with K1 class -->
<input pInputText class="k1-input"
       formControlName="location"
       placeholder="Peralvillo 87..." />
<!-- Error state driven by Angular reactive forms -->
<span class="k1-error" *ngIf="form.get('location')?.invalid && submitted">
  Campo requerido
</span>

Input with Icon

Preview

Select / Dropdown

Custom dropdown replaces the native <select> and PrimeNG p-dropdown. Same height (36px), padding, border, and radius as text input.

Default · With value — click to open
Accidente Vial
Incendio Estructura
Fuga de Gas
Abandono Animal
ALTA — Alta prioridadALTA
MEDIA — Media prioridadMEDIA
BAJA — Baja prioridadBAJA
Angular — p-dropdown override
<!-- Replace native select with k1-dd-wrap -->
<div class="k1-dd-wrap">
  <button class="k1-dd-trigger" (click)="toggleDd()">
    <span class="k1-dd-trigger-label">{{ selected }}</span>
    <span class="k1-dd-trigger-icon"><!-- chevron svg --></span>
  </button>
  <div class="k1-dd-panel" role="listbox">
    <div class="k1-dd-item" *ngFor="let opt of options"
         (click)="select(opt)">
      <span class="k1-dd-item-text">
        <span class="k1-dd-item-label">{{ opt.label }}</span>
      </span>
    </div>
  </div>
</div>

Checkbox, Radio & Switch

All interactive — click to toggle
CCTV Overlay activo
Modo oscuro

Textarea

Preview
Máximo 500 caracteres
Components

Cards

Surface: --color-surface-2. Border: 1px solid --color-border. Radius: 16px (--radius-xl). Shadow: --shadow-sm. Internal padding: 20px 24px.

Base Card

Preview
Resumen del Incidente
C5/00051 — INCENDIO ESTRUCTURA

Peralvillo 87, Tepito. BAMBE-01 en escena. Incendio controlado al 70%. Solicita apoyo de Protección Civil.

Angular — p-card override
<!-- Option A: native div (recommended for K1) -->
<div class="k1-card">
  <div class="k1-card-header">
    <div class="k1-card-title">Title</div>
  </div>
  <div class="k1-card-content">Content</div>
  <div class="k1-card-footer">Footer</div>
</div>
<!-- Option B: p-card with styleClass -->
<p-card styleClass="k1-card"></p-card>
Components

Alerts

Padding: 12px 16px. Radius: 8px. Font: 13px. Each variant uses token-based subtle background + border. No opacity hacks.

All Variants

Preview
Unidad Despachada
BAMBE-01 está en camino. ETA estimado: 4 minutos.
Alerta de Gas
Priv. Moctezuma 23 — evacuación preventiva en curso.
Enlace de Radio Caído
Conexión con Radio Base CDMX perdida. Reintentando…
Actualización del Sistema
Nuevo turno iniciado. Reporte de cambio generado.
Components

Tabs

Tab height: 36px. Padding: 0 16px. Active: surface-4 bg + border + shadow-sm. Font: 13px/500 → 13px/600 active.

Default Tabs

Interactive
Mostrando 13 unidades activas en el sistema
Components

Overlays & Panels

K1 uses slide-down panels from the header bar — not centered modals. Animation: translateY(-12px → 0) + opacity. Duration: 220ms. Easing: cubic-bezier(0.16,1,0.3,1).

Panel Pattern

Static mockup (non-fixed positioning)
🔔 Notificaciones 3
INCENDIO ESTRUCTURA
Peralvillo 87, Tepito — BAMBE-01 en escena.
13:45
NUEVO REPORTE
Insurgentes Norte 1500. 2 lesionados leves.
13:31
CSS — slide-down animation
/* Panel container */
.k1-panel {
  position: fixed;
  top: 60px;      /* --h-header */
  left: 50%;
  transform: translateX(-50%);
  width: 560px;
  max-height: calc(100vh - 80px);
  overflow-y: auto;
  background: var(--color-surface-2);
  border: 1px solid var(--color-border-strong);
  border-radius: 0 0 var(--radius-xl) var(--radius-xl);
  box-shadow: var(--shadow-lg);
  animation: panelIn 0.22s cubic-bezier(0.16,1,0.3,1);
  z-index: 200;
}

@keyframes panelIn {
  from { opacity: 0; transform: translateX(-50%) translateY(-12px); }
  to   { opacity: 1; transform: translateX(-50%) translateY(0); }
}
Platform

Kanban Board

5-column incident workflow board. Column width: 240px. Status top-border (3px) keyed to --color-status-*. Cards use the full k1-inc anatomy: tags · title · address · timer + action + case-ID · progress · priority + avatar + number.

Filter Bar

Always visible above board
All Priorities
HighALTA
MediumMEDIA
LowBAJA
All Assignees
01
Operator 01
02
Operator 02
All Zones
Roma Norte
Juárez
Mixcoac
All Types
Fire
Traffic Accident
Medical Emergency

Full Board — Live Preview

Interactive · Dark surface · Matches KDispatch product
New
4
New Fire Roma Norte
Fire
Calle Durango, Roma Norte
503:51:02 C5/20260407/00053
Progress
5%
New Traffic Accident Observatorio
Traffic Accident
Av. Observatorio, Observatorio
503:41:02 C5/20260407/00057
Progress
5%
New Medical Emergency Cuauhtémoc
Medical Emergency
Paseo de la Reforma, Cuauhtémoc
503:29:02 C5/20260407/00060
Progress
5%
Review
2
Review Medical Emergency Santa Fe
Medical Emergency
Av. Vasco de Quiroga, Santa Fe
503:49:02 C5/20260407/00054
Progress
25%
Review Domestic Violence Roma Norte
Domestic Violence
Calle Coahuila, Roma Norte
503:36:02 C5/20260407/00058
Progress
25%
Assigned
3
Assigned Pedestrian Robbery Juárez
Pedestrian Robbery
Paseo de la Reforma, Juárez
503:56:02 P-07 / SSC-Cu…
Progress
50%
Assigned Vehicle Theft Mixcoac
Vehicle Theft
Blvd. Adolfo López Mateos, Mixcoac
504:11:02 P-09 / SSC-Al…
Progress
50%
Assigned Traffic Accident Pedregal S.N.
Traffic Accident
Calz. de Tlalpan, Pedregal de San Nicolás
503:33:02 A-03 / A-07 / P…
Progress
50%
On Scene
2
On Scene Traffic Accident Hipódromo Condesa
Traffic Accident
Av. Insurgentes Sur, Hipódromo Condesa
504:01:02 P-12 / A-03 / S…
Progress
75%
On Scene Incident Bosque Chapultepec
Incident
Bosque de Chapultepec, Bosque de Chapultepec
504:13:02 P-14 / P-15
Progress
75%
Closed
3
Closed Disturbance Hipódromo
Disturbance
Av. Chapultepec, Hipódromo
505:16:02 P-05 C5/20260407/00055
Progress
100%
Closed Incident Roma Norte
Incident
Calle Mérida, Roma Norte
506:01:02 B-01 C5/20260407/00049
Progress
100%
Closed Medical Emergency Hipódromo Condesa
Medical Emergency
Av. Sonora, Hipódromo Condesa
506:26:02 A-05 C5/20260407/00048
Progress
100%

Column Status Tokens

ColumnCSS varDarkLightProgress fill %
New--color-status-nuevo#00b4d8#0096b45%
Review--color-status-revision#f59e0b#d9770625%
Assigned--color-status-asignado#4d7cfe#3d6ef050%
On Scene--color-status-escena#ff5263#e8253b75%
Closed--color-status-cerrado#00d492#00a868100%
Platform

Vertical Toolbar

Width: 56px (collapsed) / 200px (expanded). Item height: 44px. Active: primary-subtle bg + 2px left border. Icons: 18×18px.

Collapsed State (56px)

Preview
Platform

Incident Card

Core Kanban tile — k1-inc component. Full anatomy: status pill + type tags + zone tag · title (13px/700) · address (11px/400) · timer + action button + case-ID link · 4px progress bar · priority chip + avatar + incident number. Radius: 8px. Padding: 10px 12px. Gap between zones: 6px.

Anatomy — Zone Breakdown

Each card is a flex column with six distinct zones. Every zone has a fixed token mapping.

Annotated card
On Scene Fire Roma Norte
Fire
Calle Durango, Roma Norte
504:01:02 P-12 / A-03
Progress
75%
ZoneClassToken / value
Status pillk1-status k1-status-*--color-status-* · 10px/700
Type tagk1-inc-tag k1-inc-tag-*Semantic color · 10px/700
Zone tagk1-inc-tag k1-inc-tag-zone--color-text-3 · border
Titlek1-inc-title13px / 700 / text-1
Addressk1-inc-addr11px / 400 / text-2
Timerk1-inc-timer11px / 600 / tabular-nums
Unitsk1-inc-units10px / text-3
Action btnk1-inc-actionprimary or error border+bg
Case IDk1-inc-caseid10px / primary / link
Progressk1-inc-prog-fill4px / --color-status-*
Priorityk1-priority k1-priority-*alta / media / baja
Avatark1-avatar k1-avatar-sm24px · surface-4 bg
Numberk1-inc-num10px / 700 / text-3

Card States — Default · Active · Closed

Hover over cards to see hover state
Default
ReviewMedical EmergencySanta Fe
Medical Emergency
Av. Vasco de Quiroga, Santa Fe
503:49:02
Progress
25%
Active (selected)
AssignedVehicle TheftMixcoac
Vehicle Theft
Blvd. Adolfo López Mateos, Mixcoac
504:11:02P-09 / SSC-Al…
Progress
50%
Closed (muted 0.6)
ClosedIncidentRoma Norte
Incident
Calle Mérida, Roma Norte
506:01:02B-01C5/20260407/00049
Progress
100%

Action Button Variants — Per Workflow Stage

Hover to see fill state
Utilities

Avatars

Sizes: 24/32/40/48px. Status dot: 8×8px, bottom-right, 2px border (surface-2). Font weight: 700. Letter color: --color-primary.

Sizes & States

Preview
GL
sm · 24px
HM
md · 32px
LP
lg · 40px
OP
xl · 48px
ON
Online
ID
Idle
OF
Offline
Utilities

Feedback & Loading

Skeleton: shimmer animation at 1.5s cycle. Progress track: 6px height, radius-full. Empty state: centered, muted palette.

Skeleton Loader

Animated

Progress Bar

Preview
Incidentes resueltos74%
Recursos desplegados60%
Carga del sistema38%
Utilities

Tooltip

From Figma: 06 Feedback / 02 Tooltip. Two themes: Light (white) and Dark. Four positions: bottom ↓, top ↑, right →, left ←. Font: Public Sans 14px/400. Padding: 12px 16px. Radius: 8px. Max-width: 240px.

Light & Dark Themes

Figma specifies two distinct tooltip themes. Light uses a white background with dark text (#131523). Dark uses a near-black surface (#131523) with white text. Hover the trigger buttons below.

Hover each button to trigger · Light theme
Bottom ↓
Tooltip text goes here
Top ↑
Tooltip text goes here
Right →
Tooltip text goes here
Left ←
Tooltip text goes here
Hover each button to trigger · Dark theme
Bottom ↓
Tooltip text goes here
Top ↑
Tooltip text goes here
Right →
Tooltip text goes here
Left ←
Tooltip text goes here

Tooltip Tokens — Pixel Spec

All values extracted directly from Figma. Every property is a strict token — no raw values in component CSS.

PropertyLight ThemeDark ThemeToken / Value
Background#ffffff#131523Figma exact — not using surface tokens
Text color#131523#ffffffFigma exact
FontPublic Sansvar(--font)
Font size14pxvar(--text-md)
Font weight400 (Regular)var(--fw-regular)
Line height20pxFigma: leading-[20px]
Padding12px 16pxvar(--space-3) var(--space-4)
Border radius8pxvar(--radius-md)
Max width240pxHardcoded max-width
Arrow size6pxCSS border trick
Gap to trigger10pxcalc(100% + 10px)
Shadowmdvar(--shadow-md)
Transitionopacity + transform0.15s ease

Platform Usage in K1

Tooltips appear on icon-only toolbar buttons, header action icons, and table cell overflows. Use Dark theme on the kanban/dark backgrounds, Light on white card surfaces.

Toolbar context — Dark tooltip on dark background
Ver Mapa
CCTV
Kanban Board

CSS Implementation

CSS — Tooltip classes
/* ── Tooltip wrapper (position: relative context) ── */
.k1-tooltip-wrap {
  position: relative;
  display: inline-flex;
}

/* ── Base bubble ── */
.k1-tooltip {
  position: absolute;
  z-index: 500;
  max-width: 240px;
  padding: var(--space-3) var(--space-4);   /* 12px 16px */
  border-radius: var(--radius-md);           /* 8px */
  font-family: var(--font);
  font-size: var(--text-md);                 /* 14px */
  font-weight: var(--fw-regular);
  line-height: 20px;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.15s ease, transform 0.15s ease;
  white-space: normal;
}

/* ── Themes ── */
.k1-tooltip-light {
  background: #ffffff;
  color: #131523;
  box-shadow: var(--shadow-md);
  border: 1px solid var(--color-border);
}
.k1-tooltip-dark {
  background: #131523;
  color: #ffffff;
  box-shadow: var(--shadow-md);
}

/* ── Arrow ── */
.k1-tooltip::after {
  content: '';
  position: absolute;
  width: 0; height: 0;
  border: 6px solid transparent;
}

/* ── Position: bottom (arrow at bottom of bubble) ── */
.k1-tooltip-bottom { bottom: calc(100% + 10px); left: 50%; transform: translateX(-50%) translateY(4px); }
.k1-tooltip-bottom::after { top: 100%; left: 50%; transform: translateX(-50%); }
.k1-tooltip-light.k1-tooltip-bottom::after { border-top-color: #ffffff; }
.k1-tooltip-dark.k1-tooltip-bottom::after  { border-top-color: #131523; }

/* ── Position: top (arrow at top of bubble) ── */
.k1-tooltip-top { top: calc(100% + 10px); left: 50%; transform: translateX(-50%) translateY(-4px); }
.k1-tooltip-top::after { bottom: 100%; left: 50%; transform: translateX(-50%); }
.k1-tooltip-light.k1-tooltip-top::after { border-bottom-color: #ffffff; }
.k1-tooltip-dark.k1-tooltip-top::after  { border-bottom-color: #131523; }

/* ── Position: right ── */
.k1-tooltip-right { left: calc(100% + 10px); top: 50%; transform: translateY(-50%) translateX(-4px); }
.k1-tooltip-right::after { right: 100%; top: 50%; transform: translateY(-50%); }
.k1-tooltip-light.k1-tooltip-right::after { border-right-color: #ffffff; }
.k1-tooltip-dark.k1-tooltip-right::after  { border-right-color: #131523; }

/* ── Position: left ── */
.k1-tooltip-left { right: calc(100% + 10px); top: 50%; transform: translateY(-50%) translateX(4px); }
.k1-tooltip-left::after { left: 100%; top: 50%; transform: translateY(-50%); }
.k1-tooltip-light.k1-tooltip-left::after { border-left-color: #ffffff; }
.k1-tooltip-dark.k1-tooltip-left::after  { border-left-color: #131523; }

/* ── Show on hover ── */
.k1-tooltip-wrap:hover .k1-tooltip-bottom,
.k1-tooltip-wrap:hover .k1-tooltip-top {
  opacity: 1; transform: translateX(-50%) translateY(0);
}
.k1-tooltip-wrap:hover .k1-tooltip-right,
.k1-tooltip-wrap:hover .k1-tooltip-left {
  opacity: 1; transform: translateY(-50%) translateX(0);
}

Angular / PrimeNG — pTooltip Override

PrimeNG's pTooltip directive is the recommended integration. Override its generated classes to match K1 tokens exactly.

HTML — Angular template
<!-- pTooltip directive — 4 positions -->
<button
  pTooltip="Ver detalles del incidente"
  tooltipPosition="bottom"
  styleClass="k1-tooltip-dark"
  class="k1-btn k1-btn-icon-only k1-btn-ghost"
>
  <!-- icon -->
</button>

<!-- tooltipPosition options: bottom | top | right | left -->
<!-- styleClass: k1-tooltip-light (white bg) OR k1-tooltip-dark (dark bg) -->
SCSS — pTooltip override (add to primeng.scss)
/* Override PrimeNG tooltip to match K1 spec */
.p-tooltip .p-tooltip-text {
  font-family: var(--font);         /* Public Sans */
  font-size: var(--text-md);         /* 14px */
  font-weight: var(--fw-regular);    /* 400 */
  line-height: 20px;
  padding: var(--space-3) var(--space-4);  /* 12px 16px */
  border-radius: var(--radius-md);   /* 8px */
  max-width: 240px;
  box-shadow: var(--shadow-md);
}

/* Dark theme (default for K1 dark mode) */
.p-tooltip.k1-tooltip-dark .p-tooltip-text {
  background: #131523;
  color: #ffffff;
  border: 1px solid rgba(255,255,255,0.08);
}
.p-tooltip.k1-tooltip-dark.p-tooltip-bottom .p-tooltip-arrow  { border-bottom-color: #131523; }
.p-tooltip.k1-tooltip-dark.p-tooltip-top    .p-tooltip-arrow  { border-top-color: #131523; }
.p-tooltip.k1-tooltip-dark.p-tooltip-right  .p-tooltip-arrow  { border-right-color: #131523; }
.p-tooltip.k1-tooltip-dark.p-tooltip-left   .p-tooltip-arrow  { border-left-color: #131523; }

/* Light theme */
.p-tooltip.k1-tooltip-light .p-tooltip-text {
  background: #ffffff;
  color: #131523;
  border: 1px solid var(--color-border);
}
.p-tooltip.k1-tooltip-light.p-tooltip-bottom .p-tooltip-arrow { border-bottom-color: #ffffff; }
.p-tooltip.k1-tooltip-light.p-tooltip-top    .p-tooltip-arrow { border-top-color: #ffffff; }
.p-tooltip.k1-tooltip-light.p-tooltip-right  .p-tooltip-arrow { border-right-color: #ffffff; }
.p-tooltip.k1-tooltip-light.p-tooltip-left   .p-tooltip-arrow { border-left-color: #ffffff; }

Usage Rules

ContextThemePositionNotes
Toolbar iconsDarkRight →Always right — toolbar is on left edge
Header action buttonsDarkBottom ↓Header is at top — tooltip drops down
Form field hintsLightTop ↑Appears above field to not cover input
Table cell overflowDarkTop ↑Shows full text on truncated cells
Inline icon buttons (on cards)LightBottom ↓Light cards use light tooltip
Dispatch button (disabled)DarkTop ↑Explains why button is disabled
React / PrimeReact

PrimeReact Overrides

PrimeReact v10.x component overrides for KDispatch React product. CSS lives in src/design-system/k1-primereact-theme.css. Import once in main.tsx.

Token namespace: Code blocks below use kdispatch token names (--primary, --field-bg, --background, etc.) — NOT the --color-* prefix used inside this design system HTML. Copy as-is into your React project's src/design-system/ folder.

CSS Override Patterns

All overrides use K1 design tokens — no hardcoded hex values.

CSS — src/design-system/k1-primereact-theme.css
/* ── Dropdown ── */
.p-dropdown {
  height: var(--h-md);
  background: var(--field-bg);
  border: 1px solid var(--field-border);
  border-radius: var(--radius-md);
  font-family: var(--font);
  color: var(--field-text);
  transition: border-color 0.15s ease;
}
.p-dropdown:hover { border-color: var(--color-primary); }
.p-dropdown.p-focus { box-shadow: var(--focus-ring); border-color: var(--color-primary); outline: none; }

/* ── Dropdown Panel ── */
.p-dropdown-panel {
  background: var(--color-surface-2);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-panel);
}
.p-dropdown-item {
  font-family: var(--font);
  font-size: var(--text-base);
  color: var(--color-text-1);
  border-radius: var(--radius-sm);
  padding: 6px 10px;
}
.p-dropdown-item:hover,
.p-dropdown-item.p-highlight {
  background: var(--color-primary-subtle);
  color: var(--color-primary);
}

/* ── InputText ── */
.p-inputtext {
  height: var(--h-md);
  background: var(--field-bg);
  border: 1px solid var(--field-border);
  border-radius: var(--radius-md);
  font-family: var(--font);
  font-size: var(--text-base);
  color: var(--field-text);
  padding: 0 var(--space-3);
  width: 100%;
}
.p-inputtext:focus { box-shadow: var(--focus-ring); border-color: var(--color-primary); outline: none; }

/* ── Calendar / DatePicker ── */
.p-calendar .p-inputtext { width: 100%; }
.p-datepicker {
  background: var(--color-surface-2);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-panel);
}
.p-datepicker td > span:hover,
.p-datepicker td > span.p-highlight {
  background: var(--color-primary-subtle);
  color: var(--color-primary);
  border-radius: var(--radius-sm);
}

React Import & Usage

K1 wrapper components for PrimeReact primitives. Import from the design system components barrel.

TSX — component imports
// Design System components
import { K1Select, K1Input, K1Textarea, K1Number, K1DatePicker } from '@/design-system/components';

// K1Select — wraps PrimeReact Dropdown
<K1Select
  value={value}
  options={['Option A', 'Option B']}
  onChange={v => setValue(v)}
  placeholder="Select…"
/>

// With object options
<K1Select
  value={status}
  options={[
    { label: 'Active', value: 'active' },
    { label: 'Closed', value: 'closed' },
  ]}
  onChange={v => setStatus(v)}
/>

// K1Input
<K1Input value={val} onChange={e => setVal(e.target.value)} placeholder="Enter text…" />

// k1-status-pill variant (for status dropdowns)
<K1Select
  className="k1-status-pill"
  value={status}
  options={statusOptions}
  onChange={v => setStatus(v)}
  style={{ background: 'var(--color-primary)', color: '#fff' }}
/>

K1Select Props

Full props reference for the K1Select wrapper component.

Prop Type Description
valueanySelected value (controlled)
optionsstring[] | {label, value}[]List of options — strings or label/value pairs
onChange(v: any) => voidChange handler — receives the selected value directly
placeholderstringPlaceholder text when no value selected
classNamestringExtra CSS class — use k1-status-pill for pill style
styleCSSPropertiesInline styles — only use CSS custom properties
disabledbooleanDisables the dropdown

p-dialog → K1 Modal

PrimeReact Dialog override. Matches K1 overlay token values.

CSS — p-dialog
.p-dialog {
  background: var(--panel-bg);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  color: var(--text-primary);
}
.p-dialog .p-dialog-header {
  background: var(--panel-header-bg);
  border-bottom: 1px solid var(--border);
  padding: var(--space-4) var(--space-5);
  font-size: var(--text-lg); font-weight: var(--fw-semibold);
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
}
.p-dialog .p-dialog-content {
  padding: var(--space-5) var(--space-6);
  background: var(--panel-bg);
}
.p-dialog .p-dialog-footer {
  padding: var(--space-4) var(--space-5);
  border-top: 1px solid var(--border);
  display: flex; justify-content: flex-end; gap: var(--space-2);
}
.p-dialog-mask { background: var(--overlay-bg); }
.p-dialog .p-dialog-header-icon {
  color: var(--text-tertiary);
  &:hover { background: var(--chip); color: var(--text-primary); }
}

p-toast → K1 Toast

Toast notifications. Position bottom-right. Auto-dismiss after 4s.

CSS — p-toast
.p-toast .p-toast-message {
  background: var(--panel-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  color: var(--text-primary);
}
.p-toast .p-toast-message.p-toast-message-success {
  border-color: var(--success);
  border-left: 3px solid var(--success);
}
.p-toast .p-toast-message.p-toast-message-error {
  border-left: 3px solid var(--error);
}
.p-toast .p-toast-message.p-toast-message-warn {
  border-left: 3px solid var(--warning);
}
.p-toast .p-toast-message-content {
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-base);
}

p-datatable → K1 Table

DataTable used in AdminDashboard, incident logs, unit rosters. Critical for kdispatch.

CSS — p-datatable (kdispatch)
.p-datatable { border-radius: var(--radius-lg); overflow: hidden; }
.p-datatable .p-datatable-thead > tr > th {
  background: var(--panel-header-bg);
  color: var(--text-tertiary);
  font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px;
  padding: var(--space-2) var(--space-4);
  border-bottom: 1px solid var(--border);
}
.p-datatable .p-datatable-tbody > tr {
  background: var(--row-bg);
  border-bottom: 1px solid var(--border);
  transition: background 0.10s;
  &:hover { background: var(--row-hover); }
}
.p-datatable .p-datatable-tbody > tr > td {
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-base); color: var(--text-primary);
  border: none;
}
.p-paginator {
  background: var(--panel-bg);
  border-top: 1px solid var(--border);
  padding: var(--space-2) var(--space-4);
}
.p-paginator .p-paginator-page.p-highlight {
  background: var(--primary);
  color: #fff; border-radius: var(--radius-sm);
}

p-tag & p-chip → K1 Badge

Replace PrimeReact's default tag/chip colors with K1 semantic palette.

CSS — p-tag / p-chip
.p-tag {
  font-size: var(--text-xs); font-weight: 600; border-radius: var(--radius-sm);
  padding: 2px var(--space-2); border: 1px solid transparent;
}
.p-tag.p-tag-success { background: var(--success-subtle-bg); color: var(--success); border-color: var(--success-subtle-border); }
.p-tag.p-tag-warning { background: var(--warning-subtle-bg); color: var(--warning); border-color: var(--warning-subtle-border); }
.p-tag.p-tag-danger  { background: var(--error-subtle-bg);   color: var(--error);   border-color: var(--error-subtle-border); }
.p-tag.p-tag-info    { background: var(--color-primary-subtle); color: var(--primary); }

.p-chip {
  background: var(--chip);
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  color: var(--text-secondary);
  font-size: var(--text-xs); height: 24px; padding: 0 var(--space-2);
}
React / PrimeReact

React Patterns

KDispatch React architecture patterns. All components use CSS custom properties — zero hardcoded hex.

Token Usage Rule

Always reference tokens. Never hardcode color values in component style props or CSS files.

Correct vs Incorrect
color: 'var(--color-primary)' References the design token
color: '#2b7fff' Hardcoded — breaks theme switching

Theme Switching

Set data-theme on the <html> element. All tokens update automatically — no JS color recalculation needed.

TSX — theme toggle
// Set dark mode
document.documentElement.setAttribute('data-theme', 'dark');

// Set light mode
document.documentElement.setAttribute('data-theme', 'light');

// React hook example
const useTheme = () => {
  const [theme, setTheme] = useState<'dark' | 'light'>('dark');
  useEffect(() => {
    document.documentElement.setAttribute('data-theme', theme);
  }, [theme]);
  return { theme, setTheme };
};

Form Field Pattern

Standard labelled field with K1Input. Use this structure for all form fields.

TSX — labelled field
<div className="k1-field">
  <label className="k1-label" htmlFor="incident-title">
    Incident Title <span className="k1-required">*</span>
  </label>
  <K1Input
    id="incident-title"
    value={title}
    onChange={e => setTitle(e.target.value)}
    placeholder="e.g. Traffic accident on Av. Principal"
  />
  {error && <span className="k1-field-error">{error}</span>}
</div>

Status Badge Pattern

Use K1Select with the k1-status-pill class and inline color from status tokens for editable status badges.

TSX — status pill dropdown
const STATUS_COLORS: Record<string, string> = {
  nuevo:    'var(--status-nuevo-bg)',
  revision: 'var(--status-revision-bg)',
  asignado: 'var(--status-asignado-bg)',
  escena:   'var(--status-escena-bg)',
  cerrado:  'var(--status-cerrado-bg)',
};

<K1Select
  className="k1-status-pill"
  value={status}
  options={statusOptions}
  onChange={v => setStatus(v)}
  style={{ background: STATUS_COLORS[status] }}
/>

Admin Layout Pattern

Standard flex structure used in AdminDashboardView — fixed sidebar + flex-1 content area.

TSX — admin layout
<div style={{ display: 'flex', height: '100vh', overflow: 'hidden' }}>
  {/* Sidebar — fixed 210px */}
  <aside style={{
    width: '210px',
    flexShrink: 0,
    background: 'var(--sidebar-bg)',
    borderRight: '1px solid var(--color-border)',
    display: 'flex',
    flexDirection: 'column',
    overflowY: 'auto',
  }}>
    <SidebarNav />
  </aside>

  {/* Main content — flex-1 */}
  <main style={{
    flex: 1,
    display: 'flex',
    flexDirection: 'column',
    overflow: 'hidden',
    background: 'var(--color-bg)',
  }}>
    <HeaderBar />
    <div style={{ flex: 1, overflowY: 'auto', padding: 'var(--space-6)' }}>
      <Outlet />
    </div>
  </main>
</div>
Angular / PrimeNG

PrimeNG Overrides

Maps each PrimeNG component to the K1 system. All overrides use CSS custom properties — no hardcoded values in component-specific CSS.

Token namespace: Code blocks below use K1 design system HTML tokens (--color-primary, --color-surface-*, etc.). When integrating into your Angular project, add the full token file from the Design Tokens page and use those variable names directly.

Global PrimeNG Reset

Add to styles.scss or primeng.css. This establishes the K1 base for all PrimeNG components.

SCSS — styles.scss (global)
/* ── K1 PrimeNG Base Override ── */
:root {
  /* Map PrimeNG theme vars to K1 tokens */
  --primary-color:      var(--color-primary);
  --primary-color-text: #ffffff;
  --surface-0:  var(--color-bg);
  --surface-50: var(--color-surface-1);
  --surface-100:var(--color-surface-2);
  --surface-200:var(--color-surface-3);
  --surface-300:var(--color-surface-4);
  --text-color:        var(--color-text-1);
  --text-color-secondary:var(--color-text-2);
  --border-radius:     var(--radius-md);
  --focus-ring:        var(--focus-ring);
}

/* Force Public Sans on all PrimeNG elements */
.p-component { font-family: var(--font) !important; }
.p-inputtext { font-family: var(--font) !important; }
.p-button    { font-family: var(--font) !important; }
.p-dropdown  { font-family: var(--font) !important; }
.p-datatable { font-family: var(--font) !important; }

p-button → k1-btn

p-button → .k1-btn
SCSS
/* Remove ALL PrimeNG button defaults */
.p-button {
  all: unset;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  height: var(--h-lg);             /* 40px */
  padding: 0 var(--space-4);        /* 0 16px */
  border-radius: var(--radius-md);  /* 8px */
  font-family: var(--font);
  font-size: var(--text-md);        /* 14px */
  font-weight: var(--fw-medium);    /* 500 */
  background: var(--color-primary);
  color: #fff;
  border: 1px solid transparent;
  transition: background 0.12s, box-shadow 0.12s;
  white-space: nowrap;

  &:hover  { background: var(--color-primary-hover); }
  &:focus  { outline: none; box-shadow: var(--focus-ring); }
  &:active { background: var(--color-primary-active); }

  &.p-button-secondary {
    background: var(--color-surface-4);
    color: var(--color-text-1);
    border-color: var(--color-border);
    &:hover { background: var(--color-surface-3); }
  }

  &.p-button-outlined {
    background: transparent;
    color: var(--color-text-1);
    border-color: var(--color-border-strong);
    &:hover { background: var(--color-surface-2); }
  }

  &:disabled {
    opacity: 0.4;
    pointer-events: none;
  }
}

/* Small variant */
.p-button.p-button-sm {
  height: var(--h-sm);    /* 32px */
  padding: 0 var(--space-3); /* 0 12px */
  font-size: var(--text-sm); /* 12px */
  border-radius: var(--radius-sm);
}

p-inputText / p-dropdown

p-inputText → .k1-input
SCSS
.p-inputtext {
  height: var(--h-md);               /* 36px */
  padding: 0 var(--space-3);          /* 0 12px */
  border-radius: var(--radius-md);    /* 8px */
  border: 1px solid var(--color-border);
  background: var(--color-surface-3);
  color: var(--color-text-1);
  font-family: var(--font);
  font-size: var(--text-base);        /* 13px */
  font-weight: var(--fw-regular);
  transition: border-color 0.12s, box-shadow 0.12s;
  box-shadow: none;

  &::placeholder { color: var(--color-text-3); }
  &:enabled:hover  { border-color: var(--color-border-strong); }
  &:enabled:focus  { border-color: var(--color-primary); box-shadow: var(--focus-ring); }
  &.ng-invalid.ng-dirty { border-color: var(--color-error); }
}

/* p-dropdown wrapper */
.p-dropdown {
  height: var(--h-md);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface-3);

  .p-dropdown-label { font-family: var(--font); font-size: var(--text-base); }
  .p-dropdown-panel { background: var(--color-surface-2); border: 1px solid var(--color-border-strong); border-radius: var(--radius-md); box-shadow: var(--shadow-md); }
  .p-dropdown-item  { font-family: var(--font); font-size: var(--text-base); padding: var(--space-2) var(--space-3); }
  .p-dropdown-item:hover { background: var(--color-surface-4); }
  .p-dropdown-item.p-highlight { background: var(--color-primary-subtle); color: var(--color-primary); }
}

p-table

p-table → K1 table styles
SCSS
.p-datatable {
  .p-datatable-thead > tr > th {
    background: var(--color-surface-2);
    color: var(--color-text-3);
    font-family: var(--font);
    font-size: 10px;
    font-weight: var(--fw-bold);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    padding: var(--space-2) var(--space-4);
    border-bottom: 1px solid var(--color-border);
  }
  .p-datatable-tbody > tr > td {
    font-family: var(--font);
    font-size: var(--text-base);
    padding: var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--color-border);
    color: var(--color-text-2);
  }
  .p-datatable-tbody > tr:hover > td {
    background: var(--color-surface-3);
  }
  .p-datatable-tbody > tr.p-highlight > td {
    background: var(--color-primary-subtle);
  }
}

p-dialog

p-dialog → K1 panel style
SCSS
.p-dialog {
  background: var(--color-surface-2);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-lg);
  font-family: var(--font);

  .p-dialog-header {
    padding: var(--space-5) var(--space-6);
    border-bottom: 1px solid var(--color-border);
    font-size: var(--text-lg);
    font-weight: var(--fw-bold);
    color: var(--color-text-1);
  }
  .p-dialog-content { padding: var(--space-6); }
  .p-dialog-footer  {
    padding: var(--space-4) var(--space-6);
    border-top: 1px solid var(--color-border);
    display: flex;
    justify-content: flex-end;
    gap: var(--space-2);
  }
}

.p-dialog-mask { background: rgba(0,0,0,0.6); backdrop-filter: blur(4px); }

p-toast → K1 Toast

PrimeNG Toast notifications — override to match K1 semantic colors exactly.

SCSS — p-toast
.p-toast .p-toast-message {
  background: var(--color-surface-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  color: var(--color-text-1);
}
.p-toast .p-toast-message.p-toast-message-success { border-left: 3px solid var(--color-success); }
.p-toast .p-toast-message.p-toast-message-error   { border-left: 3px solid var(--color-error);   }
.p-toast .p-toast-message.p-toast-message-warn    { border-left: 3px solid var(--color-warning); }
.p-toast .p-toast-message.p-toast-message-info    { border-left: 3px solid var(--color-info);    }
.p-toast .p-toast-message-content { padding: var(--space-3) var(--space-4); font-size: var(--text-base); }

p-table → K1 DataTable

Angular DataTable for admin views, incident logs, and unit rosters. Compact row height.

SCSS — p-table
.p-datatable { border-radius: var(--radius-lg); overflow: hidden; }
.p-datatable .p-datatable-thead > tr > th {
  background: var(--color-surface-4);
  color: var(--color-text-3);
  font-size: 10px; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.5px; padding: var(--space-2) var(--space-4);
  border-bottom: 1px solid var(--color-border);
}
.p-datatable .p-datatable-tbody > tr {
  background: var(--color-surface-1);
  border-bottom: 1px solid var(--color-border);
  transition: background 0.10s;
  &:hover { background: var(--color-surface-3); }
}
.p-datatable .p-datatable-tbody > tr > td {
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-base); color: var(--color-text-1);
  border: none;
}
.p-paginator {
  background: var(--color-surface-2);
  border-top: 1px solid var(--color-border);
  padding: var(--space-2) var(--space-4);
}
.p-paginator .p-paginator-page.p-highlight {
  background: var(--color-primary);
  color: #fff; border-radius: var(--radius-sm);
}

p-tag & p-chip → K1 Badge / Chip

PrimeNG tag and chip components mapped to K1 semantic colors.

SCSS — p-tag / p-chip
.p-tag {
  font-size: var(--text-xs); font-weight: 600;
  border-radius: var(--radius-sm); padding: 2px var(--space-2);
  border: 1px solid transparent;
}
.p-tag.p-tag-success { background: var(--color-success-subtle); color: var(--color-success); border-color: var(--color-success-border); }
.p-tag.p-tag-warning { background: var(--color-warning-subtle); color: var(--color-warning); border-color: var(--color-warning-border); }
.p-tag.p-tag-danger  { background: var(--color-error-subtle);   color: var(--color-error);   border-color: var(--color-error-border); }
.p-tag.p-tag-info    { background: var(--color-primary-subtle); color: var(--color-primary); }

.p-chip {
  background: rgba(255,255,255,0.06);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  color: var(--color-text-2);
  font-size: var(--text-xs); height: 24px; padding: 0 var(--space-2);
}
Angular / PrimeNG

Angular Patterns

Component naming, module structure, and template patterns for K1 Angular implementation.

CSS Architecture

Project structure
src/
  styles/
    tokens.css         # CSS custom properties (copy from Tokens page)
    primeng.scss       # PrimeNG overrides (copy from PrimeNG page)
    components.css     # k1-btn, k1-input, k1-badge, k1-card, etc.
    global.scss        # @import all of the above

  app/
    components/
      k1-button/       # Wraps p-button with K1 defaults
      k1-input/        # Wraps pInputText + k1-field + k1-label
      k1-badge/        # Status / resource / generic badge
      k1-incident-card/# Kanban tile with all states
      k1-kanban/       # Board container + columns
      k1-toolbar/      # Vertical sidebar toolbar
      k1-header/       # App header bar with clock

angular.json — Styles

JSON — angular.json
"styles": [
  "node_modules/primeng/resources/themes/lara-dark-blue/theme.css",
  "node_modules/primeng/resources/primeng.min.css",
  "node_modules/primeicons/primeicons.css",
  "src/styles/tokens.css",      // K1 tokens
  "src/styles/components.css",  // K1 component classes
  "src/styles/primeng.scss",    // PrimeNG overrides (LAST — highest specificity)
  "src/styles.scss"
]

K1Input Component Pattern

TypeScript — k1-input.component.ts
@Component({
  selector: 'k1-input',
  template: `
    <div class="k1-field">
      <label class="k1-label" *ngIf="label">
        {{ label }}
        <span style="color:var(--color-error)" *ngIf="required"> *</span>
      </label>
      <div [class.k1-input-icon-wrap]="iconLeft">
        <ng-content select="[slot=icon-left]"></ng-content>
        <input
          pInputText
          [class.k1-input]="true"
          [class.is-error]="control?.invalid && control?.touched"
          [placeholder]="placeholder"
          [disabled]="disabled"
          [formControl]="control"
        />
      </div>
      <span class="k1-error" *ngIf="control?.invalid && control?.touched">
        {{ errorMessage }}
      </span>
      <span class="k1-hint" *ngIf="hint && !control?.invalid">{{ hint }}</span>
    </div>
  `
})
export class K1InputComponent {
  @Input() label = '';
  @Input() placeholder = '';
  @Input() hint = '';
  @Input() errorMessage = 'Campo requerido';
  @Input() required = false;
  @Input() disabled = false;
  @Input() iconLeft = false;
  @Input() control!: FormControl;
}

Component Class Naming Rules

PatternExampleRule
k1-{component}k1-btn, k1-cardBase component
k1-{comp}-{variant}k1-btn-primaryVisual variant
k1-{comp}-{size}k1-btn-sm, k1-avatar-mdSize modifier
is-{state}is-active, is-error, is-onJS-toggled state (Angular class binding)
--color-{name}--color-primaryCSS token — always use token, never raw value