fix(familiaros-website): align spinner, metal chrome, and primary button palette
Some checks are pending
Deploy FamiliarOS Website / deploy (push) Waiting to run
Some checks are pending
Deploy FamiliarOS Website / deploy (push) Waiting to run
This commit is contained in:
parent
b3d915c00e
commit
80b968465f
5 changed files with 300 additions and 183 deletions
|
|
@ -6,20 +6,57 @@
|
|||
- Header layout on all public pages: emblem left, wordmark centered in header track, nav/actions right.
|
||||
- Header shell height: `h-[10rem]` / `md:h-[10.5rem]` / `lg:h-[11rem]`.
|
||||
|
||||
- Color contract (from `/website/src/styles/global.css`)
|
||||
- Core system blue/cyan:
|
||||
- `--fos-cyan: #00E6FF`
|
||||
- `--fos-ion-blue: #3A86FF`
|
||||
- `--fos-deep-blue: #0A66FF`
|
||||
- Action / activation amber:
|
||||
- `--fos-amber: #FF9A00`
|
||||
- `--fos-gold: #FFC43D`
|
||||
- `--fos-ember: #C96A00`
|
||||
- Metal hierarchy:
|
||||
- `--fos-chrome: #E6E8EC`
|
||||
- `--fos-steel: #A6ADB8`
|
||||
- `--fos-gunmetal: #3A3F46`
|
||||
- `--fos-slate: #121821`
|
||||
- `--fos-deep-space: #0B0F14`
|
||||
- `--fos-black: #05070A`
|
||||
- Silver surface language:
|
||||
- `--brand-silver: #E6E8EC`
|
||||
- `--brand-silver-soft: #F5F6F7`
|
||||
- `--brand-silver-ink: #303949`
|
||||
|
||||
- Spinner system (suspended load)
|
||||
- Use the suspense frame in `GeneralPageLoader`.
|
||||
- Default state uses `NamedAgentSpinner name="cascade"` with `size={32}` and `loading-spinner` class.
|
||||
- Default color: `--fos-cyan` (blue/cyan).
|
||||
- Final transition pulse: append `is-completing` class and use `--fos-amber` for one short flash.
|
||||
- Keep no top progress bar; spinner sits central in one framed shell.
|
||||
|
||||
- Silver accent system for public marketing surfaces
|
||||
- Use the silver tokens for shared effects and surfaces:
|
||||
- `--brand-silver`
|
||||
- `--brand-silver-soft`
|
||||
- `--brand-silver-ink`
|
||||
- Applied across all `MarketingShell`-based pages (`About`, `Docs`, `Support`, `Help`, `Login`, `Register`, `Pricing`, `Changelog`, `Affiliate*`, and legal marketing wrappers).
|
||||
- Apply silver treatment to `public-card`, `public-card-raised`, `pricing-glow-border`, and MetalFX frames.
|
||||
- Use the silver tokens for shared effects and surfaces.
|
||||
- Apply across `public-card`, `public-card-raised`, `pricing-glow-border`, MetalFX frames, and nav/header pills.
|
||||
- Pricing controls/faces use silver (`billing tabs`, `toggle`, `plan badge`, `Most Popular` ribbon, `feature check`/icons, FAQ icons, CTA sparkles).
|
||||
- Subscription frame background glows and borders must remain silver.
|
||||
- Subscription frame background glows and borders remain silver.
|
||||
|
||||
- Typography
|
||||
- Technical/modern stack remains in global tokens:
|
||||
- Technical stack remains:
|
||||
- `--font-ui: Sora`
|
||||
- `--font-display: Orbitron` (with Sora fallback)
|
||||
- `--font-display: Orbitron`
|
||||
|
||||
- Recommended font direction: technical/modern sans stack (Sora + Orbitron), with `Space Grotesk` as an alternate UI edge option.
|
||||
|
||||
- Light/dark mode
|
||||
- Keep `data-color-mode`/`html.light` style overrides for public cards/surfaces aligned with the silver frame language.
|
||||
- Keep `data-color-mode`/`html.light` style overrides for public cards/surfaces aligned with silver frame language.
|
||||
- Keep header/nav/button frames and branding transparent where applicable.
|
||||
|
||||
- Background video decision lane
|
||||
- Preferred default for the homepage/marketing background: `matrix-digital-moewalls-com.mp4`.
|
||||
- If no full swap is needed, keep no motion background.
|
||||
- Use the cyan family (`--fos-cyan`, `--fos-ion-blue`) as the final grade tone when needed.
|
||||
|
||||
- Reverse-sync for brand/video assets
|
||||
- Use the shared Windows lane to bring in local asset drops from `C:\FamiliarOS`:
|
||||
- `powershell -File C:\ScriptoriumAI\ops\ssh\run-vps-remote-dev-reverse-sync.ps1 -Selection FamiliarOS`
|
||||
- Place local logo/video drop targets under `C:\FamiliarOS\website\public\` equivalents and re-run the above once files are present.
|
||||
|
|
|
|||
|
|
@ -102,15 +102,17 @@ export function MarketingShell({ children, showFooter = true }: MarketingShellPr
|
|||
const navGlassClassName = isDark
|
||||
? 'rounded-full border border-white/15 bg-white/5 backdrop-blur-2xl'
|
||||
: 'rounded-full border border-[#262B33]/25 bg-white/85 backdrop-blur-2xl'
|
||||
const navMetalFrameClassName = `public-nav-metal-frame ${isDark ? '' : 'bg-white/5 border border-[#262B33]/25'}`
|
||||
|
||||
const logoClassName = 'drop-shadow-[0_0_14px_rgba(232,232,232,0.36)]'
|
||||
const headerFrameClassName = 'h-[10rem] md:h-[10.5rem] lg:h-[11rem]'
|
||||
const headerInnerClassName = `relative mx-auto flex w-full max-w-7xl items-center gap-2.5 px-4 md:gap-3 md:px-5 lg:gap-4 lg:px-6 xl:gap-5 ${headerFrameClassName}`
|
||||
const emblemImageClassName = `block h-[3.8rem] w-[3.8rem] shrink-0 bg-transparent object-contain object-center sm:h-[4.2rem] sm:w-[4.2rem] md:h-[4.5rem] md:w-[4.5rem] lg:h-[4.9rem] lg:w-[4.9rem] ${logoClassName}`
|
||||
const wordmarkImageClassName = `block h-[3.35rem] w-auto max-w-[14rem] shrink-0 bg-transparent object-contain sm:h-[3.8rem] md:h-[4.2rem] md:max-w-[14.5rem] lg:h-[4.65rem] lg:max-w-[15.8rem] ${logoClassName}`
|
||||
const emblemImageClassName = `block h-[3.8rem] w-[3.8rem] shrink-0 bg-transparent object-contain object-center sm:h-[4.2rem] sm:w-[4.2rem] md:h-[4.6rem] md:w-[4.6rem] lg:h-[5rem] lg:w-[5rem] ${logoClassName}`
|
||||
const wordmarkImageClassName = `block h-[3.6rem] w-auto max-w-[14.5rem] shrink-0 bg-transparent object-contain sm:h-[4.1rem] md:h-[4.8rem] md:max-w-[15.2rem] lg:h-[5.2rem] lg:max-w-[16.5rem] ${logoClassName}`
|
||||
const logoClusterClassName = 'flex items-center gap-2.5'
|
||||
const emblemLinkClassName = 'relative z-10 flex min-w-0 items-center gap-0'
|
||||
const wordmarkLinkClassName = 'relative hidden md:inline-flex items-center justify-center'
|
||||
const wordmarkWrapperClassName = 'pointer-events-none absolute left-1/2 top-1/2 z-10 hidden -translate-x-1/2 -translate-y-1/2 flex-col items-center md:flex'
|
||||
const wordmarkLinkClassName = 'relative inline-flex items-center justify-center pointer-events-auto'
|
||||
|
||||
const activePath = useMemo(() => {
|
||||
if (location.pathname === '/about') return '/about'
|
||||
|
|
@ -165,6 +167,9 @@ export function MarketingShell({ children, showFooter = true }: MarketingShellPr
|
|||
draggable={false}
|
||||
/>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div className={wordmarkWrapperClassName}>
|
||||
<Link
|
||||
to="/"
|
||||
className={wordmarkLinkClassName}
|
||||
|
|
@ -181,63 +186,65 @@ export function MarketingShell({ children, showFooter = true }: MarketingShellPr
|
|||
</div>
|
||||
|
||||
<nav className="hidden items-center justify-center flex-1 lg:flex">
|
||||
<div className={`flex items-center gap-2 px-3 py-2 ${navGlassClassName}`}>
|
||||
{navigationItems.map((entry) => {
|
||||
if (entry.kind === 'dropdown') {
|
||||
const isChildActive = entry.children.some((c) => activePath === c.to)
|
||||
<div className={navMetalFrameClassName}>
|
||||
<div className={`flex items-center gap-2 px-3 py-2 ${navGlassClassName}`}>
|
||||
{navigationItems.map((entry) => {
|
||||
if (entry.kind === 'dropdown') {
|
||||
const isChildActive = entry.children.some((c) => activePath === c.to)
|
||||
return (
|
||||
<div key={entry.label} className="relative" ref={resourcesRef}>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setResourcesOpen((v) => !v)}
|
||||
onBlur={(e) => {
|
||||
if (!resourcesRef.current?.contains(e.relatedTarget as Node)) setResourcesOpen(false)
|
||||
}}
|
||||
className={`public-nav-link flex items-center gap-1 ${
|
||||
isChildActive
|
||||
? 'public-nav-link-active'
|
||||
: `${mutedClassName} ${navHoverClassName} hover:text-current`
|
||||
}`}
|
||||
>
|
||||
{entry.label}
|
||||
<ChevronDown size={12} className={`transition-transform ${resourcesOpen ? 'rotate-180' : ''}`} />
|
||||
</button>
|
||||
{resourcesOpen && (
|
||||
<div className={`absolute left-0 top-full mt-2 min-w-[160px] rounded-2xl border p-1 shadow-xl z-50 ${isDark ? 'bg-[hsl(var(--card))] border-white/15' : 'bg-white border-[hsl(var(--border))]'}`}>
|
||||
{entry.children.map((child) => (
|
||||
<Link
|
||||
key={child.to}
|
||||
to={child.to}
|
||||
onClick={() => setResourcesOpen(false)}
|
||||
className={`block rounded-xl px-3 py-2 text-sm transition-colors ${
|
||||
activePath === child.to
|
||||
? 'bg-[hsl(var(--brand-line))] text-[hsl(var(--foreground))]'
|
||||
: `${mutedClassName} ${navHoverClassName} hover:text-current`
|
||||
}`}
|
||||
>
|
||||
{child.label}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
const isActive = activePath === entry.to
|
||||
return (
|
||||
<div key={entry.label} className="relative" ref={resourcesRef}>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setResourcesOpen((v) => !v)}
|
||||
onBlur={(e) => {
|
||||
if (!resourcesRef.current?.contains(e.relatedTarget as Node)) setResourcesOpen(false)
|
||||
}}
|
||||
className={`public-nav-link flex items-center gap-1 ${
|
||||
isChildActive
|
||||
? 'public-nav-link-active'
|
||||
: `${mutedClassName} ${navHoverClassName} hover:text-current`
|
||||
}`}
|
||||
>
|
||||
{entry.label}
|
||||
<ChevronDown size={12} className={`transition-transform ${resourcesOpen ? 'rotate-180' : ''}`} />
|
||||
</button>
|
||||
{resourcesOpen && (
|
||||
<div className={`absolute left-0 top-full mt-2 min-w-[160px] rounded-2xl border p-1 shadow-xl z-50 ${isDark ? 'bg-[hsl(var(--card))] border-white/15' : 'bg-white border-[hsl(var(--border))]'}`}>
|
||||
{entry.children.map((child) => (
|
||||
<Link
|
||||
key={child.to}
|
||||
to={child.to}
|
||||
onClick={() => setResourcesOpen(false)}
|
||||
className={`block rounded-xl px-3 py-2 text-sm transition-colors ${
|
||||
activePath === child.to
|
||||
? 'bg-[hsl(var(--brand-line))] text-[hsl(var(--foreground))]'
|
||||
: `${mutedClassName} ${navHoverClassName} hover:text-current`
|
||||
}`}
|
||||
>
|
||||
{child.label}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<Link
|
||||
key={entry.to}
|
||||
to={entry.to}
|
||||
className={`public-nav-link ${
|
||||
isActive
|
||||
? 'public-nav-link-active'
|
||||
: `${mutedClassName} ${navHoverClassName} hover:text-current`
|
||||
}`}
|
||||
>
|
||||
{entry.label}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
const isActive = activePath === entry.to
|
||||
return (
|
||||
<Link
|
||||
key={entry.to}
|
||||
to={entry.to}
|
||||
className={`public-nav-link ${
|
||||
isActive
|
||||
? 'public-nav-link-active'
|
||||
: `${mutedClassName} ${navHoverClassName} hover:text-current`
|
||||
}`}
|
||||
>
|
||||
{entry.label}
|
||||
</Link>
|
||||
)
|
||||
})}
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,11 @@ export function PublicPrimaryButton({
|
|||
const Comp = asChild ? Slot : 'button'
|
||||
const theme = colorMode === 'light' ? 'light' : 'dark'
|
||||
const [metalReady, setMetalReady] = useState(false)
|
||||
const buttonStyle = {
|
||||
color: 'hsl(var(--brand-silver))',
|
||||
textShadow: '0 1px 2px rgba(0, 0, 0, 0.35)',
|
||||
...props.style,
|
||||
}
|
||||
|
||||
useLayoutEffect(() => {
|
||||
setSharedPreset('silver', theme)
|
||||
|
|
@ -30,6 +35,7 @@ export function PublicPrimaryButton({
|
|||
<Comp
|
||||
className={cn('public-btn-primary', className)}
|
||||
{...(asChild ? {} : { type: type ?? 'button' })}
|
||||
style={buttonStyle}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import React from 'react'
|
||||
import { LissajousDriftLoader } from './LissajousDriftLoader'
|
||||
import React from 'react'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { NamedAgentSpinner } from './agent-spinners'
|
||||
|
||||
type SkeletonBlockProps = {
|
||||
className?: string
|
||||
|
|
@ -67,10 +68,36 @@ export function EditorLoader() {
|
|||
)
|
||||
}
|
||||
|
||||
export function GeneralPageLoader({ title = 'Loading' }: { title?: string }) {
|
||||
return (
|
||||
<div className="h-full w-full flex flex-col items-center justify-center bg-[#181A1E] text-gray-300 gap-4">
|
||||
<LissajousDriftLoader text={title} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export function GeneralPageLoader({ title = 'Loading' }: { title?: string }) {
|
||||
const [isCompleting, setIsCompleting] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
const pulseTimer = window.setTimeout(() => {
|
||||
setIsCompleting(true)
|
||||
}, 900)
|
||||
const clearTimer = window.setTimeout(() => {
|
||||
setIsCompleting(false)
|
||||
}, 1550)
|
||||
|
||||
return () => {
|
||||
window.clearTimeout(pulseTimer)
|
||||
window.clearTimeout(clearTimer)
|
||||
}
|
||||
}, [])
|
||||
|
||||
const spinnerColor = isCompleting ? 'var(--fos-amber)' : 'var(--fos-cyan)'
|
||||
|
||||
return (
|
||||
<div className="general-page-loader-shell" role="status" aria-live="polite" aria-label={title}>
|
||||
<div className="general-page-loader-frame">
|
||||
<NamedAgentSpinner
|
||||
name="cascade"
|
||||
size={32}
|
||||
color={spinnerColor}
|
||||
className={`loading-spinner ${isCompleting ? 'is-completing' : ''}`}
|
||||
/>
|
||||
<p className="general-page-loader-text">{title}</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,54 +6,63 @@
|
|||
|
||||
@layer base {
|
||||
:root {
|
||||
/* FamiliarOS Brand Colors - Monochrome + deep-familar blue */
|
||||
--background: 220 13% 6%;
|
||||
--foreground: 43 66% 86%;
|
||||
|
||||
|
||||
--muted: 218 11% 14%;
|
||||
--muted-foreground: 43 28% 70%;
|
||||
|
||||
|
||||
--popover: 220 13% 6%;
|
||||
--popover-foreground: 43 50% 85%;
|
||||
|
||||
|
||||
--card: 220 11% 9%;
|
||||
--card-foreground: 43 66% 86%;
|
||||
|
||||
/* Primary: extracted from brand mark (55,106,166) */
|
||||
--primary: 212 50% 43%;
|
||||
--primary-foreground: 42 67% 95%;
|
||||
|
||||
|
||||
--primary: 190 100% 50%;
|
||||
--primary-foreground: 212 45% 97%;
|
||||
--secondary: 205 75% 20%;
|
||||
--secondary-foreground: 42 67% 95%;
|
||||
|
||||
/* Accent: extracted from icon warm neutral tones */
|
||||
--accent: 26 59% 59%;
|
||||
--accent-foreground: 220 20% 13%;
|
||||
|
||||
--brand-line: 212 50% 43%;
|
||||
--fos-cyan: 186 100% 50%;
|
||||
--fos-ion-blue: 217 100% 61%;
|
||||
--fos-deep-blue: 217 100% 52%;
|
||||
--fos-amber: 36 100% 50%;
|
||||
--fos-gold: 42 100% 62%;
|
||||
--fos-ember: 32 100% 39%;
|
||||
--fos-chrome: 220 14% 91%;
|
||||
--fos-steel: 217 11% 69%;
|
||||
--fos-gunmetal: 215 9% 25%;
|
||||
--fos-slate: 216 29% 10%;
|
||||
--fos-deep-space: 213 29% 6%;
|
||||
--fos-black: 216 33% 3%;
|
||||
|
||||
--brand-line: var(--fos-cyan);
|
||||
--brand-surface: 220 14% 12%;
|
||||
--brand-ivory: 40 34% 77%;
|
||||
--brand-gold: 43 43% 59%;
|
||||
--brand-gold-soft: 38 24% 54%;
|
||||
--brand-gold: var(--fos-gold);
|
||||
--brand-gold-soft: 47 65% 85%;
|
||||
--brand-muted: 214 7% 55%;
|
||||
--brand-pale: 209 28% 96%;
|
||||
--brand-ink: 39 63% 7%;
|
||||
--brand-deep: 220 13% 6%;
|
||||
--brand-accent-alt: 258 90% 70%;
|
||||
|
||||
|
||||
--brand-silver: 220 14% 91%;
|
||||
--brand-silver-soft: 210 11% 96%;
|
||||
--brand-silver-ink: 218 21% 24%;
|
||||
|
||||
--destructive: 0 72% 51%;
|
||||
--destructive-foreground: 210 40% 98%;
|
||||
|
||||
|
||||
--border: 214 25% 17%;
|
||||
--input: 214 25% 17%;
|
||||
--ring: 206 100% 13%;
|
||||
|
||||
|
||||
--radius: 0.5rem;
|
||||
--font-ui: 'Sora', 'Inter', 'Fira Sans', 'Source Sans 3', 'Segoe UI', sans-serif;
|
||||
--font-ui: 'Sora', 'Space Grotesk', 'Inter', 'Fira Sans', 'Source Sans 3', 'Segoe UI', sans-serif;
|
||||
--font-display: 'Orbitron', 'Sora', 'Space Grotesk', 'Inter', 'Segoe UI', sans-serif;
|
||||
--brand-silver: 0 0% 76%;
|
||||
--brand-silver-soft: 0 0% 93%;
|
||||
--brand-silver-ink: 220 7% 16%;
|
||||
}
|
||||
|
||||
* {
|
||||
|
|
@ -91,20 +100,33 @@
|
|||
--card: 220 11% 9%;
|
||||
--card-foreground: 43 66% 86%;
|
||||
|
||||
--primary: 212 50% 43%;
|
||||
--primary-foreground: 42 67% 95%;
|
||||
--primary: 190 100% 50%;
|
||||
--primary-foreground: 212 45% 97%;
|
||||
|
||||
--secondary: 205 75% 20%;
|
||||
--secondary-foreground: 42 67% 95%;
|
||||
|
||||
--accent: 26 59% 59%;
|
||||
--accent-foreground: 220 20% 13%;
|
||||
|
||||
--brand-line: 212 50% 43%;
|
||||
|
||||
--fos-cyan: 186 100% 50%;
|
||||
--fos-ion-blue: 217 100% 61%;
|
||||
--fos-deep-blue: 217 100% 52%;
|
||||
--fos-amber: 36 100% 50%;
|
||||
--fos-gold: 42 100% 62%;
|
||||
--fos-ember: 32 100% 39%;
|
||||
--fos-chrome: 220 14% 91%;
|
||||
--fos-steel: 217 11% 69%;
|
||||
--fos-gunmetal: 215 9% 25%;
|
||||
--fos-slate: 216 29% 10%;
|
||||
--fos-deep-space: 213 29% 6%;
|
||||
--fos-black: 216 33% 3%;
|
||||
|
||||
--brand-line: var(--fos-cyan);
|
||||
--brand-surface: 220 14% 12%;
|
||||
--brand-ivory: 40 34% 77%;
|
||||
--brand-gold: 43 43% 59%;
|
||||
--brand-gold-soft: 38 24% 54%;
|
||||
--brand-gold-soft: 47 65% 85%;
|
||||
--brand-muted: 214 7% 55%;
|
||||
--brand-pale: 209 28% 96%;
|
||||
--brand-ink: 39 63% 7%;
|
||||
|
|
@ -113,6 +135,10 @@
|
|||
|
||||
--destructive: 0 72% 51%;
|
||||
--destructive-foreground: 210 40% 98%;
|
||||
|
||||
--brand-silver: 220 14% 91%;
|
||||
--brand-silver-soft: 210 11% 96%;
|
||||
--brand-silver-ink: 218 21% 24%;
|
||||
|
||||
--border: 214 25% 17%;
|
||||
--input: 214 25% 17%;
|
||||
|
|
@ -134,16 +160,36 @@
|
|||
--card: 42 66% 96%;
|
||||
--card-foreground: 220 20% 16%;
|
||||
|
||||
/* Primary: keep brand gold, darker shade for contrast on light bg */
|
||||
--primary: 212 50% 43%; /* brand blue on light */
|
||||
/* Primary: keep brand blue, cooler tone on light bg */
|
||||
--primary: 190 100% 38%;
|
||||
--primary-foreground: 0 0% 100%;
|
||||
|
||||
--secondary: 42 52% 84%; /* warm light tint */
|
||||
--secondary-foreground: 220 20% 16%;
|
||||
|
||||
--accent: 26 59% 59%; /* warm neutral */
|
||||
--accent: 217 100% 45%; /* cool neutral accent */
|
||||
--accent-foreground: 0 0% 100%;
|
||||
|
||||
--fos-cyan: 186 100% 50%;
|
||||
--fos-ion-blue: 217 100% 61%;
|
||||
--fos-deep-blue: 217 100% 52%;
|
||||
--fos-amber: 36 100% 50%;
|
||||
--fos-gold: 42 100% 62%;
|
||||
--fos-ember: 32 100% 39%;
|
||||
--fos-chrome: 220 14% 91%;
|
||||
--fos-steel: 217 11% 69%;
|
||||
--fos-gunmetal: 215 9% 25%;
|
||||
--fos-slate: 216 29% 10%;
|
||||
--fos-deep-space: 213 29% 6%;
|
||||
--fos-black: 216 33% 3%;
|
||||
|
||||
--brand-line: var(--fos-cyan);
|
||||
--brand-gold: var(--fos-gold);
|
||||
--brand-gold-soft: 47 65% 85%;
|
||||
--brand-silver: 220 14% 91%;
|
||||
--brand-silver-soft: 210 11% 96%;
|
||||
--brand-silver-ink: 218 21% 24%;
|
||||
|
||||
--destructive: 0 72% 44%;
|
||||
--destructive-foreground: 0 0% 100%;
|
||||
|
||||
|
|
@ -982,11 +1028,29 @@
|
|||
}
|
||||
|
||||
/* ── CTA pill-box buttons — primary uses metal-fx wrapper on public pages ── */
|
||||
.public-nav-metal-frame {
|
||||
display: inline-flex;
|
||||
vertical-align: middle;
|
||||
border-radius: 9999px;
|
||||
border: 1px solid hsl(var(--brand-silver) / 0.2);
|
||||
background: color-mix(in srgb, hsl(var(--brand-silver) / 0.05) 78%, transparent);
|
||||
transition: transform 0.18s ease, filter 0.18s ease;
|
||||
}
|
||||
|
||||
.public-nav-metal-frame:hover {
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.public-nav-metal-frame:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.public-silver-metal-frame,
|
||||
.public-gold-metal-frame {
|
||||
display: inline-flex;
|
||||
vertical-align: middle;
|
||||
border-radius: 9999px;
|
||||
background: transparent !important;
|
||||
filter: drop-shadow(0 12px 24px hsla(var(--brand-silver) / 0.15)) drop-shadow(0 0 16px hsla(var(--brand-silver) / 0.35));
|
||||
transition: transform 0.18s ease, filter 0.18s ease;
|
||||
}
|
||||
|
|
@ -1015,16 +1079,15 @@
|
|||
line-height: 1.2;
|
||||
transition: color 0.18s ease, opacity 0.18s ease;
|
||||
background: transparent;
|
||||
color: hsl(var(--foreground));
|
||||
color: hsl(var(--brand-silver)) !important;
|
||||
border: 1px solid hsl(var(--brand-silver) / 0.7);
|
||||
box-shadow: 0 1px 4px rgba(0,0,0,0.35), 0 0 0 1px hsla(var(--brand-silver) / 0.25), 0 0 32px hsla(var(--brand-silver) / 0.2);
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
text-shadow: 0 1px 2px rgba(0,0,0,0.35);
|
||||
}
|
||||
.public-btn-primary:hover {
|
||||
color: hsl(var(--foreground));
|
||||
text-shadow: 0 1px 2px rgba(0,0,0,0.45);
|
||||
.public-btn-primary:hover {
|
||||
color: hsl(var(--brand-silver-soft));
|
||||
}
|
||||
.public-btn-primary:disabled {
|
||||
cursor: not-allowed;
|
||||
|
|
@ -1041,13 +1104,9 @@
|
|||
filter: drop-shadow(0 18px 34px rgba(90,90,90,0.2)) drop-shadow(0 0 20px rgba(220,220,220,0.18));
|
||||
}
|
||||
|
||||
[data-color-mode='light'] .public-btn-primary {
|
||||
color: #1f2937;
|
||||
text-shadow: none;
|
||||
}
|
||||
[data-color-mode='light'] .public-btn-primary,
|
||||
[data-color-mode='dark'] .public-btn-primary {
|
||||
color: #E2E8F0;
|
||||
text-shadow: 0 1px 2px rgba(0,0,0,0.45);
|
||||
color: hsl(var(--brand-silver));
|
||||
}
|
||||
|
||||
/* Secondary: ghost border */
|
||||
|
|
@ -1084,14 +1143,14 @@
|
|||
}
|
||||
|
||||
/* Nav active background — visible in both dark and light */
|
||||
.public-nav-link-active {
|
||||
background: rgba(216,203,175,0.18);
|
||||
color: #D8CBAF;
|
||||
}
|
||||
[data-color-mode='light'] .public-nav-link-active {
|
||||
background: rgba(166,146,110,0.14);
|
||||
color: #7A6A50;
|
||||
}
|
||||
.public-nav-link-active {
|
||||
background: hsl(var(--brand-silver) / 0.18);
|
||||
color: hsl(var(--brand-silver-soft));
|
||||
}
|
||||
[data-color-mode='light'] .public-nav-link-active {
|
||||
background: hsl(var(--brand-silver) / 0.18);
|
||||
color: hsl(var(--brand-silver));
|
||||
}
|
||||
}
|
||||
|
||||
@layer utilities {
|
||||
|
|
@ -1141,75 +1200,56 @@
|
|||
}
|
||||
|
||||
/* Quantum Pulse Loader */
|
||||
.generating-loader-wrapper {
|
||||
.general-page-loader-shell {
|
||||
position: relative;
|
||||
display: flex;
|
||||
min-height: calc(100vh - 10rem);
|
||||
display: grid;
|
||||
place-items: center;
|
||||
overflow: hidden;
|
||||
padding: 1.5rem;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.general-page-loader-frame {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
min-width: min(24rem, 82vw);
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
padding: 1rem;
|
||||
gap: 0.9rem;
|
||||
border: 1px solid hsl(var(--brand-silver) / 0.32);
|
||||
border-radius: 1.2rem;
|
||||
padding: 1.35rem 1.2rem 1.1rem;
|
||||
background: hsl(var(--brand-deep) / 0.35);
|
||||
box-shadow:
|
||||
inset 0 0 0 1px hsl(var(--brand-silver) / 0.08),
|
||||
0 0 28px hsl(var(--brand-silver) / 0.2);
|
||||
backdrop-filter: blur(14px);
|
||||
}
|
||||
|
||||
.generating-loader-text {
|
||||
display: flex;
|
||||
.general-page-loader-text {
|
||||
display: inline-flex;
|
||||
font-size: 0.81rem;
|
||||
font-weight: 600;
|
||||
font-size: 1.25rem;
|
||||
letter-spacing: 0.1em;
|
||||
color: hsl(var(--primary) / 0.8);
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
color: hsl(var(--brand-muted));
|
||||
}
|
||||
|
||||
.generating-loader-letter {
|
||||
display: inline-block;
|
||||
animation: generating-loader-letter-anim 2s infinite;
|
||||
.loading-spinner {
|
||||
color: hsl(var(--fos-cyan));
|
||||
text-shadow:
|
||||
0 0 6px hsl(var(--fos-cyan) / 0.9),
|
||||
0 0 18px hsl(var(--fos-ion-blue) / 0.55),
|
||||
0 0 32px hsl(var(--fos-cyan) / 0.28);
|
||||
}
|
||||
|
||||
.generating-loader-bar {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
background: linear-gradient(90deg, transparent, hsl(var(--primary)), transparent);
|
||||
animation: generating-loader-bar-anim 2s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes generating-loader-letter-anim {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(20px) rotateX(-90deg);
|
||||
text-shadow: 0 0 0px rgba(255, 255, 255, 0);
|
||||
}
|
||||
10% {
|
||||
opacity: 1;
|
||||
transform: translateY(0) rotateX(0deg);
|
||||
text-shadow: 0 0 10px rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
30% {
|
||||
opacity: 1;
|
||||
transform: translateY(0) rotateX(0deg);
|
||||
text-shadow: 0 0 10px rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
50% {
|
||||
opacity: 0;
|
||||
transform: translateY(-20px) rotateX(90deg);
|
||||
text-shadow: 0 0 0px rgba(255, 255, 255, 0);
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes generating-loader-bar-anim {
|
||||
0% {
|
||||
left: -100%;
|
||||
}
|
||||
50% {
|
||||
left: 100%;
|
||||
}
|
||||
100% {
|
||||
left: -100%;
|
||||
}
|
||||
.loading-spinner.is-completing {
|
||||
color: hsl(var(--fos-amber));
|
||||
text-shadow:
|
||||
0 0 6px hsl(var(--fos-amber) / 0.95),
|
||||
0 0 18px hsl(var(--fos-amber) / 0.55),
|
||||
0 0 32px hsl(var(--fos-gold) / 0.28);
|
||||
}
|
||||
|
||||
/* ── Collaborative cursor decorations (Monaco remote user cursors) ─────────── */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue