diff --git a/apps/machine/public/fonts/Ubuntu-Bold.woff2 b/apps/machine/public/fonts/Ubuntu-Bold.woff2 new file mode 100644 index 0000000..8eaed1f Binary files /dev/null and b/apps/machine/public/fonts/Ubuntu-Bold.woff2 differ diff --git a/apps/machine/public/fonts/Ubuntu-Regular.woff2 b/apps/machine/public/fonts/Ubuntu-Regular.woff2 new file mode 100644 index 0000000..8cb3d32 Binary files /dev/null and b/apps/machine/public/fonts/Ubuntu-Regular.woff2 differ diff --git a/apps/machine/public/fonts/UbuntuMono-Regular.woff2 b/apps/machine/public/fonts/UbuntuMono-Regular.woff2 new file mode 100644 index 0000000..ef1fc70 Binary files /dev/null and b/apps/machine/public/fonts/UbuntuMono-Regular.woff2 differ diff --git a/apps/machine/src/style.css b/apps/machine/src/style.css index dd619fc..60661f0 100644 --- a/apps/machine/src/style.css +++ b/apps/machine/src/style.css @@ -1,6 +1,29 @@ @import 'tailwindcss'; @import 'tw-animate-css'; +/* Ubuntu font family (self-hosted for offline kiosk) */ +@font-face { + font-family: 'Ubuntu'; + src: url('/fonts/Ubuntu-Regular.woff2') format('woff2'); + font-weight: 400; + font-style: normal; + font-display: swap; +} +@font-face { + font-family: 'Ubuntu'; + src: url('/fonts/Ubuntu-Bold.woff2') format('woff2'); + font-weight: 700; + font-style: normal; + font-display: swap; +} +@font-face { + font-family: 'Ubuntu Mono'; + src: url('/fonts/UbuntuMono-Regular.woff2') format('woff2'); + font-weight: 400; + font-style: normal; + font-display: swap; +} + @custom-variant dark (&:where(.dark, .dark *)); @theme inline { @@ -474,6 +497,17 @@ } body { @apply bg-background text-foreground; + font-family: 'Ubuntu', system-ui, sans-serif; + font-size: 1.5rem; + line-height: 1.4; + } +} + +/* Touch feedback for kiosk (no hover available) */ +@media (hover: none) { + button:active, + [role='button']:active { + transform: scale(0.96); } } @@ -526,3 +560,119 @@ @utility animate-hourglass { animation: hourglass 4s steps(8) infinite; } + +/* Monospace utility for addresses/codes */ +@utility font-mono-code { + font-family: 'Ubuntu Mono', ui-monospace, monospace; +} + +/* Three-dot bounce loader */ +@keyframes dot-bounce { + 0%, + 80%, + 100% { + transform: scale(0); + } + 40% { + transform: scale(1); + } +} +@utility animate-dot-bounce { + animation: dot-bounce 1.4s ease-in-out infinite both; +} + +/* QR scanning line */ +@keyframes qr-scan { + 0% { + transform: translateY(0); + opacity: 0; + } + 10% { + opacity: 1; + } + 90% { + opacity: 1; + } + 100% { + transform: translateY(calc(100% - 3px)); + opacity: 0; + } +} +@utility animate-qr-scan { + animation: qr-scan 3s linear infinite; +} + +/* Corner bracket pulse */ +@keyframes corner-pulse { + 0%, + 100% { + opacity: 0.7; + } + 50% { + opacity: 1; + transform: scale(1.05); + } +} +@utility animate-corner-pulse { + animation: corner-pulse 2s ease-in-out infinite; +} + +/* Idle touch zone glow */ +@keyframes zone-glow { + 0%, + 100% { + box-shadow: 0 0 0 0 var(--glow-color, transparent); + } + 50% { + box-shadow: 0 0 40px 8px var(--glow-color, transparent); + } +} +@utility animate-zone-glow { + animation: zone-glow 3s ease-in-out infinite; +} + +/* Vue state transition */ +.state-fade-enter-active, +.state-fade-leave-active { + transition: + opacity 0.3s ease, + transform 0.3s ease; +} +.state-fade-enter-from { + opacity: 0; + transform: translateY(12px); +} +.state-fade-leave-to { + opacity: 0; + transform: translateY(-12px); +} + +/* Step indicator */ +.step-indicator { + display: flex; + align-items: center; + justify-content: center; +} +.step-indicator__dot { + width: 14px; + height: 14px; + border-radius: 50%; + background: var(--muted); + transition: all 0.3s ease; +} +.step-indicator__dot--active { + background: var(--primary); + transform: scale(1.3); +} +.step-indicator__dot--complete { + background: var(--success); +} +.step-indicator__line { + width: 60px; + height: 3px; + background: var(--muted); + transition: background 0.3s; +} +.step-indicator__line--complete { + background: var(--success); +}