@import "tailwindcss"; @import "./tw-animate.css"; @import "./shadcn-tailwind.css"; @custom-variant dark (&:is(.dark *)); /* The landing site's faces, self-hosted (served from /static/fonts/ by embed.go). Latin + Latin Extended only; other scripts fall back. */ @font-face { font-family: "Schibsted Grotesk Variable"; font-style: normal; font-display: swap; font-weight: 400 900; src: url(/static/fonts/schibsted-grotesk-latin-wght-normal.woff2) format("woff2-variations"); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } @font-face { font-family: "Schibsted Grotesk Variable"; font-style: normal; font-display: swap; font-weight: 400 900; src: url(/static/fonts/schibsted-grotesk-latin-ext-wght-normal.woff2) format("woff2-variations"); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; } @font-face { font-family: "JetBrains Mono Variable"; font-style: normal; font-display: swap; font-weight: 100 800; src: url(/static/fonts/jetbrains-mono-latin-wght-normal.woff2) format("woff2-variations"); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } @font-face { font-family: "JetBrains Mono Variable"; font-style: normal; font-display: swap; font-weight: 100 800; src: url(/static/fonts/jetbrains-mono-latin-ext-wght-normal.woff2) format("woff2-variations"); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; } @source "../*.templ"; @source "../../components/**/*.templ"; @theme { /* Readability floor: nothing renders below 16px. Tailwind's xs (12px) and sm (14px) steps, used across the templates and the vendored shadcn components, are pinned to the base size. */ --text-xs: 1rem; --text-xs--line-height: 1.5rem; --text-sm: 1rem; --text-sm--line-height: 1.5rem; --color-smart-blue-50: #eef0f6; --color-smart-blue-100: #dee2ed; --color-smart-blue-200: #bdc4db; --color-smart-blue-300: #9ca7c9; --color-smart-blue-400: #7a8ab8; --color-smart-blue-500: #596ca6; --color-smart-blue-600: #475785; --color-smart-blue-700: #364163; --color-smart-blue-800: #242b42; --color-smart-blue-900: #121621; --color-smart-blue-950: #0c0f17; --color-french-blue-50: #edf0f7; --color-french-blue-100: #dbe0f0; --color-french-blue-200: #b8c2e0; --color-french-blue-300: #94a3d1; --color-french-blue-400: #7085c2; --color-french-blue-500: #4d66b3; --color-french-blue-600: #3d528f; --color-french-blue-700: #2e3d6b; --color-french-blue-800: #1f2947; --color-french-blue-900: #0f1424; --color-french-blue-950: #0b0e19; --color-light-gold-50: #fdf8e8; --color-light-gold-100: #fbf1d0; --color-light-gold-200: #f6e3a2; --color-light-gold-300: #f2d473; --color-light-gold-400: #eec644; --color-light-gold-500: #e9b816; --color-light-gold-600: #bb9311; --color-light-gold-700: #8c6e0d; --color-light-gold-800: #5d4a09; --color-light-gold-900: #2f2504; --color-light-gold-950: #211a03; --color-tangerine-dream-50: #feeee7; --color-tangerine-dream-100: #fcddcf; --color-tangerine-dream-200: #f9bb9f; --color-tangerine-dream-300: #f79a6e; --color-tangerine-dream-400: #f4783e; --color-tangerine-dream-500: #f1560e; --color-tangerine-dream-600: #c1450b; --color-tangerine-dream-700: #913408; --color-tangerine-dream-800: #602206; --color-tangerine-dream-900: #301103; --color-tangerine-dream-950: #220c02; --color-vibrant-coral-50: #fee9e7; --color-vibrant-coral-100: #fdd2ce; --color-vibrant-coral-200: #faa59e; --color-vibrant-coral-300: #f8786d; --color-vibrant-coral-400: #f64c3c; --color-vibrant-coral-500: #f41f0b; --color-vibrant-coral-600: #c31909; --color-vibrant-coral-700: #921207; --color-vibrant-coral-800: #610c05; --color-vibrant-coral-900: #310602; --color-vibrant-coral-950: #220402; --color-muted-teal-50: #f0f5ef; --color-muted-teal-100: #e0ebe0; --color-muted-teal-200: #c1d8c0; --color-muted-teal-300: #a3c4a1; --color-muted-teal-400: #84b082; --color-muted-teal-500: #659d62; --color-muted-teal-600: #517d4f; --color-muted-teal-700: #3d5e3b; --color-muted-teal-800: #283f27; --color-muted-teal-900: #141f14; --color-muted-teal-950: #0e160e; --shadow-card: 0 1px 2px rgb(18 22 33 / 0.08), 0 4px 16px rgb(54 65 99 / 0.08); --shadow-popover: 0 8px 24px rgb(18 22 33 / 0.16); --shadow-focus: 0 0 0 3px rgb(77 102 179 / 0.5); } @theme inline { --font-sans: "Schibsted Grotesk Variable", "Helvetica Neue", Arial, sans-serif; --font-heading: var(--font-sans); --font-mono: "JetBrains Mono Variable", ui-monospace, SFMono-Regular, Menlo, monospace; --color-background: var(--background); --color-foreground: var(--foreground); --color-card: var(--card); --color-card-foreground: var(--card-foreground); --color-popover: var(--popover); --color-popover-foreground: var(--popover-foreground); --color-primary: var(--primary); --color-primary-foreground: var(--primary-foreground); --color-secondary: var(--secondary); --color-secondary-foreground: var(--secondary-foreground); --color-muted: var(--muted); --color-muted-foreground: var(--muted-foreground); --color-accent: var(--accent); --color-accent-foreground: var(--accent-foreground); --color-destructive: var(--destructive); --color-success: var(--success); --color-success-foreground: var(--success-foreground); --color-border: var(--border); --color-input: var(--input); --color-ring: var(--ring); --color-sky: var(--sky); --color-chart-1: var(--chart-1); --color-chart-2: var(--chart-2); --color-chart-3: var(--chart-3); --color-chart-4: var(--chart-4); --color-chart-5: var(--chart-5); --radius-sm: calc(var(--radius) * 0.6); --radius-md: calc(var(--radius) * 0.8); --radius-lg: var(--radius); --radius-xl: calc(var(--radius) * 1.4); --radius-2xl: calc(var(--radius) * 1.8); --radius-3xl: calc(var(--radius) * 2.2); --radius-4xl: calc(var(--radius) * 2.6); --color-sidebar: var(--sidebar); --color-sidebar-foreground: var(--sidebar-foreground); --color-sidebar-primary: var(--sidebar-primary); --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); --color-sidebar-accent: var(--sidebar-accent); --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); --color-sidebar-border: var(--sidebar-border); --color-sidebar-ring: var(--sidebar-ring); } :root { --background: #eef0f6; --foreground: #121621; --card: #ffffff; --card-foreground: #121621; --popover: #ffffff; --popover-foreground: #121621; --primary: #364163; --primary-foreground: #ffffff; --secondary: #dee2ed; --secondary-foreground: #242b42; --muted: #dee2ed; --muted-foreground: #475785; --accent: #fbf1d0; --accent-foreground: #5d4a09; --destructive: #c31909; --success: #517d4f; --success-foreground: #ffffff; --border: #bdc4db; --input: #bdc4db; --ring: #4d66b3; --sky: #7085c2; --chart-1: #4d66b3; --chart-2: #f1560e; --chart-3: #e9b816; --chart-4: #596ca6; --chart-5: #f41f0b; --radius: 0.625rem; --sidebar: #eef0f6; --sidebar-foreground: #121621; --sidebar-primary: #364163; --sidebar-primary-foreground: #ffffff; --sidebar-accent: #fbf1d0; --sidebar-accent-foreground: #5d4a09; --sidebar-border: #bdc4db; --sidebar-ring: #4d66b3; } .dark { --background: #0c0f17; --foreground: #eef0f6; --card: #121621; --card-foreground: #eef0f6; --popover: #121621; --popover-foreground: #eef0f6; --primary: #bdc4db; --primary-foreground: #0c0f17; --secondary: #364163; --secondary-foreground: #eef0f6; --muted: #242b42; --muted-foreground: #9ca7c9; --accent: #5d4a09; --accent-foreground: #fdf8e8; --destructive: #f8786d; --success: #84b082; --success-foreground: #0c0f17; --border: #364163; --input: #364163; --ring: #94a3d1; --sky: #94a3d1; --chart-1: #94a3d1; --chart-2: #f79a6e; --chart-3: #f2d473; --chart-4: #7a8ab8; --chart-5: #f8786d; --sidebar: #0c0f17; --sidebar-foreground: #eef0f6; --sidebar-primary: #bdc4db; --sidebar-primary-foreground: #0c0f17; --sidebar-accent: #5d4a09; --sidebar-accent-foreground: #fdf8e8; --sidebar-border: #364163; --sidebar-ring: #94a3d1; } @layer base { * { @apply border-border outline-ring/50; } body { @apply bg-background text-foreground; } ::selection { background: var(--color-tangerine-dream-500); color: #fff; } :where(a, button, input, [tabindex]):focus-visible { outline: none; } input, textarea { caret-color: var(--color-tangerine-dream-500); } code, kbd, samp { font-variant-numeric: tabular-nums; font-feature-settings: "zero" 1; } a { text-underline-offset: 4px; } [data-slot="card"] { box-shadow: 0 1px 2px rgb(18 22 33 / 0.08), 0 4px 16px rgb(54 65 99 / 0.08); } .dark [data-slot="card"] { box-shadow: 0 1px 2px rgb(0 0 0 / 0.3), 0 8px 24px rgb(0 0 0 / 0.35); } ::-webkit-scrollbar { width: 10px; height: 10px; } ::-webkit-scrollbar-thumb { background: #9ca7c9; border-radius: 9999px; border: 2px solid var(--background); } ::-webkit-scrollbar-thumb:hover { background: rgb(112 133 194 / 0.7); } } /* Handle typeahead (static/typeahead.js builds these rows in JS, outside Tailwind's sources): square rows in the brand palette, handles in mono. */ @layer components { [data-typeahead-list] { border-radius: 0; border: 2px solid var(--color-french-blue-700); background: var(--color-smart-blue-50); box-shadow: none; } [data-typeahead-list] button { color: var(--color-smart-blue-900); } [data-typeahead-list] button:hover, [data-typeahead-list] [aria-selected="true"] button { background: var(--color-light-gold-100); } [data-typeahead-list] img { border-radius: 0; } [data-typeahead-list] button > span:first-of-type { font-family: var(--font-mono); font-weight: 500; } [data-typeahead-list] button > span:last-of-type { color: var(--color-smart-blue-600); } } /* Copy confirmation (static/app.js builds the chip in JS, outside Tailwind's sources): a square success chip that rises into the fixed lower-right region, so confirming a copy never shifts the layout. */ @layer components { .copy-toaster { position: fixed; right: max(1rem, env(safe-area-inset-right)); bottom: max(1rem, env(safe-area-inset-bottom)); z-index: 50; pointer-events: none; } .copy-toast { display: inline-flex; align-items: center; gap: 0.375rem; padding: 0.5rem 0.875rem; background: var(--success); color: var(--success-foreground); font-size: 1rem; font-weight: 700; box-shadow: var(--shadow-popover); animation: copy-toast-in 180ms cubic-bezier(0.16, 1, 0.3, 1); } .copy-toast svg { width: 1rem; height: 1rem; } .copy-toast[data-leaving] { animation: copy-toast-out 160ms ease-in forwards; } @keyframes copy-toast-in { from { opacity: 0; translate: 0 0.75rem; } } @keyframes copy-toast-out { to { opacity: 0; translate: 0 0.375rem; } } @media (prefers-reduced-motion: reduce) { .copy-toast { animation-name: copy-toast-fade-in; } .copy-toast[data-leaving] { animation-name: copy-toast-fade-out; } } @keyframes copy-toast-fade-in { from { opacity: 0; } } @keyframes copy-toast-fade-out { to { opacity: 0; } } } /* The landing page's postal cell field (site WaitlistForm): each character lands in its own cell. A mono advance of 1ch plus letter-spacing equals one cell; dotted ticks inset from the frame mark the cells without competing with the text. Long values (DIDs) scroll inside the field. .cell-grid sets the cell module; .cell-width snaps a column (form, rules, ledger) to a whole number of cells, so the field frame, the button and the head rules all share one right edge. */ @layer components { .cell-grid { --cell: 1.75rem; } .cell-width { width: min(calc(20 * var(--cell) + 4px), calc(round(down, 100% - 4px, var(--cell)) + 4px)); } .cell-field { position: relative; display: block; width: 100%; min-width: 0; } .cell-field::after { content: ""; position: absolute; inset: 0.85rem 2px; pointer-events: none; background: linear-gradient(to bottom, var(--color-french-blue-700) 0 2px, transparent 2px 5px) 0 0 / 100% 5px; opacity: 0.4; -webkit-mask: repeating-linear-gradient(to right, transparent 0 calc(var(--cell) - 1px), #000 calc(var(--cell) - 1px) var(--cell)); mask: repeating-linear-gradient(to right, transparent 0 calc(var(--cell) - 1px), #000 calc(var(--cell) - 1px) var(--cell)); } .cell-field input { display: block; width: 100%; height: 3.5rem; margin: 0; padding: 0 0 0 calc((var(--cell) - 1ch) / 2); border: 2px solid var(--color-french-blue-700); border-radius: 0; background: transparent; color: var(--color-french-blue-700); font-family: var(--font-mono); font-size: 1.25rem; font-weight: 700; letter-spacing: calc(var(--cell) - 1ch); appearance: none; transition: background-color 0.2s ease-out; } .cell-field input::placeholder { color: var(--color-french-blue-700); opacity: 0.8; } .cell-field input:focus-visible { outline: 3px solid var(--color-french-blue-700); outline-offset: 3px; background-color: rgb(251 241 208 / 0.45); } @media (max-width: 640px) { .cell-grid { --cell: 1.2rem; } .cell-field input { font-size: 1rem; } } } /* Console brand atoms (home and future operator pages): the landing page's square buttons and heavy tight headings at working size. */ @layer components { .home-title { color: var(--color-french-blue-700); font-size: clamp(2.25rem, 5vw, 3rem); font-weight: 850; line-height: 0.95; letter-spacing: -0.04em; } .home-lede { max-width: 62ch; color: var(--color-smart-blue-900); font-size: 1.0625rem; line-height: 1.55; } .btn-brand, .btn-brand-outline { display: inline-flex; align-items: center; justify-content: space-between; gap: 1.25rem; min-height: 3rem; padding: 0.625rem 1.25rem; border: 2px solid var(--color-french-blue-700); border-radius: 0; font-size: 1rem; font-weight: 700; letter-spacing: -0.015em; text-decoration: none; cursor: pointer; transition: background-color 0.2s ease-out, color 0.2s ease-out; } .btn-brand { background: var(--color-french-blue-700); color: var(--color-smart-blue-50); } .btn-brand:hover { background: var(--color-french-blue-800); border-color: var(--color-french-blue-800); } .btn-brand-outline { background: transparent; color: var(--color-french-blue-700); } .btn-brand-outline:hover { background: var(--color-light-gold-100); } .btn-brand:disabled, .btn-brand-outline:disabled { opacity: 0.45; cursor: not-allowed; translate: none; } .btn-brand:disabled:hover { background: var(--color-french-blue-700); border-color: var(--color-french-blue-700); } .btn-brand-outline:disabled:hover { background: transparent; } .brand-field { width: 100%; padding-inline: 0.875rem; border: 2px solid var(--color-french-blue-700); border-radius: 0; background: var(--color-smart-blue-50); color: var(--color-smart-blue-900); font-size: 1rem; } .brand-field::placeholder { color: var(--color-smart-blue-600); } .brand-field:focus-visible { outline: 3px solid var(--color-french-blue-700); outline-offset: 3px; background: var(--color-light-gold-50); } .btn-brand:active, .btn-brand-outline:active { translate: 0 1px; } .btn-brand svg { transition: translate 0.3s cubic-bezier(0.16, 1, 0.3, 1); } .btn-brand:hover svg { translate: 0.3rem 0; } .btn-brand:focus-visible, .btn-brand-outline:focus-visible { outline: 3px solid var(--color-french-blue-700); outline-offset: 3px; } @media (prefers-reduced-motion: reduce) { .btn-brand svg { transition: none; } } } /* Busy state (bug 15c948f #6): a control waiting on the server keeps its size and shows a spinner in place of its content, and ignores further clicks. htmx marks its requesting element (or a posting form) .htmx-request; busy.js marks a plain form's submitter aria-busy. The text is hidden with text-fill-color, not color, so the spinner can still draw in currentColor. */ @layer components { :is(button, a):is([aria-busy="true"], .htmx-request), form.htmx-request :is(button[type="submit"], button:not([type])) { position: relative; pointer-events: none; cursor: progress; -webkit-text-fill-color: transparent; } :is(button, a):is([aria-busy="true"], .htmx-request) > *, form.htmx-request :is(button[type="submit"], button:not([type])) > * { visibility: hidden; } :is(button, a):is([aria-busy="true"], .htmx-request)::after, form.htmx-request :is(button[type="submit"], button:not([type]))::after { content: ""; position: absolute; inset: 0; margin: auto; width: 1.125rem; height: 1.125rem; border: 2px solid currentColor; border-right-color: transparent; border-radius: 9999px; animation: busy-spin 0.7s linear infinite; } @keyframes busy-spin { to { rotate: 1turn; } } @media (prefers-reduced-motion: reduce) { :is(button, a):is([aria-busy="true"], .htmx-request)::after, form.htmx-request :is(button[type="submit"], button:not([type]))::after { animation-duration: 2.4s; } } } /* The checkbox's mixed state (a select-all with some rows ticked): a filled box with a dash, not the tick the vendored indicator draws. */ @layer components { [data-slot="checkbox"][data-indeterminate] { border-color: var(--primary); background: var(--primary); color: var(--primary-foreground); } [data-slot="checkbox-indicator"][data-indeterminate] > svg { display: none; } [data-slot="checkbox-indicator"][data-indeterminate]::before { content: ""; width: 0.5rem; height: 2px; background: currentColor; } }