Files
TREK/client/tailwind.config.js
T
Maurice b7a91fc84e fix(mobile): one form sheet for every dialog, opaque and placed beside the rail
Every sheet now stands on the opaque sheet surface: the frosting the
translucent one relied on is dropped while the scrim fades, so the page
read through the fields as sharp ghost text.

On a wide window a sheet is centred in the content beside the navigation
rail instead of on the whole window, so it never lies on the rail, and it
grows to the window's height instead of stopping at 880px. On a phone the
card stands between the status bar and the dock rather than across the
dock. A sheet marked as a form fills the height of a window as short as a
phone on its side, with Cancel and Save beside the title (new `short:`
variant, m-form-sheet grid in mobile.css).

The form chrome gains a scrolling body that fades at the edges with more
behind them (useEdgeFade on the vertical axis), a date field whose
keyboard entry moves into the picker, a field wrapper for amounts with a
currency, and two-line titles. The focused sheet no longer draws the
app-wide focus frame or loses its corners, and the desktop's dark field
paint stays out of the touch shell, which painted a dark box inside every
rounded field.
2026-11-07 23:25:14 +01:00

137 lines
5.4 KiB
JavaScript

/** @type {import('tailwindcss').Config} */
export default {
darkMode: 'class',
content: [
"./index.html",
"./src/**/*.{js,jsx,ts,tsx}",
],
theme: {
extend: {
colors: {
primary: {
50: '#eef2ff',
100: '#e0e7ff',
200: '#c7d2fe',
300: '#a5b4fc',
400: '#818cf8',
500: '#6366f1',
600: '#4f46e5',
700: '#4338ca',
800: '#3730a3',
900: '#312e81',
950: '#1e1b4b',
},
planner: {
day: '#f8fafc',
dayBorder: '#e2e8f0',
dayHeader: '#1e293b',
sidebar: '#ffffff',
sidebarBorder: '#f1f5f9',
overlay: 'rgba(15, 23, 42, 0.4)',
dragActive: '#eef2ff',
dragOver: '#c7d2fe',
},
// Semantic theme tokens — resolve to the CSS variables in src/index.css
// (:root light / .dark dark). Use these utilities (bg-surface, text-content,
// border-edge, bg-accent) instead of inline `style={{ ... 'var(--...)' }}`.
surface: {
DEFAULT: 'var(--bg-primary)',
secondary: 'var(--bg-secondary)',
tertiary: 'var(--bg-tertiary)',
elevated: 'var(--bg-elevated)',
card: 'var(--bg-card)',
input: 'var(--bg-input)',
hover: 'var(--bg-hover)',
selected: 'var(--bg-selected)',
},
content: {
DEFAULT: 'var(--text-primary)',
secondary: 'var(--text-secondary)',
muted: 'var(--text-muted)',
faint: 'var(--text-faint)',
},
edge: {
DEFAULT: 'var(--border-primary)',
secondary: 'var(--border-secondary)',
faint: 'var(--border-faint)',
},
accent: {
DEFAULT: 'var(--accent)',
text: 'var(--accent-text)',
on: 'var(--accent-on)',
hover: 'var(--accent-hover)',
subtle: 'var(--accent-subtle)',
},
// Semantic status colors (+ soft tinted background variant).
success: { DEFAULT: 'var(--success)', soft: 'var(--success-soft)' },
danger: { DEFAULT: 'var(--danger)', soft: 'var(--danger-soft)' },
warning: { DEFAULT: 'var(--warning)', soft: 'var(--warning-soft)' },
info: { DEFAULT: 'var(--info)', soft: 'var(--info-soft)' },
// Inverse surface (the near-black/near-white "pill" header pattern).
inverse: { DEFAULT: 'var(--bg-inverse)', text: 'var(--text-inverse)' },
// Mobile rewrite tokens — resolve to the --m-* variables scoped to
// .m-root in src/mobile/mobile.css. Only meaningful inside MobileShell.
'm-ink': 'var(--m-ink)',
'm-muted': 'var(--m-muted)',
'm-faint': 'var(--m-faint)',
'm-act': 'var(--m-act)',
'm-actfg': 'var(--m-actfg)',
'm-card': 'var(--m-card)',
'm-cbr': 'var(--m-cbr)',
'm-inner': 'var(--m-inner)',
'm-inbr': 'var(--m-inbr)',
'm-glass': 'var(--m-glass)',
'm-gbr': 'var(--m-gbr)',
'm-sheet': 'var(--m-sheet)',
'm-sheetop': 'var(--m-sheetop)',
'm-shbr': 'var(--m-shbr)',
'm-ic': 'var(--m-ic)',
'm-avbr': 'var(--m-avbr)',
'm-rowbr': 'var(--m-rowbr)',
'm-dim': 'var(--m-dim)',
'm-conn': 'var(--m-conn)',
'm-trackoff': 'var(--m-trackoff)',
},
fontFamily: {
// Secondary "subtext" face of the mobile design (numbers, eyebrows).
geist: ['Geist Sans', 'Poppins', '-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'system-ui', 'sans-serif'],
},
boxShadow: {
'day-column': '0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)',
'place-card': '0 1px 2px 0 rgba(0, 0, 0, 0.05)',
'drag-overlay': '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)',
// Token-backed elevation (scheme/dark aware) — for migrating inline rgba shadows.
'card': 'var(--shadow-card)',
'elevated': 'var(--shadow-elevated)',
'modal': 'var(--shadow-modal)',
'dropdown': 'var(--shadow-dropdown)',
'popover': 'var(--shadow-popover)',
},
// Semantic type tiers — each scales with its own user multiplier (defaults
// to 1). Use text-title/subtitle/body/caption for headings/labels so the
// appearance "text size" control reaches them; the global fontScale (root
// font-size) additionally scales all rem-based text.
fontSize: {
title: ['calc(24px * var(--fs-scale-title, 1))', '1.2'],
subtitle: ['calc(18px * var(--fs-scale-subtitle, 1))', '1.35'],
body: ['calc(14px * var(--fs-scale-body, 1))', '1.5'],
caption: ['calc(12px * var(--fs-scale-caption, 1))', '1.4'],
},
},
},
plugins: [
// The touch shell's size classes (src/hooks/sizeClass.ts) as the `wide:` and
// `split:` variants. Variants of their own rather than entries in `screens`:
// both need a height bound (a phone on its side stays compact), and a raw
// screen among the min-width ones reorders how Tailwind sorts every
// responsive class.
({ addVariant }) => {
addVariant('wide', '@media (min-width: 600px) and (min-height: 501px)')
addVariant('split', '@media (min-width: 840px) and (min-height: 501px)')
// The other side of that height bound: a window as short as a phone on its
// side, where a form sheet takes the full height (MSheet's `form`).
addVariant('short', '@media (max-height: 500px)')
},
],
}