@hotelfriendag/design-tokens 0.3.4 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -134,6 +134,12 @@ App code should reference **semantic** tokens (`accent`, `fg`, `bg-*`, `border`,
134
134
 
135
135
  | Class | Anatomy | See |
136
136
  |---|---|---|
137
+ | `.hf-btn` + `--primary` / `--danger` / `--outline-primary` / `--outline-default` / `--cancel` (sizes `--sm` / `--icon`) | Buttons — 40px h, 6px radius, token-driven chrome | components.html#buttons |
138
+ | `.hf-input` / `.hf-textarea` / `.hf-select` (+ `.hf-select-wrap`) | Form controls — 39px h, accent focus ring, token caret | components.html#inputs |
139
+ | `.hf-form-field` + `__label` / `__hint` / `__error` (`--required`, `--error`) | Field wrapper — label + control + hint/error | components.html#inputs |
140
+ | `.hf-switch` | Toggle — styled checkbox, 40×22 track, accent when on | components.html#inputs |
141
+ | `.hf-card` + `__header/__title/__description/__body/__footer` (`--flat`) | Elevated card — 12px radius, card shadow | components.html#cards |
142
+ | `.hf-drawer` + `__backdrop/__panel/__header/__body/__footer` (`--left`) | Side-panel — backdrop + sliding panel | components.html#layout |
137
143
  | `.hf-pill` + `.status-{domain}-{state}` | Status badge — 6px radius, 15% bg + 100% text + 1px border | components.html#status |
138
144
  | `.hf-tab` / `.hf-tab--sm` / `.hf-pill-tabs` | Underline + segmented tabs | components.html#tabs |
139
145
  | `.hf-pagination` + `__item` / `__ellipsis` | Subtle gray active (NOT accent!) — 34×34, 8px radius | components.html#pagination |
@@ -142,9 +148,234 @@ App code should reference **semantic** tokens (`accent`, `fg`, `bg-*`, `border`,
142
148
  | `.hf-alert--tinted` / `--banner` / `--compact` | Modifiers — bg tint / full-width strip / compact-in-card | components.html#alerts |
143
149
  | `.hf-toast` | Floating notification — 9px radius | components.html#alerts |
144
150
  | `.hf-check` / `.hf-radio` | Custom checkbox+radio — 18×18, filled accent on check | components.html#inputs |
145
- | `.hf-dropdown-menu` + `__item / __header / __shortcut / __icon / __divider` | 9px radius dropdown, portal shadow | components.html#dropdown |
151
+ | `.hf-dropdown-menu` + `__header / __item / __item-icon / __shortcut / __divider` (+ `__item--danger`) | 9px radius dropdown, portal shadow (legacy flat `.hf-dropdown-{header\|item\|divider}` kept as deprecated aliases) | components.html#dropdown |
146
152
  | `.skeleton` + `.hf-spin` | Loading-state primitives (shimmer + rotation keyframes) | components.html#empty |
147
153
 
154
+ ## Usage examples
155
+
156
+ Copy-paste markup for the main `.hf-*` components — framework-agnostic (works in HTML, Vue, JSX; swap `class`/`className`). Icons are illustrative; wire your own (Lucide, etc.).
157
+
158
+ ### Status pill
159
+
160
+ ```html
161
+ <span class="hf-pill status-booking-confirmed">Confirmed</span>
162
+ <span class="hf-pill status-order-waiting">Waiting</span>
163
+ <span class="hf-pill status-room-item-cleaning-dirty">Dirty</span>
164
+ ```
165
+
166
+ ### Tabs
167
+
168
+ ```html
169
+ <div class="flex border-b border-hf-border">
170
+ <button class="hf-tab is-active">Overview</button>
171
+ <button class="hf-tab">Bookings <span class="hf-tab__count">12</span></button>
172
+ <button class="hf-tab">Guests</button>
173
+ <button class="hf-tab" disabled>Reports</button>
174
+ </div>
175
+ <!-- compact sub-filter variant: add .hf-tab--sm -->
176
+ ```
177
+
178
+ ### Pagination
179
+
180
+ ```html
181
+ <div class="hf-pagination">
182
+ <button class="hf-pagination__item" disabled aria-label="Previous">‹</button>
183
+ <button class="hf-pagination__item is-active">1</button>
184
+ <button class="hf-pagination__item">2</button>
185
+ <button class="hf-pagination__item">3</button>
186
+ <span class="hf-pagination__ellipsis">…</span>
187
+ <button class="hf-pagination__item">12</button>
188
+ <button class="hf-pagination__item" aria-label="Next">›</button>
189
+ </div>
190
+ ```
191
+
192
+ ### Modal
193
+
194
+ ```html
195
+ <div class="hf-modal max-w-[500px] mx-auto">
196
+ <div class="hf-modal__header">
197
+ <h2 class="hf-modal__title">Edit Guest</h2>
198
+ <button class="hf-modal__close" aria-label="Close">✕</button>
199
+ </div>
200
+ <div class="hf-modal__body">…</div>
201
+ <div class="hf-modal__footer">
202
+ <button class="hf-btn hf-btn--cancel">Cancel</button>
203
+ <button class="hf-btn hf-btn--primary">Save</button>
204
+ </div>
205
+ </div>
206
+ <!-- footer with top border: add .hf-modal--with-footer-border on .hf-modal -->
207
+ ```
208
+
209
+ ### Alert
210
+
211
+ ```html
212
+ <div class="hf-alert hf-alert--success">
213
+ <div class="hf-alert__icon"><!-- icon svg --></div>
214
+ <div class="hf-alert__body">
215
+ <div class="hf-alert__title">Saved successfully</div>
216
+ <p class="hf-alert__text">Booking #1284 has been updated.</p>
217
+ </div>
218
+ <button class="hf-alert__close" aria-label="Dismiss">✕</button>
219
+ </div>
220
+ <!-- variants: --success | --info | --warn | --error · modifiers: --tinted | --banner | --compact -->
221
+ ```
222
+
223
+ ### Toast
224
+
225
+ ```html
226
+ <div class="hf-toast">
227
+ <span class="hf-toast__icon"><!-- icon svg --></span>
228
+ <span class="hf-toast__text">Booking <strong>#2841</strong> confirmed</span>
229
+ <button class="hf-toast__close" aria-label="Dismiss">✕</button>
230
+ </div>
231
+ ```
232
+
233
+ ### Dropdown menu
234
+
235
+ ```html
236
+ <div class="hf-dropdown-menu w-52">
237
+ <div class="hf-dropdown-menu__header">Actions</div>
238
+ <div class="hf-dropdown-menu__item">View details</div>
239
+ <div class="hf-dropdown-menu__item">Edit <span class="hf-dropdown-menu__shortcut">⌘E</span></div>
240
+ <div class="hf-dropdown-menu__item is-disabled">Refresh</div>
241
+ <div class="hf-dropdown-menu__divider"></div>
242
+ <div class="hf-dropdown-menu__item hf-dropdown-menu__item--danger">Delete</div>
243
+ </div>
244
+ <!-- pre-0.4 flat names (.hf-dropdown-header / -item / -divider) still work as deprecated aliases -->
245
+ ```
246
+
247
+ ### Checkbox & radio
248
+
249
+ ```html
250
+ <input type="checkbox" class="hf-check" checked />
251
+ <input type="checkbox" class="hf-check" disabled />
252
+ <input type="radio" name="grp" class="hf-radio" checked />
253
+ ```
254
+
255
+ ### Buttons
256
+
257
+ ```html
258
+ <button class="hf-btn hf-btn--primary">Save</button>
259
+ <button class="hf-btn hf-btn--outline-primary">Preview</button>
260
+ <button class="hf-btn hf-btn--outline-default">Settings</button>
261
+ <button class="hf-btn hf-btn--cancel">Cancel</button>
262
+ <button class="hf-btn hf-btn--danger">Delete</button>
263
+ <button class="hf-btn hf-btn--primary hf-btn--sm">Small</button>
264
+ <button class="hf-btn hf-btn--icon hf-btn--outline-default" aria-label="Edit">✎</button>
265
+ ```
266
+
267
+ ### Form controls & field
268
+
269
+ ```html
270
+ <div class="hf-form-field">
271
+ <label class="hf-form-field__label hf-form-field__label--required">Email</label>
272
+ <input type="email" class="hf-input" placeholder="guest@example.com" />
273
+ <span class="hf-form-field__hint">We'll never share it.</span>
274
+ </div>
275
+
276
+ <div class="hf-form-field hf-form-field--error">
277
+ <label class="hf-form-field__label">Room</label>
278
+ <div class="hf-select-wrap">
279
+ <select class="hf-select">
280
+ <option>Deluxe</option>
281
+ <option>Suite</option>
282
+ </select>
283
+ </div>
284
+ <span class="hf-form-field__error">Please choose a room.</span>
285
+ </div>
286
+
287
+ <textarea class="hf-textarea" placeholder="Notes…"></textarea>
288
+
289
+ <!-- toggle: a styled checkbox -->
290
+ <input type="checkbox" class="hf-switch" checked />
291
+ ```
292
+
293
+ ### Card
294
+
295
+ ```html
296
+ <section class="hf-card">
297
+ <header class="hf-card__header">
298
+ <div>
299
+ <h3 class="hf-card__title">Channel settings</h3>
300
+ <p class="hf-card__description">Enable the sales channels for this property.</p>
301
+ </div>
302
+ <button class="hf-btn hf-btn--outline-default hf-btn--sm">Edit</button>
303
+ </header>
304
+ <div class="hf-card__body">…</div>
305
+ <footer class="hf-card__footer">
306
+ <button class="hf-btn hf-btn--cancel">Cancel</button>
307
+ <button class="hf-btn hf-btn--primary">Save</button>
308
+ </footer>
309
+ </section>
310
+ <!-- borderless/flat variant: add .hf-card--flat -->
311
+ ```
312
+
313
+ ### Drawer (side-panel)
314
+
315
+ ```html
316
+ <div class="hf-drawer">
317
+ <div class="hf-drawer__backdrop"></div>
318
+ <aside class="hf-drawer__panel">
319
+ <header class="hf-drawer__header">
320
+ <h2 class="hf-drawer__title">Reservation #2841</h2>
321
+ <button class="hf-drawer__close" aria-label="Close">✕</button>
322
+ </header>
323
+ <div class="hf-drawer__body">…</div>
324
+ <footer class="hf-drawer__footer">
325
+ <button class="hf-btn hf-btn--cancel">Close</button>
326
+ <button class="hf-btn hf-btn--primary">Check in</button>
327
+ </footer>
328
+ </aside>
329
+ </div>
330
+ <!-- slide from the left: add .hf-drawer--left on .hf-drawer -->
331
+ ```
332
+
333
+ ## Cheat-sheet — common tokens & utilities
334
+
335
+ Tailwind v4 derives utilities from the `@theme` tokens (`bg-hf-*`, `text-hf-*`, `rounded-hf-*`, `shadow-hf-*`). Vanilla CSS uses the `var(--color-hf-*)` form; SCSS uses `$colorAccent`, `$radiusSm`, … See [`UI_DESIGN.md`](UI_DESIGN.md) §9 for the full token list.
336
+
337
+ **Brand & text color**
338
+
339
+ | Utility | Token | Value |
340
+ |---|---|---|
341
+ | `bg-hf-accent` / `text-hf-accent` | `--color-hf-accent` | `#24AFE8` (brand) |
342
+ | `hover:bg-hf-accent-hover` | `--color-hf-accent-hover` | `#149AD1` |
343
+ | `bg-hf-accent-subtle` / `-subtler` | `--color-hf-accent-subtle` | light tints |
344
+ | `text-hf-fg` | `--color-hf-fg` | body `#2B2B2B` |
345
+ | `text-hf-fg-muted` / `-subtle` / `-faint` | `--color-hf-fg-*` | secondary → placeholder |
346
+ | `text-hf-on-accent` | `--color-hf-on-accent` | `#FFFFFF` (text on accent) |
347
+
348
+ **Surfaces & borders**
349
+
350
+ | Utility | Token |
351
+ |---|---|
352
+ | `bg-hf-bg-surface` | card / modal / popover (white) |
353
+ | `bg-hf-bg-page` / `-section` / `-muted` | page → section → muted grays |
354
+ | `border-hf-border` / `-subtle` / `-strong` | default → faint → hover border |
355
+
356
+ **Scales**
357
+
358
+ - **Text:** `text-hf-xs` 11 · `text-hf-sm` 13 · `text-hf-base` 14 · `text-hf-md` 15 · `text-hf-lg` 16 · `text-hf-xl` 18
359
+ - **Radius:** `rounded-hf-sm` 6 · `-md` 8 · `-lg` 9 · `-xl` 12 · `-pill` 99
360
+ - **Shadow:** `shadow-hf-subtle` · `shadow-hf-card` · `shadow-hf-modal` · `shadow-hf-hover`
361
+ - **Status:** `text-hf-status-{success|warning|error|info|cancel}` + `bg-hf-status-{…}-bg` — or just use `.hf-pill .status-{domain}-{state}`
362
+
363
+ ## Visual reference (live)
364
+
365
+ `components.html` is the canonical rendered showcase of every `.hf-*` component. The package is public on npm, so **unpkg serves it rendered in the browser** — no hosting needed:
366
+
367
+ **→ https://unpkg.com/@hotelfriendag/design-tokens/components.html**
368
+
369
+ Always serves the latest; pin a version with `…/design-tokens@0.4.0/components.html`. Or open the copy in your own project:
370
+
371
+ ```bash
372
+ open node_modules/@hotelfriendag/design-tokens/components.html # macOS
373
+ xdg-open node_modules/@hotelfriendag/design-tokens/components.html # Linux
374
+ start node_modules\@hotelfriendag\design-tokens\components.html # Windows
375
+ ```
376
+
377
+ > Use the **unpkg** link, not jsDelivr — jsDelivr serves `.html` as `text/plain` (shows source); unpkg serves it as `text/html` (renders).
378
+
148
379
  ## AI rules
149
380
 
150
381
  The package ships agent rules under `ai-rules/`. Drop one into the consumer's root so Claude / Cursor / Copilot follow the same UI rules:
package/UI_DESIGN.md CHANGED
@@ -241,6 +241,9 @@ box-shadow: 0 3px 4px rgba(0, 0, 0, 0.03);
241
241
 
242
242
  ### Buttons
243
243
 
244
+ > **Design-system API (v0.4+):** these portal recipes now ship as the `.hf-btn` primitive in `pre-built/components.css`. Use `.hf-btn` + a modifier in new code; the legacy portal classes below are the source these were extracted from:
245
+ > `.btn-primary`→`.hf-btn--primary` · `.btn-hf-outline-primary`→`.hf-btn--outline-primary` · neutral `.btn`→`.hf-btn--outline-default` · `.btn-cancel`→`.hf-btn--cancel` · `.btn-delete`→`.hf-btn--danger` · `.btn-sm`→`.hf-btn--sm` · icon-only→`.hf-btn--icon`.
246
+
244
247
  Live observation: 25+ unique button variants across 13 sidebar sections + 7 sub-tabs + 7 edit forms. Below is the canonical set; legacy variants (e.g. `btn.btn-b-gray`, `btn-text-blue`) exist but should be migrated.
245
248
 
246
249
  | Style | Class | Look |
@@ -445,19 +448,57 @@ These are the **canonical component classes** shipped in `pre-built/components.c
445
448
 
446
449
  ### `.hf-dropdown-menu` — Dropdown
447
450
  - **Anatomy:** 9px radius, white bg, `box-shadow: 0 1px 10px 0 rgba(0,0,0,.1)` (portal's `$dropdown_shadow`), 1px border `rgba(228,232,239,.6)`, padding `6px 0`, min-width 180px
448
- - **Children:**
451
+ - **Children** (canonical BEM, v0.4+):
449
452
  - `__header` — uppercase 11px/600 `#99A1B7` section label
450
453
  - `__item` — flex row, padding `8px 16px`, 14px text, gap 10px
451
- - `__item__icon` — 16px, color `#99A1B7` (faint), becomes `#50627E` on item hover
452
- - `__item__shortcut` — right-aligned 12px text (for ⌘keys or counts)
454
+ - `__item-icon` — 16px, color `#99A1B7` (faint), becomes `#50627E` on item hover
455
+ - `__shortcut` — right-aligned 12px text (for ⌘keys or counts)
453
456
  - `__divider` — 1px `#E4E8EF` separator
454
457
  - **Item states:**
455
458
  - Default → hover `bg: #F5F5F5`
456
459
  - `.is-active` → `bg: #EFF6FF; color: #24AFE8` (primary tint + primary text)
457
460
  - `:focus-visible` → outline 2px primary inset
458
- - `.danger` → red text, red-tint hover
461
+ - `__item--danger` → red text, red-tint hover
459
462
  - `.is-disabled` / `[aria-disabled="true"]` → `#AEBCCF` color, pointer-events none
460
- - **Reference:** `components.html#dropdown` · **Portal source:** `.dropdown-menu.open` in `_custom.scss` · **Decision:** 1:1 portal match for shadow/radius/colors. **Adapted:** uses flat `<div>` structure instead of Bootstrap 3 `<ul><li><a>` (modern, framework-agnostic).
463
+ - **Deprecated aliases (still work, remove in v1.0):** the pre-0.4 flat names `.hf-dropdown-header`, `.hf-dropdown-item`, `.hf-dropdown-item__icon`, `.hf-dropdown-item__shortcut`, `.hf-dropdown-divider`, `.hf-dropdown-item.danger`.
464
+ - **Reference:** `components.html#dropdown` · **Portal source:** `.dropdown-menu.open` in `_custom.scss` · **Decision:** 1:1 portal match for shadow/radius/colors. **Adapted:** uses flat `<div>` structure instead of Bootstrap 3 `<ul><li><a>` (modern, framework-agnostic); renamed to BEM children of `.hf-dropdown-menu` in v0.4 for consistency with `.hf-modal__*` / `.hf-alert__*`.
465
+
466
+ ### `.hf-btn` — Buttons (v0.4+)
467
+ - **Anatomy:** `inline-flex` center, height 40px, padding `0 20px`, 6px radius, 15px/600, `border: 1px solid transparent`, 200ms transitions. `:focus-visible` → 2px accent outline (offset 2px). `:disabled` / `.is-disabled` → opacity .6, not-allowed.
468
+ - **Variants:**
469
+ - `--primary` — accent bg, white text; hover `--color-hf-accent-hover` (`#149AD1`)
470
+ - `--danger` — `--color-hf-status-error-strong` (`#D9534F`) bg; hover `--color-hf-status-error-strong-hover` (`#C9302C`)
471
+ - `--outline-primary` — white bg, accent text + border; hover bg-muted
472
+ - `--outline-default` — white bg, steel text, neutral border, `--shadow-hf-outline`; hover bg-muted
473
+ - `--cancel` — transparent, muted text; hover bg-muted
474
+ - **Sizes/shapes:** `--sm` (32px / 14px), `--icon` (square — width = height), `--block` (full width)
475
+ - **Reference:** `components.html#buttons` · **Portal source:** `.btn-primary` / `.btn-hf-outline-*` / `.btn-cancel` / `.btn-delete` · **Decision:** consolidates 25+ portal button recipes into one base + modifiers. Compact portal-only families (reset-filters, icon-square) stay Tailwind-utility recipes until promoted.
476
+
477
+ ### `.hf-input` / `.hf-textarea` / `.hf-select` — Form controls (v0.4+)
478
+ - **Anatomy:** width 100%, height 39px, padding `0 12px`, 6px radius, 1px `--color-hf-input-border` (`#DBDFE9`), 14px text. Placeholder `--color-hf-fg-faint`.
479
+ - **Focus:** accent border + 3px `--color-hf-accent-subtle` ring (accessible — portal had no ring).
480
+ - **Disabled:** bg-muted, faint text, not-allowed.
481
+ - **Textarea:** auto height, min-height 80px, vertical resize.
482
+ - **Select:** `appearance:none` + wrapper `.hf-select-wrap` draws a token-colored caret (clip-path triangle, same technique as `.hf-pill--dd` — no data-URI, so no bare hex).
483
+ - **Reference:** `components.html#inputs` · **Portal source:** `.form-control` · **Decision:** 1:1 geometry; adds the accessible focus ring the portal lacks.
484
+
485
+ ### `.hf-switch` — Toggle (v0.4+)
486
+ - **Anatomy:** styled `<input type="checkbox">`, 40×22 track (999px radius), 18px white knob with `--shadow-hf-hover`. Off = `--color-hf-border`; `:checked` = accent bg + knob slides 18px right. `:focus-visible` outline; `:disabled` opacity .5.
487
+ - **Reference:** `components.html#inputs` · **Decision:** new lightweight token-driven primitive (portal shipped only a Bootstrap-Switch).
488
+
489
+ ### `.hf-form-field` — Field wrapper (v0.4+)
490
+ - **Anatomy:** `flex column gap 6px`. `__label` (14px/500), `__label--required::after` red `*`, `__hint` (13px subtle), `__error` (13px error).
491
+ - **State:** `--error` colours the contained `.hf-input` / `.hf-textarea` / `.hf-select` border + focus ring in `--color-hf-status-error`.
492
+ - **Reference:** `components.html#inputs` · **Decision:** new primitive — standardises label + control + hint/error so consumers stop re-inventing field structure.
493
+
494
+ ### `.hf-card` — Card (v0.4+)
495
+ - **Anatomy:** white bg, 1px `--color-hf-border-subtle`, 12px radius, `--shadow-hf-card`. `__header` (20px, bottom border) + `__title` (18px/600) + `__description` (14px muted) + `__body` (20px) + `__footer` (20px, top border, right-aligned).
496
+ - **Variant:** `--flat` removes the shadow.
497
+ - **Reference:** `components.html#cards` · **Portal source:** `.dashboard-card` · **Decision:** elevated card; for the lighter look use the bordered pattern `bg-white rounded-lg border p-5`.
498
+
499
+ ### `.hf-drawer` — Side-panel (v0.4+)
500
+ - **Anatomy:** `position:fixed; inset:0; z-index:10051` (= `zIndex.modalDialog`), flex justify-end. `__backdrop` (`rgba(0,0,0,.4)`), `__panel` (max-width 480px, full height, `--shadow-hf-modal`, slide-in keyframe). `--left` slides from the left. `__header` / `__title` / `__close` / `__body` (scroll) / `__footer` mirror `.hf-modal`.
501
+ - **Reference:** `components.html#layout` · **Decision:** new primitive — consolidates the repeated backdrop + sliding-panel pattern (reservation / room / guest drawers).
461
502
 
462
503
  ### `.skeleton` / `.hf-spin` — Loading primitives
463
504
  - **Skeleton:** linear-gradient shimmer animation, 1.4s infinite, 4px radius. Use as block element with width/height utilities (e.g. `<div class="skeleton h-3 w-3/4">`)
@@ -468,6 +509,8 @@ These are the **canonical component classes** shipped in `pre-built/components.c
468
509
 
469
510
  ## 6. Forms
470
511
 
512
+ > **Design-system API (v0.4+):** these ship as `.hf-input` / `.hf-textarea` / `.hf-select` + `.hf-form-field` + `.hf-switch` in `pre-built/components.css` (see §5.1). Use those in new code; the portal-observed specs below are the source. The DS focus ring (accent border + 3px `--color-hf-accent-subtle`) is the accessible variant.
513
+
471
514
  - **Inputs (Text / Select):** Height `39px`, Padding `6px 12px`, Radius `6px`, Border `1px solid #d1d6dd`. Placeholder `#AEBCCF`. **Focus (portal-exact):** border darkens only to `#B2BAC4`, **no ring**. **Focus (accessible, recommended for new projects):** add `box-shadow: 0 0 0 2px rgba(36,175,232,0.2)` for WCAG compliance.
472
515
  - **Field Anatomy:**
473
516
  1. Label (`14px / 500`, color `#2B2B2B`, margin-bottom `8px`).
@@ -25,8 +25,8 @@ This project follows the **HotelFriend Design System v0.1.0**. The design system
25
25
  ## Hard rules — never violate these
26
26
 
27
27
  1. **Colors:** Use only tokens defined in `pre-built/tailwind.css` / `pre-built/tokens.css`. Never hard-code hex codes. The primary brand color is `#24AFE8` (CSS var `--color-primary`, Tailwind `primary`). The four status colors are success `#59B59D`, warning `#FFBD5A`, error `#EA6565`, coral `#F87921`.
28
- 2. **Status badges:** Use `.hf-pill .status-{domain}-{state}`. Color is `var(--color-badge-{domain}-{state}-color)`, background is `var(--color-badge-{domain}-{state}-bg)` (15% alpha). Cancellation reasons (`canceled-by-hotel/guest/hf/pos`) all share the `.status-cancel` alias. Do NOT invent new status colors.
29
- 3. **Component primitives — reuse, never rebuild:** Before writing a modal, alert, dropdown, pagination, tabs, checkbox, or toggle, **check `pre-built/components.css` for an existing `.hf-*` primitive**. Use `.hf-modal`, `.hf-alert`, `.hf-pagination`, `.hf-dropdown-menu`, `.hf-check`, etc. with their BEM-style children (`__header`, `__body`, `__footer`, `__icon`, `__title`, `__close`, etc.) and modifiers (`--success`, `--tinted`, `--banner`, `--compact`, `--sm`). See `UI_DESIGN.md` §5.1 for the full list.
28
+ 2. **Status badges:** Use `.hf-pill .status-{domain}-{state}` (rules in `status.css`). Each class sets `color`/`background` from a semantic slot — `var(--color-hf-status-{role})` and `var(--color-hf-status-{role}-bg)` (15% alpha) — and the domain→role map lives in `status-map.json`. Cancellation reasons (`canceled-by-hotel/guest/hf/pos`) all share the `.status-cancel` alias. Do NOT invent new status colors.
29
+ 3. **Component primitives — reuse, never rebuild:** Before writing a button, input, modal, alert, dropdown, pagination, tabs, checkbox, toggle, card, or drawer, **check `pre-built/components.css` for an existing `.hf-*` primitive**. Available: `.hf-btn` (`--primary` / `--danger` / `--outline-primary` / `--outline-default` / `--cancel`, sizes `--sm` / `--icon`); `.hf-input` / `.hf-textarea` / `.hf-select` (wrap `<select>` in `.hf-select-wrap`); `.hf-switch`; `.hf-form-field` (`__label` / `__hint` / `__error`, state `--error`); `.hf-card`; `.hf-drawer`; `.hf-modal`; `.hf-alert`; `.hf-pagination`; `.hf-dropdown-menu`; `.hf-check` / `.hf-radio`; `.hf-pill`; `.hf-tab`; `.hf-toast`. Use BEM-style children (`__header`, `__body`, `__footer`, `__title`, `__close`, `__item`, ) and modifiers (`--primary`, `--success`, `--tinted`, `--banner`, `--compact`, `--sm`). For dropdowns the canonical children are `.hf-dropdown-menu__header / __item / __item-icon / __shortcut / __divider` and modifier `.hf-dropdown-menu__item--danger` (the older flat `.hf-dropdown-{header|item|divider}` names still work as deprecated aliases). See `UI_DESIGN.md` §5.1 for the full list.
30
30
  4. **Typography:** Family is **Roboto**. Sizes from canonical scale only: 11/13/14/15/16/18/20/24/26/30 px. Weights only 400 / 500 / 600. Line-heights 1.2 (headings), 1.5 (body), 1 (chips).
31
31
  5. **Spacing:** Multiples of 4 only. Default section gap is 20px. Never write 7px / 13px / 18px — round to the scale. (Exception: portal-exact padding `7px 10px 9px` for `.hf-alert` `help-block` is documented in components.html.)
32
32
  6. **Border radius:** `6px` (buttons/inputs/checkboxes/modals/alerts), `8px` (pagination items), `9px` (dropdowns/toasts/pill-tabs), `12px` (large cards), `99px` (status pills are 6px square — pills are NOT round). Never invent intermediate values.
@@ -49,15 +49,15 @@ The visual reference is `components.html`. If the user asks "make a settings pag
49
49
 
50
50
  1. Open `components.html`, find Page Layouts section (`#layout`). Pick the matching pattern (List / Detail / Form / Dashboard).
51
51
  2. Replicate the structure (Title bar → Tabs → Filters → Data grid → Footer pagination).
52
- 3. Use only `.btn-primary`, `.btn-outline-primary`, `.btn-cancel`, `.btn-danger` for buttons.
52
+ 3. Use `.hf-btn` + a variant (`.hf-btn--primary`, `.hf-btn--outline-primary`, `.hf-btn--cancel`, `.hf-btn--danger`) for buttons.
53
53
  4. Use `.hf-pill .status-{domain}-{state}` for status indicators.
54
- 5. Wrap data sections in `.bg-white rounded-lg border border-border p-5` (the bordered card pattern most common in portal).
54
+ 5. Wrap data sections in `.hf-card` (`__header` / `__body` / `__footer`), or the lighter bordered pattern `.bg-white rounded-lg border border-border p-5` — both common in the portal.
55
55
  6. Use `.hf-pagination` for pager.
56
56
  7. Use `.hf-modal` / `.hf-alert` / `.hf-dropdown-menu` for floating UI.
57
57
 
58
58
  ## Anti-patterns
59
59
 
60
- - ❌ `<button class="bg-blue-500 text-white px-4 py-2 rounded">Save</button>` (Tailwind native classes for what should be a `.btn.btn-primary`)
60
+ - ❌ `<button class="bg-blue-500 text-white px-4 py-2 rounded">Save</button>` (Tailwind native classes for what should be a `.hf-btn.hf-btn--primary`)
61
61
  - ❌ Inventing colors like `#1F8FCE` because "it's close to primary"
62
62
  - ❌ Border-radius `8px` because "it looks better than 6px" (8px is reserved for pagination items only)
63
63
  - ❌ Adding a new shadow `0 4px 12px rgba(...)` instead of `var(--shadow-hf-modal)`
@@ -6,8 +6,8 @@ You are working in a project that uses the **HotelFriend Design System v0.1.0**.
6
6
  # Inviolable rules
7
7
 
8
8
  - **Colors:** only use tokens. Primary `#24AFE8` (`--color-primary` / Tailwind `primary`). Status colors success `#59B59D`, warning `#FFBD5A`, error `#EA6565`, coral `#F87921`. Cancellation reasons share `.status-cancel`. Never hard-code other hex codes.
9
- - **Status badges:** use `.hf-pill .status-{domain}-{state}`. Color via `var(--color-badge-{domain}-{state}-color)`, bg via `var(--color-badge-{domain}-{state}-bg)`. Never invent new status colors.
10
- - **Component primitives — reuse, never rebuild:** Use `.hf-modal`, `.hf-alert`, `.hf-pagination`, `.hf-dropdown-menu`, `.hf-tab`, `.hf-check`, `.hf-radio`, `.hf-toast` from `pre-built/components.css` BEFORE writing new component CSS. BEM children with `__` (e.g. `__header`, `__body`, `__footer`, `__icon`). Variants with `--` (`--success`, `--banner`, `--compact`). State classes with `.is-*` (`.is-active`, `.is-disabled`).
9
+ - **Status badges:** use `.hf-pill .status-{domain}-{state}` (rules in `status.css`). Color/bg come from `var(--color-hf-status-{role})` / `-bg` (15% alpha); the domain→role map is in `status-map.json`. Never invent new status colors.
10
+ - **Component primitives — reuse, never rebuild:** Use `.hf-btn`, `.hf-input` / `.hf-textarea` / `.hf-select`, `.hf-switch`, `.hf-form-field`, `.hf-card`, `.hf-drawer`, `.hf-modal`, `.hf-alert`, `.hf-pagination`, `.hf-dropdown-menu`, `.hf-tab`, `.hf-check`, `.hf-radio`, `.hf-toast` from `pre-built/components.css` BEFORE writing new component CSS. BEM children with `__` (e.g. `__header`, `__body`, `__footer`, `__item`, `__icon`). Variants with `--` (`--primary`, `--success`, `--banner`, `--compact`, `--sm`). State classes with `.is-*` (`.is-active`, `.is-disabled`). For dropdowns the canonical children are `.hf-dropdown-menu__header / __item / __item-icon / __shortcut / __divider` (the older flat `.hf-dropdown-{header|item|divider}` names still work as deprecated aliases).
11
11
  - **Typography:** Roboto only. Sizes: 11 / 13 / 14 / 15 / 16 / 18 / 20 / 24 / 26 / 30 px. Weights: 400 / 500 / 600.
12
12
  - **Spacing:** multiples of 4. Default section gap 20px.
13
13
  - **Border radius:** 6 (buttons/inputs/modals/alerts), 8 (pagination items), 9 (dropdowns/toasts), 12 (cards), 99 (pills are square 6px, not round).
@@ -7,8 +7,8 @@ This project uses the **HotelFriend Design System v0.1.0**. Canonical visual ref
7
7
  ## Hard rules — never violate
8
8
 
9
9
  1. **Colors:** use only tokens. Brand accent `#24AFE8` (`var(--color-hf-accent)` / Tailwind `bg-hf-accent`). Status colors via `var(--color-hf-status-{success|warning|error|info})`. Cancellation reasons share `.status-cancel`. Never hard-code other hex codes.
10
- 2. **Status badges:** use `.hf-pill .status-{domain}-{state}`. Color via `var(--color-badge-{domain}-{state}-color)`, background via `var(--color-badge-{domain}-{state}-bg)` (15% alpha). Never invent new status colors.
11
- 3. **Component primitives — reuse, never rebuild:** Use `.hf-modal`, `.hf-alert`, `.hf-pagination`, `.hf-dropdown-menu`, `.hf-tab`, `.hf-check`, `.hf-radio`, `.hf-toast` from `pre-built/components.css` BEFORE writing new component CSS.
10
+ 2. **Status badges:** use `.hf-pill .status-{domain}-{state}` (rules in `status.css`). Color/background come from a semantic slot `var(--color-hf-status-{role})` / `-bg` (15% alpha); the domain→role map is in `status-map.json`. Never invent new status colors.
11
+ 3. **Component primitives — reuse, never rebuild:** Use `.hf-btn`, `.hf-input` / `.hf-textarea` / `.hf-select`, `.hf-switch`, `.hf-form-field`, `.hf-card`, `.hf-drawer`, `.hf-modal`, `.hf-alert`, `.hf-pagination`, `.hf-dropdown-menu`, `.hf-tab`, `.hf-pill`, `.hf-check`, `.hf-radio`, `.hf-toast` from `pre-built/components.css` BEFORE writing new component CSS.
12
12
  4. **Typography:** Roboto only. Sizes from scale: 11 / 13 / 14 / 15 / 16 / 18 / 20 / 24 / 26 / 30 px. Weights: 400 / 500 / 600. Line-heights: 1.2 (headings), 1.5 (body), 1 (chips).
13
13
  5. **Spacing:** multiples of 4 only. Default section gap 20 px. Never write 7 / 13 / 18 px.
14
14
  6. **Border radius:** `6px` (buttons/inputs/modals/alerts), `8px` (pagination items), `9px` (dropdowns/toasts), `12px` (large cards), `99px` (pill-rounded). No intermediate values.
@@ -19,10 +19,10 @@ This project uses the **HotelFriend Design System v0.1.0**. Canonical visual ref
19
19
 
20
20
  ## When generating UI code
21
21
 
22
- - **Button classes:** `.btn-primary`, `.btn-hf-outline-primary`, `.btn-cancel`, `.btn-danger`, `.btn-reset-filters` + compact variants (`btn-b-gray`, `btn-add-grey`, `btn-edit-sm`, `btn-trash`, `btn-copy-sm`, `btn-plus-sm`)
23
- - **Form primitives:** `.form-control` (inputs), `.hf-check` (checkbox), `.hf-radio` (radio), toggle pattern
24
- - **Containers:** `.hf-modal` + `__header/__title/__body/__footer/__close`, `.hf-alert` + variants/modifiers, `.hf-toast`, bordered card `<div class="bg-white rounded-lg border border-border p-5">`, elevated card with `shadow-subtle`
25
- - **Navigation:** `.hf-tab` + `--sm` + `__count`, `.hf-pill-tabs` + `.hf-pill-tab`, `.hf-pagination` + `__item/__ellipsis`, `.hf-dropdown-menu` + `__header/__item/__shortcut/__icon/__divider`
22
+ - **Button classes:** `.hf-btn` + variant — `.hf-btn--primary`, `.hf-btn--outline-primary`, `.hf-btn--outline-default`, `.hf-btn--cancel`, `.hf-btn--danger`; sizes `.hf-btn--sm`, `.hf-btn--icon` (compact portal-only variants like reset-filters / icon-square can be layered with Tailwind utilities until promoted)
23
+ - **Form primitives:** `.hf-input` / `.hf-textarea` / `.hf-select` (wrap `<select>` in `.hf-select-wrap`), `.hf-switch` (toggle), `.hf-check` (checkbox), `.hf-radio` (radio), `.hf-form-field` + `__label`/`__hint`/`__error` (`--required`, `--error`)
24
+ - **Containers:** `.hf-card` + `__header/__title/__description/__body/__footer` (`--flat`), `.hf-drawer` + `__backdrop/__panel/__header/__body/__footer` (`--left`), `.hf-modal` + `__header/__title/__body/__footer/__close`, `.hf-alert` + variants/modifiers, `.hf-toast`; light bordered card `<div class="bg-white rounded-lg border border-border p-5">`
25
+ - **Navigation:** `.hf-tab` + `--sm` + `__count`, `.hf-pill-tabs` + `.hf-pill-tab`, `.hf-pagination` + `__item/__ellipsis`, `.hf-dropdown-menu` + `__header/__item/__item-icon/__shortcut/__divider` (+ `__item--danger`)
26
26
  - **Status:** `.hf-pill .status-{domain}-{state}` + modifiers (`--striped`, `--dd`, `.is-active`, `min-w-*`)
27
27
  - **Loading:** `.skeleton` for shimmer, `.hf-spin` for spinner
28
28
  - Every interactive element needs: default + `:hover` + `:focus-visible` + `:disabled` states at minimum. See `states-canonical.json`.
@@ -4,7 +4,7 @@
4
4
  Primary: `#24AFE8` · Hover: `#149AD1` · Light tint: `#E9F6FC`
5
5
  Neutrals: page-bg `#FBFBFC` · section-bg `#F6F7FB` · very-light `#F1F3F6` · border `#D1D6DD` · text `#2B2B2B` · secondary-text `#4B5675` · placeholder `#AEBCCF`
6
6
  Status: success `#59B59D` · warning `#FFBD5A` · error `#EA6565` · coral `#F87921` · violet `#5761D8` · cancellation/deleted `#7F8FA4`
7
- Status badges use `--color-badge-{domain}-{state}-color` + `--color-badge-{domain}-{state}-bg` (15% alpha). Domains: booking · order · fd (frontDesk) · clean (roomItem.cleaning). Cancellation reasons all share `.status-cancel`.
7
+ Status badges: apply `.hf-pill .status-{domain}-{state}`; color/bg come from `--color-hf-status-{role}` / `-bg` (15% alpha), domain→role map in `status-map.json`. Domains: booking · order · front-desk · room-item-cleaning. Cancellation reasons all share `.status-cancel`.
8
8
 
9
9
  ## Typography
10
10
  Font: Roboto · Sizes: 11 / 13 / 14 / 15 / 16 / 18 / 20 / 24 / 26 / 30 px · Weights: 400 / 500 / 600
@@ -17,14 +17,14 @@ Shadows: default `0 1px 8px rgba(0,0,0,.1)` · subtle `0 2px 4px rgba(0,0,0,.05)
17
17
 
18
18
  ## Component primitives (`.hf-*`)
19
19
 
20
- **Buttons** — `.btn-primary` 40 h / 15px / 600 / `#24AFE8` · `.btn-cancel` white bg muted text · `.btn-danger` red bg · `.btn-outline-primary` 1px primary border · `.btn-reset-filters` 38 h `#EFF6FF` bg
21
- **Inputs** — `.form-control` 39 h / 6 r / placeholder `#AEBCCF` / focus border darkens to `#B2BAC4` (portal) or add `box-shadow: 0 0 0 2px rgba(36,175,232,.2)` for accessibility
20
+ **Buttons** — `.hf-btn` base (40 h / 15px / 600) + variant: `--primary` `#24AFE8` (hover `#149AD1`) · `--danger` `#D9534F` (hover `#C9302C`) · `--outline-primary` 1px primary border · `--outline-default` steel text + neutral border + outline-shadow · `--cancel` transparent / muted text; sizes `--sm` 32 h · `--icon` square
21
+ **Inputs** — `.hf-input` / `.hf-textarea` / `.hf-select` 39 h / 6 r / border `#DBDFE9` / placeholder `#AEBCCF` / focus = accent border + 3px accent-subtle ring · wrap `<select>` in `.hf-select-wrap` (token-colored caret) · `.hf-form-field` + `__label`/`__hint`/`__error` (`--required`, `--error`)
22
22
  **Checkbox/Radio** — `.hf-check` / `.hf-radio` 18×18 · transparent + 1px `#DBDFE9` border · checked = filled `#26ADE4` + white tick or dot
23
- **Toggle** — 52×28 track · off `#DFDFDF` / on `#24AFE8` · thumb 20×20 white shadow `0 1px 6px rgba(0,0,0,.3)`
24
- **Cards** — bordered `bg-white rounded-lg border border-border p-5` (no shadow, most common) · elevated `bg-white rounded border-[rgba(72,91,120,.05)] shadow-subtle p-4` (dashboard KPIs)
23
+ **Toggle** — `.hf-switch` (styled `<input type=checkbox>`) 40×22 track · off `#D1D6DD` / on `#24AFE8` · 18px white knob slides right on `:checked`
24
+ **Cards** — `.hf-card` + `__header/__title/__description/__body/__footer` (12 r, card-shadow; `--flat` removes shadow) · `.hf-drawer` + `__backdrop/__panel/__header/__body/__footer` (`--left`) side-panel · light bordered alt `bg-white rounded-lg border border-border p-5`
25
25
  **Status pills** — `.hf-pill.status-{domain}-{state}` 6 r · 15% bg + 100% text + 1px border · modifiers: `.is-active` (transparent + inset ring) / `--striped` / `--dd` (chevron) / `min-w-[130/160/180px]`
26
26
  **Tabs** — `.hf-tab` 16/500 padding 22 15 / `--sm` 15/500 padding 10 15 · active `#24AFE8` + 3px bottom · `__count` badge inside · `.hf-pill-tabs > .hf-pill-tab` segmented (Day/Week/Month)
27
- **Dropdown** — `.hf-dropdown-menu` 9 r shadow `0 1px 10px rgba(0,0,0,.1)` · `__header` (uppercase 11px) · `__item` 14/normal hover `#F5F5F5` · `__shortcut` right-aligned · `.is-active` primary-tint · `.danger`
27
+ **Dropdown** — `.hf-dropdown-menu` 9 r shadow `0 1px 10px rgba(0,0,0,.1)` · `__header` (uppercase 11px) · `__item` 14/normal hover `#F5F5F5` · `__item-icon` · `__shortcut` right-aligned · `__divider` · `.is-active` primary-tint · `__item--danger` (legacy flat `.hf-dropdown-{header|item|divider}` still alias)
28
28
  **Modal** — `.hf-modal` 6 r border `1px rgba(72,91,120,.15)` shadow `0 2px 4px rgba(72,91,120,.18)` · `__header` bottom border / `__footer` NO top border · sizes sm 420 / md 500 / lg 720 / xl 960
29
29
  **Alerts** — `.hf-alert` white bg + 3px top accent bar + 26×26 squared icon · variants `--success/--info/--warn/--error` · modifiers `--tinted/--banner/--compact`
30
30
  **Toast** — `.hf-toast` 9 r modal-shadow · `__icon` 20×20 · floating bottom-right