Files
explore/nextjs/global.css
T
zeekay 793816c7a7 Let the reader set type, density and face
The explorer had no way for a person to change how it reads. Colour mode was
the only control, and it is one bit.

@hanzo/appearance stores the preference and puts it on <html>; what the numbers
mean is bound in styles/tokens.css. Type rides the root font size, so every
Tailwind rung — all of them in rem — moves from one declaration and nothing is
restated. Density rides --spacing, the single base every p-*, m-* and gap-*
computes from. Both default to 1, so an install that never opens the panel
renders exactly what it rendered before; measured in a browser against the
production build: 16px root, p-4 at 16px, unchanged.

@hanzo/design's token sheets stay out. They declare --text-*, --radius-* and
--breakpoint-* — the names Tailwind v4 publishes — outside any layer, and v4
compiles utilities to var() references rather than baked values, so importing
them silently reanchors the app: --text-base 16px to 14px, --radius-lg 8px to
12px. Two sets under one set of names is a fork, not a migration. They become
the ramps when Tailwind leaves and there is one ramp to own.

The boot script is hashed for CSP from the same call that renders it, the way
the adbutler scripts are. A pasted literal goes stale on the next release of
the package and fails silently — policy parses, browser drops the script, page
paints at the defaults.
2026-08-28 23:45:54 -07:00

346 lines
16 KiB
CSS

