All files / src/components/ui status-ink.ts

100% Statements 4/4
100% Branches 0/0
100% Functions 0/0
100% Lines 4/4

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99                                                                                                              139x                 139x                                     139x                           139x  
/**
 * The Job Book's printed status ink — one place where a status colour is decided.
 *
 * WHY THIS FILE
 * `status-badge.tsx` (the printed code) and `alert.tsx` (the printed band) have
 * to agree on what "success" looks like, and both have to hold WCAG AA in both
 * themes. Keeping the pairs in one module means the AA argument below is made
 * once, in one place to revisit.
 *
 * THE VOCABULARY
 * A status is a printed code, never a pill: 2px radius (`rounded-sm`), `.label`
 * caps, status ink on its own `-light` tint. See `.context/mockups/_base.css`
 * §7.2 — the approved mockups are the specification.
 *
 * THE INK IS MIXED, AND THAT IS NOW A HUE DECISION
 * The mockup writes the ink as the bare `--success` / `--warning` / … token,
 * which holds AA on its `-light` tint in the Job Book palette (5.3–5.9:1). This
 * module was written while the portal still rendered the legacy palette, whose
 * four status tokens were mid-tone Tailwind hues that failed badly as text on
 * the same tints — success 2.07:1, warning 1.93:1, error 3.08:1, info 3.01:1,
 * muted-on-muted 3.31:1. Fixing that here rather than at the call sites fixed
 * every badge and banner in the portal at once.
 *
 * The fix is to pull each status ink halfway to page ink:
 *
 *     color-mix(in srgb, var(--success) 50%, var(--foreground-default))
 *
 * `--foreground-default` is near-black in light mode and near-white in dark
 * mode, and a `-light` tint is pale in light mode and deep in dark mode — so
 * one expression moves the ink AWAY from its tint in both themes, under any
 * palette. No hex is named; the mix is a ratio over two tokens. Tailwind emits
 * the bare token as the pre-`@supports` fallback, so a browser without
 * `color-mix()` renders exactly the mockup's value.
 *
 * MEASURED RATIOS, MIXED (ink on its own tint; AA for normal text is 4.5:1)
 *
 *   tone      Job Book light   Job Book dark
 *   success       10.52             6.24
 *   warning       10.38            10.30
 *   error         10.22             8.88
 *   info           9.60             8.61
 *   default        9.56             9.51
 *
 * THE MIX IS NOW OPTIONAL
 * The reskin deleted `src/styles/earthy-legacy.css` and the portal is the Job
 * Book, where the BARE tokens hold AA on their own tints (measured by
 * `status-ink.test.ts`). `STATUS_INK` may therefore be simplified to
 * `text-success` and friends whenever design wants the mockup's exact hue back
 * — it is a hue decision, not an accessibility one, and nothing else changes.
 */
 
/** The five ink families a printed code can carry. */
export type StatusTone = "success" | "warning" | "error" | "info" | "default";
 
/** The tint a printed code is printed on. */
export const STATUS_TINT: Record<StatusTone, string> = {
	success: "bg-success-light",
	warning: "bg-warning-light",
	error: "bg-error-light",
	info: "bg-info-light",
	default: "bg-background-muted",
};
 
/** The ink a printed code is printed in. See the mix argument in the header. */
export const STATUS_INK: Record<StatusTone, string> = {
	success:
		"text-[color-mix(in_srgb,var(--success)_50%,var(--foreground-default))]",
	warning:
		"text-[color-mix(in_srgb,var(--warning)_50%,var(--foreground-default))]",
	error: "text-[color-mix(in_srgb,var(--error)_50%,var(--foreground-default))]",
	info: "text-[color-mix(in_srgb,var(--info)_50%,var(--foreground-default))]",
	default:
		"text-[color-mix(in_srgb,var(--foreground-muted)_50%,var(--foreground-default))]",
};
 
/**
 * The tint a printed BAND is printed on — `alert.tsx`.
 *
 * Identical to `STATUS_TINT` bar the neutral tone, which is the mockup's
 * `.notice` ground (`--background-subtle`, grey card stock) rather than the
 * deeper `--background-muted` a small inline code needs to stay visible. Both
 * maps are measured by `status-ink.test.ts`.
 */
export const STATUS_BAND_TINT: Record<StatusTone, string> = {
	...STATUS_TINT,
	default: "bg-background-subtle",
};
 
/**
 * `.label` typography — the printed code's caps.
 *
 * `text-xs` is the mockup's 0.75rem and `tracking-wider` its 0.05em (the
 * mockup says 0.06em; the portal's nearest tracking token is used rather than
 * an arbitrary em value, per the design system's Golden Rule). Numbers are
 * tabular so a column of codes with counts lines up.
 */
export const STATUS_CODE_TYPE =
	"text-xs font-semibold uppercase tracking-wider tabular-nums leading-tight";