diff --git a/components/grid-wallet-demo/src/app/globals.scss b/components/grid-wallet-demo/src/app/globals.scss
index a8104980..c24d8d4b 100644
--- a/components/grid-wallet-demo/src/app/globals.scss
+++ b/components/grid-wallet-demo/src/app/globals.scss
@@ -147,14 +147,24 @@ body {
[data-theme] flips, so the whole backdrop changes in lockstep (no stagger).
`--dot-grid-dot` is the resting dot; `--dot-grid-dot-peak` is the ripple crest. */
:root {
- /* Light: surface-secondary is the sunken stage gray (#F0F0EE), like
- grid-visualizer's dot panels. Dark overrides to gray-925 below — the WebGL
- dots' original backdrop; surface-secondary's #111111 reads too dark. */
- --dot-grid-bg: var(--surface-secondary);
+ /* Light: surface-primary (#F8F8F7) — the stage sits a step ABOVE the
+ chrome-gray side panels (surface-secondary), matching the raised cards.
+ Dark overrides below mirror it: gray-950 stage over #111111 chrome. */
+ --dot-grid-bg: var(--surface-primary);
--dot-grid-dot: #deded9;
--dot-grid-dot-peak: #b8b8b3;
}
+/* 3-col layout: the light stage steps down a hair so it separates from the
+ raised cards flanking it. Keyed to html's data-layout attribute (set
+ pre-paint by layout.tsx, kept live by page.tsx) so the color rides the
+ same clock as the arrangement flip. Light-only — the dark stage is
+ gray-950 in both arrangements. The JS canvas re-reads the token on resize
+ (StageGL's ResizeObserver), which every arrangement flip triggers. */
+html:not([data-theme='dark']):not([data-layout='stacked']) {
+ --dot-grid-bg: #f4f4f3;
+}
+
:root {
--p-accent: #11a967;
--p-accent-press: #0e8f57;
@@ -176,9 +186,11 @@ body {
}
[data-theme='dark'] {
- --dot-grid-bg: var(--color-gray-925);
- --dot-grid-dot: #333330;
- --dot-grid-dot-peak: #4d4d47;
+ /* gray-950 (#1A1A1A) — a step darker than the chrome-gray side panels'
+ raised cards, mirroring the light stage sitting under the panel surface. */
+ --dot-grid-bg: var(--color-gray-950);
+ --dot-grid-dot: #2d2d2a;
+ --dot-grid-dot-peak: #474741;
--p-bg: #000000;
--p-screen: #000000;
--p-surface: #141414;
diff --git a/components/grid-wallet-demo/src/app/layout.tsx b/components/grid-wallet-demo/src/app/layout.tsx
index c27f8e1b..471e0381 100644
--- a/components/grid-wallet-demo/src/app/layout.tsx
+++ b/components/grid-wallet-demo/src/app/layout.tsx
@@ -1,6 +1,7 @@
import type { Metadata } from 'next';
import { GeistSans } from 'geist/font/sans';
import { easingVarsStylesheet } from '@/lib/easing';
+import { CONFIGURE_COL_PX, LAYOUT_WIDE_PX } from '@/lib/layout';
import './globals.scss';
const TITLE = 'Grid Global Accounts — Live demo';
@@ -44,7 +45,14 @@ export default function RootLayout({ children }: { children: React.ReactNode })
- {/* Set data-embed and an initial data-theme before paint to avoid a flash. */}
+ {/* Boot attributes, set before first paint to avoid flashes — an
+ effect is too late (the SSR HTML paints long before hydration):
+ - data-embed / data-theme from the URL (embed) or stored pref
+ - data-layout (stacked ⇄ 3-col) from the viewport width
+ - --api-col-default from the embed's ?nav param (the live docs
+ sidebar width), so the wide layout's code column paints at its
+ real default — sidebar + configure column — instead of the
+ expanded-sidebar assumption and re-fitting after hydration. */}