BluAuth
Docs
Sign in
User FAQ
  • Reset my password
  • I can't sign in
  • Didn't get reset email
  • Account linking
  • Session expiry
  • Two-factor auth
Admin Guides
Theme Studio
  • Overview
  • Layouts
  • Styling tokens
  • Concept copy
  • Assets & backgrounds
  • Advanced CSS
Admin Shell
  • Users
  • Providers
  • Clients
  • Invitations
Integrations
  • OIDC flow
  • Legacy OAuth flow
  • Provider token brokering
  • Email triggers
  • Webhook events
  • Session contract
Reference
  • API
  • Error codes
  • Event shapes
  • Design tokens
Runbooks
  • Deployment
  • Local operations

Design Tokens

This page is the authoritative visual contract for BluAuth. It governs the hosted login, the admin shell, provider presentation (logo, label, button variant), and anything rendered inside the BluAuth chrome. It used to live as DESIGN.md in the repo root — it now lives here so it's linkable, versioned, and addressable by integrator tooling.

Every token on this page is tenant-configurable via the Theme Studio at /admin/themes/[id]. Defaults are defined in shared/utils/hosted-login-defaults.ts and resolved by server/utils/hosted-login/theme.ts.

1. Creative North Star: The Precision Curator

The BluAuth visual system is built on the principle of The Precision Curator. It moves beyond the common "SaaS-standard" look by prioritizing editorial clarity, high-contrast intentionality, and a rhythmic use of negative space.

Sophistication comes from tonal layering and asymmetric balance, not from grids and borders. Treat the UI as an architectural portfolio: expansive dark space, sharp emerald accents that signal life and action, and a hierarchy that feels authoritative yet breathable. Typography is a structural element, not just a vehicle for information.

2. Color System: Tonal Architecture

