Pixel-sampling the rendered dashboard showed the only visible green left was the
active-nav bg (--sidebar-accent #f0fdf4). Neutralize it plus the remaining
non-dashboard green/teal tints (#008c73, #dcfce7, #1c5538, etc.) so no green can
surface in any state. Zero green remains except Google's OAuth logo.
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
Remaining green was in the sidebar active-nav accent (#22c55e), success/synced
tokens (#00b460/#16a34a and palette variants), and green fills baked into
public SVG illustrations + the MUI palettes — not the tokens already fixed.
Neutralize every green (brand accent, success, illustration) to grey across
apps/web/src, apps/web/public/images, and packages/theme (palettes + vars.css
regenerated). Keep only Google's brand green in the OAuth sign-in logo.
Verified: zero green remains except google.svg.
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
Browsers auto-request /favicon.ico (was the 15406B Safe icon). Replace it +
all brand/*/favicon.ico + android-chrome PNGs with a Lux monochrome mark.
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
The rendered Safe{Wallet}/Safe-Labs mark lived in SVG assets imported as
components (SidebarTopBar chrome, welcome/NewSafe wordmark, onboarding/WC/
first-tx icons) — not gated by isOfficialHost, so an HTML grep was clean but
the page visually showed it. Swap the assets themselves:
- logo-no-text.svg -> Lux mono rounded square (chrome icon)
- logo-safe-labs.svg-> Lux Safe wordmark (welcome/header)
- logo.svg -> Lux Safe wordmark (large)
- logo-round.svg -> Lux mono circle (was #12FF80 green)
All self-adapting (black in light / white in dark). Zero Safe mark, zero green.
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
v2.2.0 left green in the sidebar-active accent, brand icons, and 4 Tailwind
notification badges because they read palette static.textBrand (#12FF80) and
hardcoded rgba(18,255,128,.1) — not the secondary token. Neutralize:
- static.ts textBrand -> #636669 (constant grey, reads on light+dark)
- regenerate vars.css from palettes
- badge bg rgba(18,255,128,.1) -> rgba(99,102,105,.15)
Zero green remains in shipped source.
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
- yarn after-install lives in apps/web -> run it workspace-scoped (root has
no such script; typechain generate-types is required by the build)
- drop arm64 (QEMU-emulated Node build, no arm64 runner); lux-k8s is amd64
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
The safe.lux.network host was serving a separate marketing landing
(lux-apps/safe, @luxfi/safe) as ghcr.io/luxfi/lux-safe:v2.0.0 — the real
@safe-global/web app was never deployed. Point the lux brand at the new Lux
Client Gateway (safe-cgw.lux.network) so chains 96369/200200/494949 and their
Safes load, and add a build-time-correct multi-arch image + CI.
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
Each per-brand manifest references brand/active/{logo.svg,favicon.ico,
android-chrome-{192,512}x{192,512}.png}. Without those files the runtime
manifest fetch 404s after select-brand. Stamps a 1x1 transparent PNG
placeholder per slot plus a text-only SVG logo so non-Safe builds resolve;
real artwork tracked in HANZO_WHITELABEL.md "manual review queue".
Also re-aligns brand/safe/manifest.json with the committed upstream
public/safe.webmanifest so build:safe leaves the working tree clean
(no spurious diff on the canonical wallet build).
Pass-1's URL codemod missed seven JSX/template-string call sites that
hardcoded https://help.safe.global directly. Route each through
${brand.helpUrl}/articles/... so non-Safe branded builds point at their
own help center (docs.lux.network/safe, docs.hanzo.ai/vault, etc).
No protocol identifiers changed; no test fixtures changed; no behavior
diff on a build:safe build.
apps/web/package.json gains build:safe / build:lux / build:hanzo
scripts. Each runs scripts/select-brand.sh <slug> (which copies
.env.<slug> -> .env.local, brand/<slug>/ -> brand/active/, and the
per-brand manifest.json over safe.webmanifest) then `yarn build`.
scripts/codemod-brand-urls.mjs is the Pass 1 driver kept in-tree so
future merges with upstream can re-run it. .gitignore covers the
brand/active output dir.
HANZO_WHITELABEL.md updated with the per-brand invocation, the
canonical pattern table, the protocol-vs-brand boundary, and how
to add a new brand (env + asset dir + one package.json script — no
source edits).
apps/web/public/brand/{safe,lux,hanzo}/manifest.json hold per-brand web
app manifests; scripts/select-brand.sh copies the chosen one over
apps/web/public/safe.webmanifest at build time. MetaTags og/twitter
image and twitter:site read brand.appUrl / brand.twitterUrl. The
default webmanifest description is now brand-neutral.
apps/mobile/app.config.ts derives the product name from
EXPO_PUBLIC_BRAND_NAME (default 'Safe{Mobile}') and threads it into
the dev variant prefix and the camera-permission rationale string,
removing the only hard-coded brand strings in mobile config.
Exposes a Brand type and a default brand object whose values match
upstream Safe strings. Per-brand builds override via NEXT_PUBLIC_BRAND_*
(web) or EXPO_PUBLIC_BRAND_* (mobile) env vars.
Single source of truth for product name, URLs, support contacts, and
asset paths. No 'Safe' / 'safe.global' literal lives in apps/ or
packages/*/src/ once the codemod passes land.
White-label plan for this fork: every hardcoded "Safe" / "safe.global"
reference in app code gets replaced with a read from a single Brand
config object sourced from env at build time. ~1,759 source files
carry one or more brand references; HANZO_WHITELABEL.md inventories
the patterns + phases the rewrite.
The same fork can then ship as Lux Safe, Hanzo Vault, partner builds,
etc. without forking the source per brand.