@import "tailwindcss" layer(tailwind);
@import "../styles/tokens.css";
@plugin "tailwindcss-animate";
/*
* Scan the @luxfi/ui component library for Tailwind classes.
*
* @luxfi/ui ships pre-built components whose className strings use arbitrary
* Tailwind utilities that resolve design tokens — e.g. the popover / menu /
* drawer surfaces are styled with bg-[var(--color-popover-bg)],
* bg-[var(--color-drawer-bg)], shadow-[var(--shadow-popover)] and
* border-[var(--color-popover-border)]. Tailwind v4 does not scan node_modules
* by default, so without this @source those utilities are purged and every
* floating panel (Sign-in popover, Blockchain menu, chain/network selectors,
* mobile nav drawer) renders with a transparent background — the page bleeds
* through and the content is unreadable. Sourcing the package makes Tailwind
* emit the utilities so the panels get their solid token-driven backgrounds.
*/
@source "../node_modules/@luxfi/ui";
/*
* Tailwind v4 theme configuration
*
* Breakpoints match Chakra: sm=415px, lg=1000px, xl=1440px, 2xl=1920px
* Dark mode via .dark class (next-themes "class" strategy)
* Font families: Geist (body/heading), Geist Mono (mono)
*
* The block below is the TAILWIND BRIDGE: names registered so a call site can
* write `text-good` or `bg-gray-100` and get a utility, with the values coming
* from @luxfi/ui. It exists because Tailwind is here and it goes when Tailwind
* goes. The other @theme, in styles/tokens.css, is a different thing with a
* different lifetime — it binds a reader's own settings to the ramps, and it
* outlives Tailwind. Two blocks, two reasons; Tailwind merges them.
*/
@theme {
/* --- Breakpoints --- */
--breakpoint-sm: 415px;
--breakpoint-lg: 1000px;
--breakpoint-xl: 1440px;
--breakpoint-2xl: 1920px;
/* --- Font Families --- */
--font-sans: "Geist", sans-serif;
--font-heading: "Geist", sans-serif;
--font-mono: "Geist Mono", monospace;
/* --- State. The only two hues Lux keeps, plus the achromatic warn.
Registered here so a call site can say `text-good` instead of
`text-[var(--color-status-good)]`, which is the same token and
shorter than the `text-green-500` it replaced. --- */
--color-good: var(--color-status-good);
--color-bad: var(--color-status-bad);
--color-warn: var(--color-status-warn);
/* --- Colors (mapped from CSS custom properties) --- */
--color-bg-primary: var(--color-bg-primary);
--color-bg-info: var(--color-bg-info);
--color-bg-body: var(--color-bg-body);
--color-fg-info: var(--color-fg-info);
--color-text-primary: var(--color-text-primary);
--color-text-secondary: var(--color-text-secondary);
--color-text-error: var(--color-text-error);
--color-text-success: var(--color-text-success);
--color-heading: var(--color-heading);
--color-icon-primary: var(--color-icon-primary);
--color-icon-secondary: var(--color-icon-secondary);
--color-border-divider: var(--color-border-divider);
--color-border-error: var(--color-border-error);
--color-border-info: var(--color-border-info);
--color-link-primary: var(--color-link-primary);
--color-link-primary-hover: var(--color-link-primary-hover);
--color-link-secondary: var(--color-link-secondary);
--color-hover: var(--color-hover);
--color-selected-control-bg: var(--color-selected-control-bg);
--color-selected-control-text: var(--color-selected-control-text);
--color-selected-option-bg: var(--color-selected-option-bg);
--color-button-solid-bg: var(--color-button-solid-bg);
--color-button-solid-text: var(--color-button-solid-text);
--color-button-outline-fg: var(--color-button-outline-fg);
--color-button-subtle-fg: var(--color-button-subtle-fg);
--color-button-subtle-bg: var(--color-button-subtle-bg);
--color-button-dropdown-fg: var(--color-button-dropdown-fg);
--color-button-dropdown-border: var(--color-button-dropdown-border);
--color-button-header-fg: var(--color-button-header-fg);
--color-button-header-fg-selected: var(--color-button-header-fg-selected);
--color-button-header-fg-highlighted: var(--color-button-header-fg-highlighted);
--color-button-header-border: var(--color-button-header-border);
--color-button-header-bg-selected: var(--color-button-header-bg-selected);
--color-button-header-bg-highlighted: var(--color-button-header-bg-highlighted);
--color-button-pagination-fg: var(--color-button-pagination-fg);
--color-button-pagination-border: var(--color-button-pagination-border);
--color-button-hero-bg: var(--color-button-hero-bg);
--color-button-hero-fg: var(--color-button-hero-fg);
--color-button-hero-bg-hover: var(--color-button-hero-bg-hover);
--color-button-hero-fg-hover: var(--color-button-hero-fg-hover);
--color-button-hero-bg-selected: var(--color-button-hero-bg-selected);
--color-button-hero-fg-selected: var(--color-button-hero-fg-selected);
--color-button-segmented-fg: var(--color-button-segmented-fg);
--color-button-icon-bg: var(--color-button-icon-bg);
--color-button-icon-background-bg: var(--color-button-icon-background-bg);
--color-nav-bg-selected: var(--color-nav-bg-selected);
--color-nav-text-selected: var(--color-nav-text-selected);
--color-input-fg: var(--color-input-fg);
--color-input-bg: var(--color-input-bg);
--color-input-border: var(--color-input-border);
--color-input-border-hover: var(--color-input-border-hover);
--color-input-placeholder: var(--color-input-placeholder);
--color-dialog-bg: var(--color-dialog-bg);
--color-dialog-fg: var(--color-dialog-fg);
--color-popover-bg: var(--color-popover-bg);
--color-drawer-bg: var(--color-drawer-bg);
--color-tooltip-bg: var(--color-tooltip-bg);
--color-tooltip-fg: var(--color-tooltip-fg);
--color-table-header-bg: var(--color-table-header-bg);
--color-table-header-fg: var(--color-table-header-fg);
--color-alert-fg: var(--color-alert-fg);
--color-alert-bg-info: var(--color-alert-bg-info);
--color-alert-bg-warning: var(--color-alert-bg-warning);
--color-alert-bg-success: var(--color-alert-bg-success);
--color-alert-bg-error: var(--color-alert-bg-error);
--color-skeleton-start: var(--color-skeleton-start);
--color-skeleton-end: var(--color-skeleton-end);
--color-progress-track: var(--color-progress-track);
--color-stats-bg: var(--color-stats-bg);
--color-topbar-bg: var(--color-topbar-bg);
--color-graph-line: var(--color-graph-line);
--color-graph-gradient-start: var(--color-graph-gradient-start);
--color-graph-gradient-stop: var(--color-graph-gradient-stop);
--color-scrollbar-thumb: var(--color-scrollbar-thumb);
--color-selection-bg: var(--color-selection-bg);
/* --- Tabs colors --- */
--color-tabs-solid-fg: var(--color-tabs-solid-fg);
--color-tabs-secondary-fg: var(--color-tabs-secondary-fg);
--color-tabs-secondary-border: var(--color-tabs-secondary-border);
/* --- Badge colors --- */
--color-badge-gray-bg: var(--color-badge-gray-bg);
--color-badge-gray-fg: var(--color-badge-gray-fg);
--color-badge-green-bg: var(--color-badge-green-bg);
--color-badge-green-fg: var(--color-badge-green-fg);
--color-badge-red-bg: var(--color-badge-red-bg);
--color-badge-red-fg: var(--color-badge-red-fg);
--color-badge-purple-bg: var(--color-badge-purple-bg);
--color-badge-purple-fg: var(--color-badge-purple-fg);
--color-badge-orange-bg: var(--color-badge-orange-bg);
--color-badge-orange-fg: var(--color-badge-orange-fg);
--color-badge-blue-bg: var(--color-badge-blue-bg);
--color-badge-blue-fg: var(--color-badge-blue-fg);
--color-badge-yellow-bg: var(--color-badge-yellow-bg);
--color-badge-yellow-fg: var(--color-badge-yellow-fg);
--color-badge-teal-bg: var(--color-badge-teal-bg);
--color-badge-teal-fg: var(--color-badge-teal-fg);
--color-badge-cyan-bg: var(--color-badge-cyan-bg);
--color-badge-cyan-fg: var(--color-badge-cyan-fg);
--color-badge-pink-bg: var(--color-badge-pink-bg);
--color-badge-pink-fg: var(--color-badge-pink-fg);
--color-badge-purple-alt-bg: var(--color-badge-purple-alt-bg);
--color-badge-purple-alt-fg: var(--color-badge-purple-alt-fg);
--color-badge-blue-alt-bg: var(--color-badge-blue-alt-bg);
--color-badge-blue-alt-fg: var(--color-badge-blue-alt-fg);
--color-badge-bright-gray-bg: var(--color-badge-bright-gray-bg);
--color-badge-bright-gray-fg: var(--color-badge-bright-gray-fg);
--color-badge-bright-green-bg: var(--color-badge-bright-green-bg);
--color-badge-bright-green-fg: var(--color-badge-bright-green-fg);
--color-badge-bright-red-bg: var(--color-badge-bright-red-bg);
--color-badge-bright-red-fg: var(--color-badge-bright-red-fg);
--color-badge-bright-blue-bg: var(--color-badge-bright-blue-bg);
--color-badge-bright-blue-fg: var(--color-badge-bright-blue-fg);
--color-badge-bright-yellow-bg: var(--color-badge-bright-yellow-bg);
--color-badge-bright-yellow-fg: var(--color-badge-bright-yellow-fg);
--color-badge-bright-teal-bg: var(--color-badge-bright-teal-bg);
--color-badge-bright-teal-fg: var(--color-badge-bright-teal-fg);
--color-badge-bright-cyan-bg: var(--color-badge-bright-cyan-bg);
--color-badge-bright-cyan-fg: var(--color-badge-bright-cyan-fg);
--color-badge-bright-orange-bg: var(--color-badge-bright-orange-bg);
--color-badge-bright-orange-fg: var(--color-badge-bright-orange-fg);
--color-badge-bright-purple-bg: var(--color-badge-bright-purple-bg);
--color-badge-bright-purple-fg: var(--color-badge-bright-purple-fg);
--color-badge-bright-pink-bg: var(--color-badge-bright-pink-bg);
--color-badge-bright-pink-fg: var(--color-badge-bright-pink-fg);
/* --- Palette rungs ---
Self-references, like the badge block above: they exist so Tailwind emits
the `bg-gray-100` / `text-red-500` utilities, while the VALUES come from
@luxfi/ui/tokens.css (imported outside any @layer at the top, so it wins).
This block used to hold literals, which is how the explorer kept its own
browns after the token set went monochrome:
--color-orange-50 #FFFAF0 --color-orange-100 #FEEBCB
--color-orange-500 #DD6B20 --color-yellow-400 #ECC94B */
--color-gray-50: var(--color-gray-50);
--color-gray-100: var(--color-gray-100);
--color-gray-200: var(--color-gray-200);
--color-gray-300: var(--color-gray-300);
--color-gray-400: var(--color-gray-400);
--color-gray-500: var(--color-gray-500);
--color-gray-600: var(--color-gray-600);
--color-gray-700: var(--color-gray-700);
--color-gray-800: var(--color-gray-800);
--color-gray-900: var(--color-gray-900);
--color-green-50: var(--color-green-50);
--color-green-100: var(--color-green-100);
--color-green-200: var(--color-green-200);
--color-green-500: var(--color-green-500);
--color-green-800: var(--color-green-800);
--color-red-50: var(--color-red-50);
--color-red-100: var(--color-red-100);
--color-red-200: var(--color-red-200);
--color-red-500: var(--color-red-500);
--color-red-600: var(--color-red-600);
--color-red-800: var(--color-red-800);
--color-orange-50: var(--color-orange-50);
--color-orange-100: var(--color-orange-100);
--color-orange-500: var(--color-orange-500);
--color-yellow-400: var(--color-yellow-400);
--color-white: var(--color-white);
--color-black: var(--color-black);
/* --- Shadows --- */
--shadow-action-bar: var(--shadow-action-bar);
--shadow-popover: var(--shadow-popover);
--shadow-drawer: var(--shadow-drawer);
}
/*
* Motion lives in @luxfi/ui/tokens.css (imported above via styles/tokens.css):
* durations, curves, enter/exit, hover/press, the skeleton, and one global
* prefers-reduced-motion rule. Add a move to the design system, never here.
*
* What this replaced: a local `skeleton-shimmer` that animated
* background-position on a 200%-wide gradient. The explorer mounts ~1460
* skeletons, so that was ~1460 full-box repaints per frame on the main thread.
*/
/*
* Dark mode: use .dark class (next-themes)
* Tailwind v4 default is prefers-color-scheme; override to class-based.
*/
@custom-variant dark (&:is(.dark *));
/*
* Scope Tailwind to a layer so it does not override Chakra styles.
* Chakra styles have no layer, so they win by default cascade rules.
* New Tailwind components explicitly opt in via utility classes.
*/
@font-face {
font-family: 'InterFallback';
src: url('/static/fonts/Inter-fallback.woff2') format('woff2');
unicode-range: U+2192; /* Only the right arrow */
font-display: swap;
}
/*
* Global font and body styles.
* Geist is loaded via Google Fonts in _document.tsx.
* Apply it universally so Chakra components inherit it too.
*/
html, body {
font-family: 'Geist', sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* ── light mode: Tamagui text was painting white on white ──────────────────
The gui provider pins `t_dark` on <body> CLIENT-SIDE in BOTH schemes (the
server sends a bare <body>), and its theme block reads:
.t_dark { --color: var(--c-color-background) } -> #ffffff
.t_light { --color: var(--c-color-text) } -> #000000
:root { --c-color-background:#ffffff; --c-color-text:#000000 } invariant
so every Tamagui text component (is_H1 / is_H3 / is_Text) resolved --color to
#ffffff unconditionally — right by accident on dark, invisible on light.
Measured at 1.00:1 across all four widths on /address/*, /validators and the
landing page: "Address details", the ADDRESS ITSELF, "Validators", and six
section headings. A user clicking a Safe link from lux.cloud landed on a page
that never showed which address they were looking at.
The page BACKGROUND is not affected — that follows the Tailwind --lux-* layer,
which already tracks html.light/html.dark correctly. Only the text colour is
wrong, so only --color is corrected here. Both selectors are covered because
the class is applied by script: html.light is the explicit signal, and the
media query catches the pre-hydration frame.
Remove this the day the provider stops hard-pinning t_dark. */
/* NOT `body.t_dark` — measured 2026-08-06: the provider mounts a SECOND
`<span class="t_dark">` INSIDE <body>, and `:root .t_dark` matches both. A
body-scoped rule sets --color on body correctly (verified #000000 there) and
the nested span immediately re-sets it to #ffffff, which every heading then
inherits. Scoping to `.t_dark` reaches every Theme wrapper; (0,2,1) still
beats `:root .t_dark` (0,2,0). */
/* ⚠️ THIS RULE DOES NOT REACH THE BUNDLE. Do not trust it.
Three forms have now been shipped and none appear in the served CSS:
v1.1.20 html.light body.t_dark
v1.1.21 html.light .t_dark
v1.1.22 html[class~="light"] .t_dark
In every build `.t_dark` occurs exactly ONCE in the output — the media-query
rule below — while the file's OTHER top-level rule (html,body{font-family:
Geist}) survives intact, so top-level rules are not dropped wholesale.
Running this file through the real postcss + @tailwindcss/postcss pipeline
locally KEEPS both rules, so Tailwind is not the cause; something later in
the Next build removes it. Root cause not yet found.
What it is FOR, once it works: OS-dark + stored-theme-light. There <html>
gets class="light" so the background turns white, but prefers-color-scheme
is false, so the media rule below is inert and --color stays #ffffff — the
original white-on-white, measured 1.00:1 with 11,232/11,232 pure-white
pixels in the h1 band. Injecting this rule into that state live fixes it
(1.00 -> 21.00, and forcing html.dark still gives 17.93), which is the only
sense in which it is "verified" — by injection, NOT by the shipped bundle.
Not currently user-reachable: there is no theme toggle in the signed-out UI,
so the site follows the OS. But localStorage.theme IS honoured, so a
returning user carrying a stale value already lands here, and it goes live
the moment a toggle ships. */
html[class~="light"] .t_dark { --color: var(--c-color-text); }
@media (prefers-color-scheme: light) {
html:not(.dark) .t_dark { --color: var(--c-color-text); }
}