The palette is rooted in a deep obsidian foundation (#09090B) balanced by a crystalline primary emerald (#006B2C).

The "No-Line" Rule

Designers are strictly prohibited from using 1px solid borders to section off major layout areas. Boundaries must be defined through Background Color Shifts.

Surface Hierarchy & Nesting

Treat the UI as physical layers of fine paper. Importance is communicated through the "stacking" of surface tokens:

  • Surface Lowest (#0C0F0C) — reserved for the most important active cards or floating modals.
  • Surface (#111411) — the base canvas of the application.
  • Surface Container High (#202320) — inactive or secondary background elements.

Glass & Gradient

  • Glassmorphism — for floating menus or navigation bars, use surface colors at 80% opacity with a 20px backdrop-blur.
  • Signature Textures — main CTAs or Hero sections should employ a subtle linear gradient from primary (#006B2C) to primary_container (#00873A) at a 135° angle.

3. Typography: Editorial Authority

Base family is Inter (neo-grotesque). The Theme Studio exposes five fontFamilyPreset values; the resolver is resolveHostedLoginFontFamily(preset) in app/utils/hosted-login.ts.

PresetStack
systemsystem-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif
interInter, "Segoe UI", system-ui, sans-serif
robotoRoboto, "Helvetica Neue", Arial, sans-serif
humanist"Avenir Next", "Segoe UI", system-ui, sans-serif
editorial"Iowan Old Style", "Palatino Linotype", "Book Antiqua", Georgia, serif
  • Display (lg/md/sm) — high-impact hero statements. Tight tracking (-0.02em).
  • Headline & Title — the structural backbone. headline-lg (2rem) anchors page sections.
  • Body (lg/md/sm) — body-md (0.875rem) is the workhorse.
  • Labels — small, all-caps at label-sm (0.6875rem) with +0.05em tracking for metadata.

4. Elevation & Depth: Tonal Layering

Drop shadows are largely replaced by Ambient Elevation.

  • Layering Principle — instead of adding a shadow to a card, place surface-container-lowest (#0C0F0C) on surface-container-low (#111411). The 2% luminance delta creates a soft lift.
  • Ambient Shadows — if a floating state is required, use a tinted "shadow-wash": blur: 40px; opacity: 6%, using on-surface (#E2E3DF) rather than pure black.
  • Ghost Border Fallback — outline-variant (#404941) at 15% opacity. Never use a 100% opaque border for decorative containment.

5. Layout Presets

Five layout presets are exposed via clientThemes.layoutPreset. All presets render through the <HostedLoginSurface> component and its layout children in app/components/hosted-login/layouts/.

Enumerated in HOSTED_LOGIN_LAYOUT_ITEMS:

layoutPresetComponentHero treatmentBest for
centered-cardLayoutCenteredCard.vueTicket stubs — vertical cards below the auth panel with a colored rail and arrow hover affordanceMinimal brands; product-led onboarding
split-heroLayoutSplitHero.vueHero cards — side panel with two linkable cards stacked or griddedEnterprise tenants with dual CTAs (e.g. "Request access" + "View docs")
minimalLayoutMinimal.vueEditorial list — a ·-separated inline list with ↗ arrowsText-first brands; editorial/publishing feel
cinematic-splitLayoutCinematicSplit.vueCinematic plaques — full-bleed imagery with overlaid metadata plaquesMedia companies; image-driven brands (ticket stubs, posters)
auroraLayoutAurora.vueAurora chips — ambient animated gradient with small eyebrow chipsHero-forward, animation-heavy experiences (Ziv direction)

Each preset consumes the shared theme object and overrides only its own structural CSS — all five honor the same color, surface, field, and button tokens below.

5.1 Centered Card — Ticket Stubs

Stacked layout with the auth card centered and optional hero "stubs" below. Each stub has a colored rail (--auth-primary), an eyebrow, a title, an optional description, and an arrow affordance when a URL is configured.

BEM hooks:

  • .hosted-login__shell--stacked
  • .hosted-login__hero-stubs, .hosted-login__hero-stub, .hosted-login__hero-stub--link
  • .hosted-login__hero-stub-rail, .hosted-login__hero-stub-body, .hosted-login__hero-stub-eyebrow, .hosted-login__hero-stub-title, .hosted-login__hero-stub-desc, .hosted-login__hero-stub-arrow

Theme fields consumed: heroEyebrowText, heroCard1*, heroCard2*.

5.2 Split Hero — Hero Cards

Two-column layout: hero panel on the left with logo, title, subtitle, support text, and 1–2 linkable cards; auth panel on the right.

BEM hooks:

  • .hosted-login__shell--split
  • .hosted-login__hero, .hosted-login__panel
  • .hosted-login__hero-card, .hosted-login__hero-mark, .hosted-login__logo, .hosted-login__logo-fallback
  • .hosted-login__title--hero, .hosted-login__subtitle--hero, .hosted-login__support
  • .hosted-login__hero-list, .hosted-login__hero-link, .hosted-login__hero-link--active
  • .hosted-login__hero-link-eyebrow, .hosted-login__hero-link-title, .hosted-login__hero-link-desc, .hosted-login__hero-link-arrow

Collapses to stacked on viewports < 960px.

5.3 Minimal — Editorial List

Stacked layout with an inline, footer-style hero list of title · description ↗ items. No cards, no rails — pure editorial typography.

BEM hooks:

  • .hosted-login__hero-lines, .hosted-login__hero-line-item
  • .hosted-login__hero-line, .hosted-login__hero-line--link
  • .hosted-login__hero-line-title, .hosted-login__hero-line-sep, .hosted-login__hero-line-desc, .hosted-login__hero-line-arrow

The --link modifier adds an animated underline via ::after pseudo-element on hover.

5.4 Cinematic Split — Cinematic Plaques

Full-bleed hero imagery (when backgroundImageUrl is set) with overlaid metadata plaques. Configurable via:

FieldValuesEffect
cinematicPanelModecontained, edge-to-edgeAuth panel inset vs. flush
cinematicHeightModefull, containedFill viewport vs. respect document flow

BEM hooks:

  • .hosted-login__shell (plus cinematic overrides on the Surface root)
  • Background is layered: linear-gradient(180deg, rgb(0 0 0 / 0.3), rgb(0 0 0 / 0.65)) over the user's backgroundImageUrl.

Hero plaques render via the same hero-card hooks as Split Hero but sit atop the imagery.

5.5 Aurora — Aurora Chips

Ambient-motion layout with an animated radial-gradient background driven by --auth-primary and --auth-background. Intensity is configurable:

auroraIntensityBehavior
subtleStatic gradient, 20% primary color-mix
atmosphericSlow 20s keyframe loop, 35% primary color-mix
reactive10s loop with pointer-follow displacement

Hero content renders as "chips" — small eyebrow-style capsules rather than cards. Best paired with buttonStylePreset: solid and surfaceStylePreset: glass.


6. Surface Styles

surfaceStylePreset controls how the auth card sits on the background. Enumerated in HOSTED_LOGIN_SURFACE_STYLE_ITEMS:

PresetBEM hookVisual
elevated.hosted-login__card--elevatedLinear gradient from color-mix(--auth-surface 95%, black) to color-mix(--auth-surface 86%, black)
solid.hosted-login__card--solidFlat color-mix(--auth-surface 92%, black)
glass.hosted-login__card--glasscolor-mix(--auth-surface 55%, transparent) + backdrop-filter: blur(20px)

Surface fill resolver: resolveHostedLoginSurfaceFill(theme, 'var(--auth-background)'). When useSurfaceColor = false, surface is computed as color-mix(in srgb, var(--auth-background) 80%, black 20%).

7. Field Styles

fieldStylePreset — how input fields are styled inside the auth card. Enumerated in HOSTED_LOGIN_FIELD_STYLE_ITEMS:

PresetBackgroundBorderFocus
defaultcolor-mix(--auth-background 72%, white 4%)color-mix(--auth-primary 20%, --ui-border)--auth-primary opaque
quiettransparentsubtle --ui-border--auth-primary 45% fade-in
outlinetransparent1px color-mix(--auth-primary 30%, white)2px --auth-primary
high-contrastcolor-mix(black 72%, --auth-background)color-mix(--auth-primary 30%, white)2px --auth-primary + shadow wash

Input root: .hosted-login__input.

8. Button Styles

buttonStylePreset — primary action button variant. Enumerated in HOSTED_LOGIN_BUTTON_STYLE_ITEMS:

PresetSurfaceBorderHover
solid--auth-primarycolor-mix(--auth-primary 70%, white)10% lift via box-shadow wash
softcolor-mix(--auth-primary 18%, transparent)noneDeepen to 28%
outlinetransparentcolor-mix(--auth-primary 45%, --ui-border)Fill with color-mix(--auth-primary 14%, transparent)

Primary action root: .hosted-login__primary-action.

8.1 Provider Buttons

Provider buttons have their own variants driven by presentationMode (auto, neutral, brand) and provider type:

  • .hosted-login__provider-button — base
  • .hosted-login__provider-button--neutral — monochrome
  • .hosted-login__provider-button--soft — tinted fill
  • .hosted-login__provider-button--outline — outline only
  • .hosted-login__provider-button--google — brand colors for Google
  • .hosted-login__provider-button--github — brand colors for GitHub

Provider icon resolution: resolveHostedLoginProviderIconName(provider) returns i-lucide-chrome (google), i-lucide-github (github), i-lucide-key-round (oidc), i-lucide-file-lock (saml), or i-lucide-shield (fallback).

9. Density Scale

densityPreset — vertical rhythm. Enumerated in HOSTED_LOGIN_DENSITY_ITEMS:

PresetCard paddingField heightLine-height
comfortable2rem 2.25rem2.75rem1.5
compact1.25rem 1.5rem2.25rem1.35

The compact variant applies .hosted-login__card--compact which tightens all internal spacing proportionally.


10. Color-Mix Formulas

All runtime color composition uses color-mix(in srgb, ...). Centralizing these formulas means overriding --auth-primary (or any other CSS custom property) automatically cascades through every derived surface.

RoleFormula
Card elevated topcolor-mix(in srgb, var(--auth-surface) 95%, black)
Card elevated botcolor-mix(in srgb, var(--auth-surface) 86%, black)
Card solidcolor-mix(in srgb, var(--auth-surface) 92%, black)
Card glasscolor-mix(in srgb, var(--auth-surface) 55%, transparent)
Field default bgcolor-mix(in srgb, var(--auth-background) 72%, white 4%)
Field high-contrastcolor-mix(in srgb, black 72%, var(--auth-background))
Primary highlightcolor-mix(in srgb, var(--auth-primary) 20%, transparent)
Primary gradient (start)color-mix(in srgb, var(--auth-primary) 82%, white)
Primary gradient (end)color-mix(in srgb, var(--auth-primary) 45%, black)
Secondary textcolor-mix(in srgb, white 55%, var(--auth-primary))
Tertiary textcolor-mix(in srgb, white 30%, var(--auth-primary))
Hairlinecolor-mix(in srgb, var(--auth-primary) 14%, var(--ui-border))

When backgroundImageMode = 'full-bleed', the shell adds a darkening gradient linear-gradient(180deg, rgb(8 16 32 / 0.22), rgb(8 16 32 / 0.62)) on top of the background image so foreground text retains WCAG AA contrast.

11. CSS Custom Properties

Exposed on the <HostedLoginSurface> root. Overridable via Advanced CSS.

VariableSourceDefault / Example
--auth-primarytheme.primaryColor#3B82F6
--auth-backgroundtheme.backgroundColor#0F172A
--auth-surfaceresolveHostedLoginSurfaceFill(...)#111827 or mix
--auth-background-imagetheme.backgroundImageUrlurl("https://...") or none
--auth-font-familyresolveHostedLoginFontFamily(...)resolved from fontFamilyPreset
--auth-on-primaryAdvanced CSS override (optional)falls back to white
--ui-borderNuxt UIrgba(255,255,255,0.1)

Color inputs are normalized via normalizeHexColorInput(value) which accepts #FFF, #FFFFFF, FFFFFF, or FFFFFFFF (with alpha). Invalid inputs are returned as empty strings and fall back to defaults.

--auth-on-primary is the contrast color painted on top of a surface derived from --auth-primary (e.g., the brand-mark icon inside the logo-fallback gradient). It defaults to white, which is correct for the default obsidian-emerald palette; tenants that pick a light primary color can override it via Advanced CSS (.hosted-login { --auth-on-primary: oklch(15% 0 0); }) to maintain contrast.

Admin shell widths

Not exposed on <HostedLoginSurface> — these govern the BluAuth admin console, defined at :root in app/assets/styles/main.css:

VariableUsed byDefault
--bluauth-admin-content-max.console-stack (default admin content column)1500px
--bluauth-admin-content-narrow.console-stack--narrow (form-heavy surfaces)64rem

The .console-stack class applies max-width: var(--bluauth-admin-content-max); margin-inline: auto; width: 100%; so every admin page converges on one of two widths. Opt into narrow for form-heavy detail pages (settings/index, users/[id]); default wide for list/dashboard surfaces. Never re-open this decision with a page-level max-w-* utility — the design-system/no-raw-max-width-on-console-stack validator rule will flag it.

12. Advanced CSS — BEM Class Hooks

theme.customCss is injected into the page head inside a scoped <style> tag. Use the documented BEM classes below to override. All hooks are verified by test/unit/app/experience-templates.test.ts.

Shell

  • .hosted-login — root wrapper
  • .hosted-login--with-full-bleed-background — adds bleed-mode overlay
  • .hosted-login--embedded — embedded mode (no footer)
  • .hosted-login--preview-mobile — preview mode, mobile breakpoint
  • .hosted-login__shell — layout shell
  • .hosted-login__shell--stacked — centered-card / minimal layouts
  • .hosted-login__shell--split — split-hero / cinematic layouts

Card

  • .hosted-login__card
  • .hosted-login__card--elevated | --solid | --glass | --compact

Title & body

  • .hosted-login__brand-mark, .hosted-login__eyebrow, .hosted-login__title, .hosted-login__subtitle, .hosted-login__support
  • .hosted-login__title--hero, .hosted-login__subtitle--hero (split-hero modifiers)

Hero treatments

  • Ticket stubs: .hosted-login__hero-stubs, .hosted-login__hero-stub(--link), .hosted-login__hero-stub-{rail,body,eyebrow,title,desc,arrow}
  • Hero cards: .hosted-login__hero-list, .hosted-login__hero-link(--active), .hosted-login__hero-link-{eyebrow,title,desc,arrow}
  • Editorial list: .hosted-login__hero-lines, .hosted-login__hero-line(--link), .hosted-login__hero-line-{title,sep,desc,arrow}

Fields & buttons

  • .hosted-login__input — input root for all field-style presets
  • .hosted-login__primary-action — primary CTA
  • .hosted-login__divider — "or sign in with" divider rail
  • .hosted-login__provider-button + --neutral|--soft|--outline|--google|--github

Footer

  • .hosted-login__footer — layout-owned footer
  • .hosted-login__footer-slot — Surface-level slot wrapper

Example override:

.hosted-login__card {
    box-shadow: none;
}
.hosted-login__primary-action {
    border-radius: 9999px;
}
.hosted-login__hero-link--active:hover {
    transform: translateY(-2px);
}

13. Asset Constraints

Hosted assets are uploaded through POST /api/admin/assets/upload-url and stored in S3 with Cache-Control: public, max-age=31536000, immutable.

KindMax sizeAccepted types
theme_logo512 KBimage/png, image/jpeg, image/svg+xml, image/webp
provider_icon512 KBsame as above
theme_background5 MBsame as above

Limits are defined in app/utils/hosted-login.ts as HOSTED_LOGIN_MAX_ASSET_BYTES and HOSTED_LOGIN_MAX_BACKGROUND_BYTES.

backgroundImageMode values: framed (default — image fills the hero panel only) or full-bleed (image covers the entire viewport; shell layers a gradient for contrast).


14. Do's and Don'ts

Do

  • Use asymmetric margins (wider left than right) to create an editorial, "magazine" feel.
  • Use primary_fixed (#7FFC97) as a subtle background highlight for success states or active badges.
  • Embrace white space. If a layout feels crowded, increase padding to the next step rather than adding lines.
  • Prefer color-mix over hard-coded hex derivations so overriding --auth-primary cascades properly.
  • Verify slot contracts against .external-docs/nuxt-ui/components/ before using Nuxt UI components.

Don't

  • Don't use 1px solid black or high-contrast borders.
  • Don't use standard "Material" blue or any saturated blue that reads as generic SaaS. Stay in the tenant's primary spectrum.
  • Don't use pure black #000000 for text. Use on-surface (#E2E3DF) or a color-mix.
  • Don't hand-roll HTML controls. Always use Nuxt UI equivalents (UButton, UInput, USelect, UForm, etc.) so global theming propagates.
  • Don't invent new BEM hooks — extend the documented ones via modifiers if needed.

15. Token Reference Summary

Token RoleValueUsage
Surface Base#111411Main app background
Surface Lowest#0C0F0CTop-tier cards and modals
Primary Accent#006B2CCall to action, primary brand touchpoint
Primary Container#00873AHover states, secondary brand depth
Primary Fixed#7FFC97Active badges, success highlights
On Surface#E2E3DFDefault text
Outline Variant#404941Ghost borders (at 15% opacity)
Corner Radius0.375remDefault for buttons and inputs

16. Source-of-truth Files

PurposeFile
Canonical defaultsshared/utils/hosted-login-defaults.ts
Runtime theme resolverserver/utils/hosted-login/theme.ts
Preset enumerationsapp/utils/hosted-login.ts
Theme Studio draft + payloadapp/utils/hosted-login-theme-studio.ts
Layout componentsapp/components/hosted-login/layouts/*.vue
Auth card surfaceapp/components/hosted-login/AuthFormCard.vue
Provider listapp/components/hosted-login/ProviderList.vue
Footerapp/components/hosted-login/Footer.vue
Theme schema (Drizzle)drizzle/schemas/index.ts → clientThemes table
Theme admin APIserver/api/admin/themes/**
Theme test guaranteestest/unit/app/experience-templates.test.ts

All changes to these files are considered public API. Breaking changes require a versioned release and a migration path documented in the release notes.

On this page

  • 1. Creative North Star: The Precision Curator
  • 2. Color System: Tonal Architecture
  • The "No-Line" Rule
  • Surface Hierarchy & Nesting
  • Glass & Gradient
  • 3. Typography: Editorial Authority
  • 4. Elevation & Depth: Tonal Layering
  • 5. Layout Presets
  • 5.1 Centered Card — Ticket Stubs
  • 5.2 Split Hero — Hero Cards
  • 5.3 Minimal — Editorial List
  • 5.4 Cinematic Split — Cinematic Plaques
  • 5.5 Aurora — Aurora Chips
  • 6. Surface Styles
  • 7. Field Styles
  • 8. Button Styles
  • 8.1 Provider Buttons
  • 9. Density Scale
  • 10. Color-Mix Formulas
  • 11. CSS Custom Properties
  • Admin shell widths
  • 12. Advanced CSS — BEM Class Hooks
  • Shell
  • Card
  • Title & body
  • Hero treatments
  • Fields & buttons
  • Footer
  • 13. Asset Constraints
  • 14. Do's and Don'ts
  • Do
  • Don't
  • 15. Token Reference Summary
  • 16. Source-of-truth Files
DocsPrivacyTerms
© 2026 Blu Digital Group