/* ───────────────────────────────────────────────────────────────────────── Mobile Design-Token System (light + dark) ───────────────────────────────────────────────────────────────────────── Loaded globally via nuxt.config.ts → css[]. Defines the --mob-* custom properties used by every page under app/pages/mobile/*. Palette is built on the Tailwind ramp (slate neutrals + blue/emerald/amber/ red/violet accents) so contrast is accessible by construction and the Nuxt UI pilot (app.config.ts → primary:'blue', neutral:'slate') matches. MODE SWITCHING -------------- Tokens are defined on :root (LIGHT, the default — matches colorMode preference 'light') and overridden under .dark / [data-mode="dark"], which the pre-hydration head script and useTheme().toggleTheme() set on . --mob-* names never collide with the desktop --theme-* system, so defining them globally is safe. NOTE: app/layouts/mobile.vue does not currently render (app.vue uses a bare ), so tokens MUST live at :root, not on .mobile-layout. The .mobile-layout helper rules below are kept tolerant (inert today, correct if the layout is ever wired up). RULES FOR MOBILE PAGES ---------------------- - Page background ............ var(--mob-bg) - Card / section / header .... var(--mob-surface) (nested → --mob-surface-2) - Hover / pressed / active ... var(--mob-hover) - Primary text ............... var(--mob-text) - Secondary text ............. var(--mob-text-secondary) - Muted / tertiary text ...... var(--mob-text-muted) (AA in both modes) - Borders / dividers ......... var(--mob-border) | --mob-border-subtle - Accents .................... var(--mob-{blue|green|amber|red|violet}*) - Text/icon on a filled accent button → var(--mob-on-{accent}) - NEVER hardcode hex colours in mobile pages. ───────────────────────────────────────────────────────────────────────── */ /* ── LIGHT (default) ── */ :root { /* Surfaces */ --mob-bg: #f1f5f9; /* slate-100 — page */ --mob-surface: #ffffff; /* cards, headers */ --mob-surface-2: #f8fafc; /* slate-50 — elevated: modals, nested cards */ --mob-hover: #e2e8f0; /* slate-200 — hover / pressed / active */ --mob-input-bg: #ffffff; --mob-border: #e2e8f0; /* slate-200 */ --mob-border-subtle: #eef2f6; /* Text */ --mob-text: #0f172a; /* slate-900 */ --mob-text-secondary: #334155; /* slate-700 — AA on light surfaces */ --mob-text-muted: #64748b; /* slate-500 — AA on white (~5.8:1) */ --mob-text-placeholder: #94a3b8; /* slate-400 */ /* Misc */ --mob-overlay: rgba(15, 23, 42, 0.45); --mob-shadow-card: 0 1px 3px rgba(15, 23, 42, 0.1), 0 1px 2px rgba(15, 23, 42, 0.06); --mob-shadow-pop: 0 10px 25px rgba(15, 23, 42, 0.15); --mob-focus-ring: rgba(37, 99, 235, 0.4); /* Blue (primary) */ --mob-blue: #2563eb; /* blue-600 */ --mob-blue-hover: #1d4ed8; /* blue-700 */ --mob-blue-soft: #2563eb; /* accent text/icon on neutral surface */ --mob-blue-bg: #dbeafe; /* blue-100 — tinted surface */ --mob-blue-fg: #1e40af; /* blue-800 — text on tinted surface */ --mob-blue-border: #bfdbfe; /* blue-200 */ --mob-on-blue: #ffffff; /* text/icon on filled blue */ /* Green (success) */ --mob-green: #059669; /* emerald-600 */ --mob-green-hover: #047857; /* emerald-700 */ --mob-green-soft: #047857; --mob-green-bg: #d1fae5; /* emerald-100 */ --mob-green-fg: #065f46; /* emerald-800 */ --mob-green-border: #a7f3d0; /* emerald-200 */ --mob-on-green: #ffffff; /* Amber (warning) */ --mob-amber: #d97706; /* amber-600 */ --mob-amber-hover: #b45309; /* amber-700 */ --mob-amber-soft: #b45309; --mob-amber-bg: #fef3c7; /* amber-100 */ --mob-amber-fg: #92400e; /* amber-800 */ --mob-amber-border: #fde68a; /* amber-200 */ --mob-on-amber: #1c1300; /* dark text on amber (AA) */ /* Red (danger) */ --mob-red: #dc2626; /* red-600 */ --mob-red-hover: #b91c1c; /* red-700 */ --mob-red-soft: #dc2626; --mob-red-bg: #fee2e2; /* red-100 */ --mob-red-fg: #991b1b; /* red-800 */ --mob-red-border: #fecaca; /* red-200 */ --mob-on-red: #ffffff; /* Violet (accent) */ --mob-violet: #7c3aed; /* violet-600 */ --mob-violet-hover: #6d28d9; /* violet-700 */ --mob-violet-soft: #7c3aed; --mob-violet-bg: #ede9fe; /* violet-100 */ --mob-violet-fg: #5b21b6; /* violet-800 */ --mob-violet-border: #ddd6fe; /* violet-200 */ --mob-on-violet: #ffffff; /* ── Legacy aliases (mode-independent; resolve to the canonical token of the current mode). Kept so the old skeleton names / helper rules keep working and to ease the migration. Prefer the canonical names above in new code. */ --mob-bg-card: var(--mob-surface); --mob-bg-header: var(--mob-surface); --mob-bg-hover: var(--mob-hover); --mob-bg-input: var(--mob-input-bg); --mob-border-light: var(--mob-border-subtle); --mob-blue-active: var(--mob-blue-hover); --mob-blue-light: var(--mob-blue-soft); --mob-blue-text: var(--mob-blue-fg); --mob-green-bright: var(--mob-green); --mob-green-text: var(--mob-green-fg); --mob-bg-success: var(--mob-green-bg); --mob-border-success: var(--mob-green-border); --mob-red-text: var(--mob-red-fg); --mob-bg-danger: var(--mob-red-bg); --mob-border-danger: var(--mob-red-border); --mob-orange: var(--mob-amber); --mob-orange-text: var(--mob-amber-fg); --mob-bg-warning: var(--mob-amber-bg); --mob-border-warning: var(--mob-amber-border); --mob-gold: var(--mob-amber-soft); --mob-purple: var(--mob-violet); --mob-purple-text: var(--mob-violet-fg); --mob-bg-purple: var(--mob-violet-bg); --mob-border-purple: var(--mob-violet-border); } /* ── DARK (overrides) ── */ .dark, [data-mode="dark"] { /* Surfaces */ --mob-bg: #0f172a; /* slate-900 — page */ --mob-surface: #1e293b; /* slate-800 — cards, headers */ --mob-surface-2: #273449; /* elevated: modals, nested cards */ --mob-hover: #334155; /* slate-700 */ --mob-input-bg: #0f172a; /* recessed field */ --mob-border: #334155; /* slate-700 */ --mob-border-subtle: #1e293b; /* slate-800 */ /* Text */ --mob-text: #f8fafc; /* slate-50 */ --mob-text-secondary: #cbd5e1; /* slate-300 */ --mob-text-muted: #94a3b8; /* slate-400 — AA on slate-800 cards (~4.5:1) */ --mob-text-placeholder: #64748b; /* slate-500 */ /* Misc */ --mob-overlay: rgba(2, 6, 23, 0.7); --mob-shadow-card: 0 2px 8px rgba(0, 0, 0, 0.5); --mob-shadow-pop: 0 10px 30px rgba(0, 0, 0, 0.6); --mob-focus-ring: rgba(96, 165, 250, 0.45); /* Blue */ --mob-blue: #3b82f6; /* blue-500 */ --mob-blue-hover: #2563eb; /* blue-600 */ --mob-blue-soft: #60a5fa; /* blue-400 */ --mob-blue-bg: #172554; /* blue-950 */ --mob-blue-fg: #93c5fd; /* blue-300 */ --mob-blue-border: #1e40af; /* blue-800 */ --mob-on-blue: #ffffff; /* Green */ --mob-green: #10b981; /* emerald-500 */ --mob-green-hover: #059669; /* emerald-600 */ --mob-green-soft: #34d399; /* emerald-400 */ --mob-green-bg: #064e3b; /* emerald-900 */ --mob-green-fg: #6ee7b7; /* emerald-300 */ --mob-green-border: #065f46; /* emerald-800 */ --mob-on-green: #ffffff; /* Amber */ --mob-amber: #f59e0b; /* amber-500 */ --mob-amber-hover: #d97706; /* amber-600 */ --mob-amber-soft: #fbbf24; /* amber-400 */ --mob-amber-bg: #422006; /* deep amber */ --mob-amber-fg: #fcd34d; /* amber-300 */ --mob-amber-border: #78350f; /* amber-900 */ --mob-on-amber: #1c1300; /* Red */ --mob-red: #ef4444; /* red-500 */ --mob-red-hover: #dc2626; /* red-600 */ --mob-red-soft: #f87171; /* red-400 */ --mob-red-bg: #450a0a; /* red-950 */ --mob-red-fg: #fca5a5; /* red-300 */ --mob-red-border: #7f1d1d; /* red-900 */ --mob-on-red: #ffffff; /* Violet */ --mob-violet: #a78bfa; /* violet-400 */ --mob-violet-hover: #8b5cf6; /* violet-500 */ --mob-violet-soft: #a78bfa; --mob-violet-bg: #2e1065; /* violet-950 */ --mob-violet-fg: #c4b5fd; /* violet-300 */ --mob-violet-border: #6d28d9; /* violet-700 */ --mob-on-violet: #ffffff; } /* ── Tolerant helper rules ── Apply only INSIDE .mobile-layout (which does not render today; inert but correct if it is ever wired up). Low specificity so page-level scoped styles override them easily. Mobile pages are self-contained and do not rely on these. */ .mobile-layout input, .mobile-layout textarea, .mobile-layout select, .mobile-layout .input, .mobile-layout .textarea, .mobile-layout .select select { background-color: var(--mob-input-bg); color: var(--mob-text); border-color: var(--mob-border); } .mobile-layout input::placeholder, .mobile-layout textarea::placeholder { color: var(--mob-text-placeholder); } .mobile-layout .label { color: var(--mob-text-secondary); } .mobile-layout .title, .mobile-layout .subtitle { color: var(--mob-text); } .mobile-layout .box { background-color: var(--mob-surface); color: var(--mob-text); } .mobile-layout .notification { color: var(--mob-text); } .mobile-layout .modal-card, .mobile-layout .modal-card-head, .mobile-layout .modal-card-body, .mobile-layout .modal-card-foot { background-color: var(--mob-surface); color: var(--mob-text); } /* Mobile completion toast — anchored to the BOTTOM (so it never covers the top header / back button), near full-width, with larger readable text. Applied via toast({ position: 'bottom-center', extraClasses: 'mob-toast-complete' }). */ .notices.bottom { width: 100%; } .notices .mob-toast-complete.notification { width: calc(100vw - 24px) !important; max-width: 620px !important; margin: 0 12px calc(16px + env(safe-area-inset-bottom)) !important; padding: 16px 44px 16px 20px !important; font-size: 16px !important; font-weight: 600 !important; line-height: 1.45 !important; text-align: center !important; border-radius: 14px !important; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.22) !important; letter-spacing: 0.2px; } /* Keep the dismiss (×) tappable and clear of the centered text */ .notices .mob-toast-complete.notification .delete { right: 12px; top: 50%; transform: translateY(-50%); }