--- # KeluargaMart POS — design tokens (family contract) # Mode: Operate / cashier terminal. Touch-first, glanceable, high-contrast. font: sans: "IBM Plex Sans" display: "IBM Plex Sans" # weight (600) carries hierarchy, not a second family mono: "IBM Plex Mono" # codes, currency, totals (.num), the "POS" label type_scale: headline: { size: 1.5rem, line: 1.25, weight: 600 } title: { size: 1.125rem, line: 1.4, weight: 600 } body: { size: 0.875rem, line: 1.5, weight: 400 } # base normalized to a defined leading label: { size: 0.75rem, line: 1.33, weight: 500, tracking: 0.04em, font: mono } color: brand: { 50: "#F0F5FF", 100: "#DCE7FC", 200: "#C4D4F5", 300: "#9DB8EA", 400: "#28459A", 500: "#142B80", 600: "#102268", 700: "#071F68" } primary: "#142B80" # family primary (replaces pos's old #182875) primary-deep: "#102268" # hover / pressed primary-soft: "#DCE7FC" primary-line: "#C4D4F5" on-primary: "#FFFFFF" canvas: "#F5F8FF" surface: "#FFFFFF" surface-subtle: "#F7F8FC" surface-well: "#EEF3FA" line: "#D9E2F0" # dividers line-strong: "#BCCBE4" # control borders (3:1) ink: "#14213D" # primary text ink-2: "#475569" # muted, 7.0:1 on every family surface ink-3: "#64748B" # subtle, #FFFFFF only (4.76:1) ink-disabled: "#94A3B8" # disabled / non-text only status: primary: { fg: "#142B80", soft: "#DCE7FC" } success: { fg: "#15803D", soft: "#ECFAF0" } warning: { fg: "#B45309", soft: "#FFF8EB" } danger: { fg: "#C0372C", soft: "#FBE7E4" } info-deep: { fg: "#0E7490", soft: "#ECFEFF" } # info FG is #0E7490, never light cyan on light surfaces neutral: { fg: "#475569", soft: "#EEF3FA" } radius: { sm: 8px, md: 10px, lg: 12px, xl: 16px } focus_ring: "outline: 2px solid #142B80; outline-offset: 2px" touch_min: 44px --- > **Family contract:** shared tokens, per-app deltas, and the sync protocol live in `UNIFORMITY.md` — byte-identical across B2B, ERP, and POS. Edit the B2B copy, then run `bash scripts/sync-design.sh`. # KeluargaMart POS — Design ## Mode: Operate (cashier terminal) This surface is used fast, all day, at a counter, often under bad lighting. It is not a place to be expressive for its own sake. Every decision serves a cashier who is looking down at a screen between glances at a customer. **North star:** the cashier can read the payable total and the change due from arm's length, and can hit every control they touch without aiming. One family, three frontends (erp, b2b, pos). POS owns the cashier terminal. The tokens above are the shared family contract; pos was realigned onto them (primary `#182875` → `#142B80`, ink `#1b2247` → `#14213D`, Lexend + Source Sans 3 → IBM Plex Sans + IBM Plex Mono). ## Colour roles - **Navy `#142B80` dominates**; it is the brand, the primary action, and the payable/change figures. `#102268` is its hover/pressed state. - **Sharp accents, sparingly.** Success green for change/positive money, danger red for destructive actions and refunds, warning amber for "not set / low stock", info-deep cyan for logistics (delivery, payment breakdowns). - **Surfaces stay quiet.** Canvas is a near-white blue (`#F5F8FF`); cards are pure white; wells (`#EEF3FA`) group secondary content. Depth comes from one soft ink-tinted shadow, not from borders stacked on borders. ## Ink usage rule - `ink #14213D` — primary text, any family surface. - `ink-2 #475569` — muted/secondary text, safe (≥7:1) on **every** family surface. - `ink-3 #64748B` — subtle text and placeholders, **white surfaces only** (4.76:1). Never on canvas or wells. - `ink-disabled #94A3B8` — disabled controls and non-text only. Never body copy. ## The ≥44px touch rule Every interactive element on the POS surface clears **44×44px**. Steppers, delete, unit chips, customer picker, shift/kas pills, draft actions, dialog/close buttons, primary pay buttons. Small visual controls (the "Ingat saya" checkbox) keep a small box but expand the hit area via a ≥44px label. Dense back-office table row actions may stay 32–36px **only if** they keep a ≥32px hit area and a visible focus ring. ## The glance-size total rule The single most important figure in a flow — the **payable total** and the **change due** — is at least `text-3xl` (30px), `.num` (IBM Plex Mono, tabular), in navy-deep (total) or success (change). Everything else is subordinate to it. ## Status semantics | Tone | Use for | |-----------|--------------------------------------------| | primary | brand, primary action, payable total | | success | change due, completed, cash-in, "Lunas" | | warning | price/stock not set, low stock, cash-out | | danger | cancel/delete/refund, over-tender shortfall | | info-deep | delivery status, payment-method breakdown | | neutral | inert metadata, counts, tags | ## Focus Every interactive element carries the family focus ring: `outline: 2px solid #142B80; outline-offset: 2px`. Inputs use a matching 2px ring. No control ships without a visible keyboard focus state. ## Motion Restrained. Transform/opacity only (dialog/drawer/toast entrances, staggered nothing). Respects `prefers-reduced-motion`. Motion communicates state (a drawer sliding in, a toast arriving), never decorates. ## Do / Don't **Do** - Keep totals huge, mono, and tabular so columns align. - Use navy as the confident dominant; let accents mean something. - Give every state a home: loading skeleton, empty, **error with retry**, disabled. - Keep Indonesian copy, routes, and the working auth/token/logout logic intact. **Don't** - Don't print live credentials in the DOM, or show invented sales figures as data. - Don't use light cyan (`#8dd9fd`) as a foreground on a light surface — it fails contrast. Info foreground is `#0E7490`. - Don't put a sub-44px tap target on the cashier surface. - Don't truncate or wrap a money figure — give it room and `whitespace-nowrap`. - Don't add gradient text, glassmorphism stacks, or nested card grids. - Demo login buttons (with role-based accounts) are intentionally kept on all login pages for development and demo purposes. Do not remove or gate them.