// TARGO Tech Module — Mobile-first design tokens + base components // // The tech surface (`/j/*` routes) targets glove-on-screen readability, // one-thumb reach, and TARGO brand identity. We deliberately don't reuse // Quasar's default component chrome here — custom CSS gives us the pill // radii, shadow layering, and motion curves trending design expects. // ── 1. Tokens ──────────────────────────────────────────────────────────────── // Scoped to `.tech-surface` so the rest of the ops app is unaffected. .tech-surface { // TARGO palette — derived from existing #3f3d7a → #5c59a8 gradient --tg-900: #2a2858; // deep night, pressed/active --tg-800: #363566; --tg-700: #3f3d7a; // current header start --tg-500: #5c59a8; // current header end --tg-300: #8b88d4; // tints, subtle accents --tg-100: #dcdaf0; // avatar backgrounds --tg-50: #f2f1fb; // wash backgrounds // Gradients --tg-hero: linear-gradient(135deg, #3f3d7a 0%, #5c59a8 100%); --tg-hero-deep: linear-gradient(160deg, #2a2858 0%, #3f3d7a 60%, #5c59a8 100%); // Signal — tuned warmer than Quasar defaults, better color-blind legibility --sig-go: #10b981; // Completed / success --sig-work: #f59e0b; // In Progress --sig-stop: #ef4444; // Urgent / error --sig-wait: #94a3b8; // On Hold (chain-blocked, invisible to tech) --sig-info: #3b82f6; // Scheduled, neutral // Surface + ink (warmer than current #eef1f5) --surface: #fafbfd; --surface-elev: #ffffff; --surface-wash: #f2f1fb; // same as --tg-50 --surface-over: rgba(255,255,255,0.88); // for floating islands with backdrop blur --ink-900: #0f172a; --ink-700: #334155; --ink-500: #64748b; --ink-400: #94a3b8; --ink-300: #cbd5e1; // Elevation system (two-layer lift, not a single fat drop shadow) --elev-1: 0 1px 2px rgba(15,23,42,0.04), 0 2px 6px rgba(15,23,42,0.03); --elev-2: 0 2px 8px rgba(15,23,42,0.06), 0 12px 32px rgba(15,23,42,0.04); --elev-3: 0 4px 14px rgba(15,23,42,0.08), 0 24px 48px rgba(15,23,42,0.06); --elev-fab: 0 8px 24px rgba(16,185,129,0.35); --elev-fab-purple: 0 8px 24px rgba(92,89,168,0.35); // Radii --r-sm: 10px; --r-md: 16px; --r-lg: 20px; --r-xl: 28px; --r-pill: 999px; // Motion — Apple spring for page-level, shorter spring for micro --ease-spring: cubic-bezier(0.32, 0.72, 0, 1); --ease-micro: cubic-bezier(0.4, 0, 0.2, 1); --dur-fast: 160ms; --dur-mid: 240ms; --dur-slow: 360ms; // Type scale --t-display: 600 2rem/1.1 system-ui, -apple-system, sans-serif; // 32px hero --t-h1: 700 1.5rem/1.2 system-ui, -apple-system, sans-serif; // 24px --t-h2: 700 1.25rem/1.25 system-ui, -apple-system, sans-serif; // 20px --t-body: 500 1rem/1.4 system-ui, -apple-system, sans-serif; // 16px --t-body-sm: 500 0.9375rem/1.4 system-ui, -apple-system, sans-serif; // 15px --t-caption: 500 0.8125rem/1.3 system-ui, -apple-system, sans-serif; // 13px --t-micro: 600 0.6875rem/1.2 system-ui, -apple-system, sans-serif; // 11px // Base surface background: var(--surface); color: var(--ink-900); min-height: 100vh; font-feature-settings: 'cv11', 'ss01'; // nicer tabular digits } // Every tech page needs room below its content for the floating tab island // (96px pill + 16px margin + safe-area). We do this with a utility class // `.tg-page` so pages opt in explicitly, and for the legacy Quasar // `` pages we extend that element with extra padding too. .tech-surface.q-page { padding-bottom: calc(96px + env(safe-area-inset-bottom)) !important; } // ── 2. Typography utilities ───────────────────────────────────────────────── .tech-surface { .t-display { font: var(--t-display); letter-spacing: -0.02em; } .t-h1 { font: var(--t-h1); letter-spacing: -0.01em; } .t-h2 { font: var(--t-h2); letter-spacing: -0.005em; } .t-body { font: var(--t-body); } .t-body-sm { font: var(--t-body-sm); } .t-caption { font: var(--t-caption); color: var(--ink-500); } .t-micro { font: var(--t-micro); text-transform: uppercase; letter-spacing: 0.08em; color: var(--ink-500); } .t-ink-900 { color: var(--ink-900); } .t-ink-700 { color: var(--ink-700); } .t-ink-500 { color: var(--ink-500); } .t-ink-400 { color: var(--ink-400); } .t-ink-on-hero { color: rgba(255,255,255,0.95); } .t-ink-on-hero-dim { color: rgba(255,255,255,0.7); } } // ── 3. Card — elevated pill-radius, no borders ────────────────────────────── .tech-surface { .tg-card { background: var(--surface-elev); border-radius: var(--r-lg); box-shadow: var(--elev-2); padding: 18px; transition: transform var(--dur-fast) var(--ease-micro), box-shadow var(--dur-fast) var(--ease-micro); &.tg-card--wash { background: var(--surface-wash); box-shadow: none; } &.tg-card--flat { box-shadow: var(--elev-1); } &.tg-card--tap { cursor: pointer; -webkit-tap-highlight-color: transparent; &:active { transform: scale(0.985); box-shadow: var(--elev-1); } } &.tg-card--done { opacity: 0.62; } } } // ── 4. Status chip — pill badge (replaces border-left indicator) ──────────── .tech-surface { .tg-chip { display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px; border-radius: var(--r-pill); font: var(--t-micro); white-space: nowrap; .tg-chip-dot { width: 6px; height: 6px; border-radius: 50%; display: inline-block; } &.is-go { background: rgba(16,185,129,0.12); color: #047857; .tg-chip-dot { background: var(--sig-go); } } &.is-work { background: rgba(245,158,11,0.14); color: #b45309; .tg-chip-dot { background: var(--sig-work); } } &.is-stop { background: rgba(239,68,68,0.12); color: #b91c1c; .tg-chip-dot { background: var(--sig-stop); } } &.is-wait { background: rgba(148,163,184,0.16); color: #475569; .tg-chip-dot { background: var(--sig-wait); } } &.is-info { background: rgba(59,130,246,0.12); color: #1d4ed8; .tg-chip-dot { background: var(--sig-info); } } &.is-tg { background: rgba(92,89,168,0.12); color: var(--tg-700); .tg-chip-dot { background: var(--tg-500); } } } } // ── 5. Button system — pill, FAB, ghost ───────────────────────────────────── .tech-surface { .tg-btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; min-height: 52px; padding: 0 24px; border: 0; border-radius: var(--r-pill); font: 700 1rem/1 system-ui, -apple-system, sans-serif; letter-spacing: 0.01em; cursor: pointer; transition: transform var(--dur-fast) var(--ease-micro), box-shadow var(--dur-fast) var(--ease-micro), background var(--dur-fast) var(--ease-micro); -webkit-tap-highlight-color: transparent; user-select: none; &:disabled { opacity: 0.5; cursor: not-allowed; } &:active:not(:disabled) { transform: scale(0.97); } &.is-block { width: 100%; } // Variants &.is-primary { background: var(--tg-700); color: #fff; box-shadow: var(--elev-fab-purple); &:active { background: var(--tg-900); } } &.is-success { background: var(--sig-go); color: #fff; box-shadow: var(--elev-fab); &:active { background: #059669; } } &.is-warning { background: var(--sig-work); color: #fff; box-shadow: 0 8px 24px rgba(245,158,11,0.35); } &.is-ghost { background: var(--surface-wash); color: var(--tg-700); box-shadow: none; &:active { background: var(--tg-100); } } &.is-outline { background: transparent; color: var(--tg-700); box-shadow: inset 0 0 0 1.5px var(--tg-300); } &.is-text { background: transparent; color: var(--tg-700); box-shadow: none; min-height: 40px; padding: 0 12px; } &.is-compact { min-height: 40px; padding: 0 16px; font-size: 0.9375rem; } } // Sticky floating CTA pill — sits above the tab bar .tg-fab-cta { position: fixed; left: 16px; right: 16px; bottom: calc(var(--tab-island-bottom, 88px) + env(safe-area-inset-bottom)); z-index: 20; } } // ── 6. Hero header — big gradient banner ──────────────────────────────────── .tech-surface { .tg-hero { background: var(--tg-hero-deep); color: #fff; padding: 18px 18px 28px; border-radius: 0 0 var(--r-xl) var(--r-xl); position: relative; overflow: hidden; // Subtle radial highlight for depth &::before { content: ''; position: absolute; inset: 0; background: radial-gradient(1200px 400px at 85% -20%, rgba(255,255,255,0.14), transparent 60%); pointer-events: none; } .tg-hero-inner { position: relative; z-index: 1; } } } // ── 7. Floating tab island (bottom nav) ───────────────────────────────────── .tech-surface .tg-tab-island, .tg-tab-island { position: fixed; left: 16px; right: 16px; bottom: calc(16px + env(safe-area-inset-bottom)); height: 64px; border-radius: var(--r-xl); background: var(--surface-over); backdrop-filter: saturate(180%) blur(22px); -webkit-backdrop-filter: saturate(180%) blur(22px); box-shadow: var(--elev-3); border: 1px solid rgba(15,23,42,0.04); display: flex; align-items: center; justify-content: space-around; z-index: 30; padding: 0 8px; .tg-tab { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; height: 56px; border-radius: var(--r-md); cursor: pointer; color: var(--ink-500); transition: color var(--dur-fast) var(--ease-micro); -webkit-tap-highlight-color: transparent; text-decoration: none; .tg-tab-icon { font-size: 24px; line-height: 1; } .tg-tab-label { font: var(--t-micro); } &.is-active { color: var(--tg-700); .tg-tab-icon { transform: translateY(-1px); } } &:active { background: var(--tg-50); } } } // ── 8. Page spacing (reserve room for floating tab island) ────────────────── // Bottom-room is handled at the q-page level (.tech-surface.q-page above), // so inner content containers don't need to add their own bottom padding — // they just flow naturally and the tab-island gap is guaranteed. .tech-surface .tg-page { min-height: 100vh; } // ── 9. Peek sheet (bottom card that slides up) ────────────────────────────── .tech-surface { .tg-peek-backdrop { position: fixed; inset: 0; z-index: 40; background: rgba(15,23,42,0.4); backdrop-filter: blur(2px); opacity: 0; pointer-events: none; transition: opacity var(--dur-mid) var(--ease-micro); &.is-open { opacity: 1; pointer-events: auto; } } .tg-peek { position: fixed; left: 0; right: 0; bottom: 0; z-index: 41; background: var(--surface-elev); border-radius: var(--r-xl) var(--r-xl) 0 0; box-shadow: var(--elev-3); padding: 8px 0 calc(16px + env(safe-area-inset-bottom)); transform: translateY(100%); transition: transform var(--dur-mid) var(--ease-spring); max-height: 82vh; overflow-y: auto; overscroll-behavior: contain; &.is-open { transform: translateY(0); } .tg-peek-handle { width: 40px; height: 4px; border-radius: 2px; background: var(--ink-300); margin: 6px auto 4px; } } } // ── 10. Progress arc (SVG ring for hero stat) ─────────────────────────────── .tech-surface { .tg-arc { position: relative; display: inline-flex; align-items: center; justify-content: center; svg { transform: rotate(-90deg); } .tg-arc-track { stroke: rgba(255,255,255,0.16); fill: none; } .tg-arc-fill { stroke: #fff; fill: none; stroke-linecap: round; transition: stroke-dashoffset var(--dur-slow) var(--ease-spring); } .tg-arc-center { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; } } } // ── 11. Offline / system banner ───────────────────────────────────────────── .tech-surface .tg-banner { position: fixed; top: env(safe-area-inset-top); left: 0; right: 0; z-index: 50; padding: 6px 16px; background: var(--sig-stop); color: #fff; font: var(--t-caption); text-align: center; display: flex; align-items: center; justify-content: center; gap: 6px; } // ── 12. Avatar ────────────────────────────────────────────────────────────── .tech-surface .tg-avatar { width: 40px; height: 40px; border-radius: 50%; background: var(--tg-900); color: #fff; display: inline-flex; align-items: center; justify-content: center; font: 700 0.875rem/1 system-ui; letter-spacing: 0.02em; } // ── 13. Route transitions (slide-up for card→detail) ──────────────────────── .tech-slide-enter-active, .tech-slide-leave-active { transition: transform var(--dur-mid) var(--ease-spring), opacity var(--dur-mid) var(--ease-micro); } .tech-slide-enter-from { transform: translateY(24px); opacity: 0; } .tech-slide-leave-to { transform: translateY(24px); opacity: 0; }