import 'package:flutter/material.dart'; /// Design tokens. Every colour, radius, shadow and text style in the app comes /// from here — screens never hardcode a value. /// /// Direction (2026-09-15 rebuild, from the 14-screen design): /// /// **Edges, not elevation.** Surfaces are separated by a 1px warm hairline and /// a 10pt radius, not by a shadow. The only shadows left in the system are the /// crimson glow under the one committing action on a screen, the float under a /// control that genuinely hovers over a map, and the sheet lift. A screen that /// drops shadows everywhere has no way left to say "this one matters". /// /// **One accent, three intensities.** Crimson fills the header and the primary /// action, washes (`brandSoft` over `brandLine`) carry supporting information, /// and everything else is warm neutral. There is no second hue competing for /// meaning — `ok` survives only for the delivered state, `danger` only for /// destructive text. /// /// **Manrope for voice, Geist Mono for data.** Headings run at w800 with tight /// negative tracking; anything a customer might read back aloud or check /// digit-by-digit — a booking reference, a phone number, a fare, a plate, a /// countdown — is set in mono so the glyphs line up and a transposed character /// is visible. class DmColors { DmColors._(); // ── Brand ──────────────────────────────────────────────────────────────── /// The mark's single colour. static const brand = Color(0xFF8F0F06); /// Pressed state, and crimson text sitting on a [brandSoft] wash where the /// full brand would vibrate against the tint. static const brandPress = Color(0xFF730C05); static const brandDeep = brandPress; /// Tint behind selected options, wash cards and brand chips. static const brandSoft = Color(0xFFFBF3F2); /// The wash's own edge, and the outline on quiet brand buttons. static const brandLine = Color(0xFFF0DEDC); // ── Ink — warm neutrals, never pure black ──────────────────────────────── static const ink = Color(0xFF191716); static const ink2 = Color(0xFF5C5654); static const ink3 = Color(0xFF6E6864); static const ink4 = Color(0xFFB4AEAA); // ── Surfaces ───────────────────────────────────────────────────────────── /// The page canvas. static const canvas = Color(0xFFF7F6F4); static const surface = Color(0xFFFFFFFF); /// Filled inputs, quiet chips, tiles, skeleton bases. Also the "sunken" /// treatment for a disabled primary action. static const surfaceAlt = Color(0xFFF1EFEC); /// Barely-there divider between rows inside one card. static const hairline = Color(0xFFF1EFEC); /// A card's own edge — the workhorse of this design. static const border = Color(0xFFE8E5E2); // ── On-brand text ──────────────────────────────────────────────────────── /// Secondary text on a crimson field. Not white-at-opacity: a tinted rose /// keeps its warmth where translucent white goes grey and dirty. static const onBrand2 = Color(0xFFFFD9D4); /// Tertiary text on a crimson field. static const onBrand3 = Color(0xFFFFD1CB); /// Recessed track inside the header (the segmented control's bed). static const onBrandSunken = Color(0x24000000); /// A control resting on the crimson field. static const onBrandRaise = Color(0x2EFFFFFF); // ── Semantic ───────────────────────────────────────────────────────────── static const ok = Color(0xFF0A6B56); static const okSoft = Color(0xFFE2F4EF); static const danger = Color(0xFFB3231F); /// "You are here" on a map. Deliberately not the brand crimson — on a map /// crimson means the pickup pin, and blue is the convention every customer /// already reads as their own position. static const locationDot = Color(0xFF1B6EF3); static const locationHalo = Color(0x241B6EF3); static const scrim = Color(0x80191716); // Backwards-compatible aliases used across the widget layer. static const bg = canvas; static const surface2 = surfaceAlt; static const line = hairline; static const lineStrong = border; } class DmRadius { DmRadius._(); /// Tiles, chips, the small square that holds a glyph. static const xs = 8.0; /// Buttons, fields, icon buttons. The design's most-used corner. static const sm = 9.0; /// Cards and every panel that holds rows. static const md = 10.0; /// Sheets' grabber area, the segmented control, the header's bottom sweep. static const lg = 12.0; /// Bottom sheets and the auth sheet that overlaps the hero. static const xl = 16.0; /// The brand header's bottom corners. static const header = 18.0; static const pill = 999.0; /// Kept for call sites that mean "a primary bar's corner". static const book = sm; static BorderRadius all(double r) => BorderRadius.circular(r); } class DmSpace { DmSpace._(); /// Horizontal page padding. 22 on the brand header's body, 24 on canvas /// content — the header's crimson field reads as tighter than it measures, /// so it takes the smaller inset. static const pad = 24.0; static const headerPad = 22.0; /// Minimum touch target. static const tap = 48.0; /// Primary button height. static const button = 54.0; /// Field height — matched to [button] so a form and its action share a rhythm. static const field = 54.0; } class DmShadow { DmShadow._(); /// Under the one committing action on a screen, and under a selected slot. static const lift = [ BoxShadow( color: Color(0x808F0F06), blurRadius: 24, spreadRadius: -12, offset: Offset(0, 10), ), ]; /// A smaller version of [lift] for chips and half-width controls. static const liftSm = [ BoxShadow( color: Color(0xA68F0F06), blurRadius: 16, spreadRadius: -8, offset: Offset(0, 7), ), ]; /// Controls that genuinely float over content — map buttons, map chips. static const float = [ BoxShadow( color: Color(0x0D191716), blurRadius: 2, offset: Offset(0, 1), ), ]; static const sheet = [ BoxShadow( color: Color(0x2E191716), blurRadius: 40, spreadRadius: -20, offset: Offset(0, -8), ), ]; // Aliases kept for existing call sites. static const two = float; static const three = sheet; } class DmMotion { DmMotion._(); static const fast = Duration(milliseconds: 140); static const base = Duration(milliseconds: 250); static const slow = Duration(milliseconds: 460); static const ease = Curves.easeOutCubic; /// The bottom nav's travelling pill — a touch of overshoot, which reads as /// the indicator catching up rather than teleporting. static const glide = Cubic(0.34, 1.06, 0.36, 1); } /// Manrope for voice, Geist Mono for data. /// /// Both ship as single variable-font files, which is why every style below sets /// `fontVariations` as well as `fontWeight` — see the note inside the class. class DmText { DmText._(); static const _f = 'Manrope'; static const _mono = 'GeistMono'; // The weight axis. Manrope and Geist Mono both ship as variable fonts, so a // style has to move `wght` to change weight — `fontWeight` alone picks the // nearest named instance and, on a single-file VF, that is always the // default. Both are set on every style: the axis does the work, the enum // keeps the semantics (and the system-font fallback) correct. static const _w500 = [FontVariation('wght', 500)]; static const _w600 = [FontVariation('wght', 600)]; static const _w700 = [FontVariation('wght', 700)]; static const _w800 = [FontVariation('wght', 800)]; // Letter spacing is quoted in em by the design and converted here at each // size, because -0.035em is a different number of pixels on a 31pt display // head than on a 15pt row title, and splitting the difference would soften // exactly the heads that are supposed to feel tight. // ── Display ────────────────────────────────────────────────────────────── /// Screen-dominating statement — "Pickup booked", "Arun is 12 minutes away". static const display = TextStyle( fontFamily: _f, fontSize: 31, height: 1.12, fontWeight: FontWeight.w800, fontVariations: _w800, letterSpacing: -1.09, color: DmColors.ink, ); /// The brand header's own title, sitting on crimson. static const headerTitle = TextStyle( fontFamily: _f, fontSize: 34, height: 1.0, fontWeight: FontWeight.w800, fontVariations: _w800, letterSpacing: -1.36, color: Colors.white, ); /// Screen headings on a canvas. static const title = TextStyle( fontFamily: _f, fontSize: 25, height: 1.18, fontWeight: FontWeight.w800, fontVariations: _w800, letterSpacing: -0.75, color: DmColors.ink, ); /// Tab-root page titles where no brand header is used. static const pageTitle = title; /// The heading above a group of cards, and a sheet's own title. static const heading = TextStyle( fontFamily: _f, fontSize: 18, height: 1.25, fontWeight: FontWeight.w700, fontVariations: _w700, letterSpacing: -0.45, color: DmColors.ink, ); static const sheetTitle = TextStyle( fontFamily: _f, fontSize: 19, height: 1.2, fontWeight: FontWeight.w800, fontVariations: _w800, letterSpacing: -0.57, color: DmColors.ink, ); // ── Rows ───────────────────────────────────────────────────────────────── /// A row's own line — `t1` in the design, and the workhorse of the app. static const cardTitle = TextStyle( fontFamily: _f, fontSize: 15, height: 1.4, fontWeight: FontWeight.w700, fontVariations: _w700, letterSpacing: -0.18, color: DmColors.ink, ); /// Alias: the same weight of statement, used mid-form. static const bodyStrong = cardTitle; static const body = TextStyle( fontFamily: _f, fontSize: 15, height: 1.5, fontWeight: FontWeight.w500, fontVariations: _w500, letterSpacing: -0.12, color: DmColors.ink, ); /// Supporting line under a row title — `t2`. static const small = TextStyle( fontFamily: _f, fontSize: 13.5, height: 1.45, fontWeight: FontWeight.w500, fontVariations: _w500, color: DmColors.ink2, ); /// The quietest line — `t3`. Timestamps, counts, "collected on". static const tiny = TextStyle( fontFamily: _f, fontSize: 13, height: 1.4, fontWeight: FontWeight.w500, fontVariations: _w500, color: DmColors.ink3, ); /// Paragraph under a screen heading. static const lede = TextStyle( fontFamily: _f, fontSize: 14.5, height: 1.55, fontWeight: FontWeight.w500, fontVariations: _w500, color: DmColors.ink2, ); /// The right-hand value in a settings row. static const value = TextStyle( fontFamily: _f, fontSize: 13.5, height: 1.4, fontWeight: FontWeight.w600, fontVariations: _w600, color: DmColors.ink2, ); /// Field labels, tags, chips, inline actions. static const label = TextStyle( fontFamily: _f, fontSize: 12.5, height: 1.3, fontWeight: FontWeight.w700, fontVariations: _w700, color: DmColors.ink2, ); static const button = TextStyle( fontFamily: _f, fontSize: 15.5, height: 1.2, fontWeight: FontWeight.w700, fontVariations: _w700, letterSpacing: -0.23, ); /// The text-only action under a primary button ("Back to home"). static const textButton = TextStyle( fontFamily: _f, fontSize: 14.5, height: 1.2, fontWeight: FontWeight.w700, fontVariations: _w700, color: DmColors.ink2, ); /// Uppercase micro-label above a group — the design's `micro`. Crimson when /// it heads brand content, [DmColors.ink3] when it heads a neutral group. static const eyebrow = TextStyle( fontFamily: _f, fontSize: 10.5, height: 1.3, fontWeight: FontWeight.w700, fontVariations: _w700, letterSpacing: 1.16, color: DmColors.ink3, ); /// The eyebrow as it appears on the crimson header. static const headerEyebrow = TextStyle( fontFamily: _f, fontSize: 11.5, height: 1.3, fontWeight: FontWeight.w800, fontVariations: _w800, letterSpacing: 1.84, color: DmColors.onBrand3, ); /// Sentence-case heading above a group of rows. static const sectionHead = TextStyle( fontFamily: _f, fontSize: 15, height: 1.3, fontWeight: FontWeight.w700, fontVariations: _w700, letterSpacing: -0.3, color: DmColors.ink, ); /// Alias kept for existing call sites. static const groupHead = sectionHead; /// Field input text. static const field = TextStyle( fontFamily: _f, fontSize: 16, height: 1.3, fontWeight: FontWeight.w600, fontVariations: _w600, color: DmColors.ink, ); // ── Mono: anything checkable digit by digit ────────────────────────────── /// References, plates and phone numbers sitting inline in a row. static const mono = TextStyle( fontFamily: _mono, fontSize: 13, height: 1.4, fontWeight: FontWeight.w500, fontVariations: _w500, letterSpacing: -0.26, color: DmColors.ink3, ); /// Step counters, timers, the smallest data. static const monoSm = TextStyle( fontFamily: _mono, fontSize: 11.5, height: 1.3, fontWeight: FontWeight.w500, fontVariations: _w500, letterSpacing: -0.23, color: DmColors.ink3, ); /// A booking reference given its own line, or a fare. static const monoLg = TextStyle( fontFamily: _mono, fontSize: 19, height: 1.2, fontWeight: FontWeight.w500, fontVariations: _w500, letterSpacing: -0.38, color: DmColors.ink, ); /// The OTP digits. static const otp = TextStyle( fontFamily: _f, fontSize: 24, height: 1.1, fontWeight: FontWeight.w700, fontVariations: _w700, color: DmColors.ink, ); }