This commit is contained in:
oliver
2026-06-08 09:02:07 -03:00
parent 6684e500aa
commit f5c9bb6a35
4 changed files with 823 additions and 78 deletions
+27 -24
View File
@@ -6,7 +6,9 @@ Read this file fully before taking any action.
## Project Context
Single-page user portal for **agent-loft.com** — lets customers sign up, log in, and manage their AI agents. No framework, no build step, no external dependencies.
Single-page user portal for **derez.ai** — lets customers sign up, log in, and manage their AI agents. No framework, no build step, no external dependencies.
**Active visual theme:** Digital Grid — deep navy/black with electric-cyan `#00f5ff` accent, monospace `Courier New` font, 3-D perspective grid floor, star-field sky. Full design spec in `style_guide.md`.
| Item | Detail |
|---|---|
@@ -25,6 +27,7 @@ styles.css ← all styles — design tokens, layout, components
app.js ← all logic — auth, agents, keys, password, restart, backups, contract
start ← dev server launcher (live-server)
AGENTS.md ← this file
style_guide.md ← visual design spec (tokens, typography, components)
skills/
index.json ← summary: [{ name, file, description }] — loaded on wizard step 1
@@ -103,27 +106,27 @@ The email is the only session token. There is no password verification on the fr
## Design Tokens
All tokens are CSS custom properties declared in `:root` inside `styles.css`.
All tokens are CSS custom properties declared in `:root` inside `styles.css`. See `style_guide.md` for full usage rules and visual examples.
| Variable | Value | Usage |
|---|---|---|
| `--bg` | `#0f1117` | page background |
| `--bg-card` | `#1a1d27` | app shell / auth card surface |
| `--bg-inner` | `#141720` | inner cards, tabs bar |
| `--bg-hover` | `#22263a` | hover states, ghost button bg |
| `--bg-input` | `#12151f` | input / textarea background |
| `--border` | `#2a2f45` | default borders |
| `--border-hi` | `rgba(79,142,247,0.28)` | shell outer border glow |
| `--accent` | `#4f8ef7` | primary brand blue |
| `--accent-dim` | `#1a2d5e` | active tab bg, logo bg |
| `--danger` | `#e05252` | destructive actions, errors |
| `--danger-dim` | `#5a1f1f` | error message background |
| `--success` | `#3fc97e` | positive indicators, active dot |
| `--warning` | `#f0a04b` | mid-range credit bar, contract warning |
| `--text` | `#e4e8f5` | primary text |
| `--text-muted` | `#7a82a0` | secondary text, labels |
| `--bg` | `#000810` | page background |
| `--bg-card` | `#010f20` | app shell / auth card surface |
| `--bg-inner` | `#000d1a` | inner cards, tabs bar |
| `--bg-hover` | `#001a30` | hover states, ghost button bg |
| `--bg-input` | `#000813` | input / textarea background |
| `--border` | `#0a3060` | default borders |
| `--border-hi` | `rgba(0,245,255,0.45)` | shell outer border glow |
| `--accent` | `#00f5ff` | primary electric-cyan accent |
| `--accent-dim` | `#002535` | active tab bg, logo bg |
| `--danger` | `#ff3b3b` | destructive actions, errors |
| `--danger-dim` | `#3b0000` | error message background |
| `--success` | `#00ff88` | positive indicators, active dot |
| `--warning` | `#ffaa00` | mid-range credit bar, contract warning |
| `--text` | `#c8f0ff` | primary text |
| `--text-muted` | `#2e6a80` | secondary text, labels |
| `--radius` | `8px` | default border-radius |
| `--shadow` | (see CSS) | shell / auth card drop shadow |
| `--shadow` | neon glow + depth (see CSS) | shell / auth card drop shadow |
**Never use raw hex values in HTML or JS** — always reference a token via `var(--token-name)` in CSS or as a string literal only when building inline styles in JS (acceptable only for dynamic status colours in `renderKeys` and `renderContract`).
@@ -150,15 +153,15 @@ Card backgrounds are `--bg-inner` (one level darker than the shell's `--bg-card`
### Buttons
| Class | Colour | Use for |
| Class | Appearance | Use for |
|---|---|---|
| `btn btn-primary btn-sm` | `--accent` blue | navigation / open actions (Open Agent) |
| `btn btn-ghost btn-sm` | `--bg-hover` grey + border | all card-header and inline actions (Restart Agent, Buy Credits, Restore, Extend Contract, Cancel, Make Backup) |
| `btn btn-danger` | `--danger` red | confirm dialog destructive confirm only |
| `btn btn-block` | — modifier, full width | auth form submit buttons |
| `btn btn-primary btn-sm` | transparent bg · white text · `--accent` border + neon glow | primary navigation actions (Open Agent, Sign In, Next →) |
| `btn btn-ghost btn-sm` | `--bg-hover` dark bg · `--text` · `--border` | all card-header and inline actions (Restart Agent, Buy Credits, Restore, Extend Contract, Cancel, Make Backup) |
| `btn btn-danger` | `--danger` red fill · white text | confirm dialog destructive confirm only |
| `btn btn-block` | — width modifier, full width | auth form submit buttons |
**Card-header action buttons must:**
- Use `btn btn-ghost btn-sm` (grey) by default, or `btn btn-primary btn-sm` (blue) for a primary navigation action.
- Use `btn btn-ghost btn-sm` (dark) by default, or `btn btn-primary btn-sm` (cyan outline) for a primary navigation action.
- Have **no SVG icons** — text label only.
- When two buttons appear side-by-side in a header, wrap them in `<div style="display:flex;gap:8px;">` rather than placing them as siblings.
+4 -4
View File
@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Derez — My Portal</title>
<title>derez.ai — My Portal</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
@@ -37,7 +37,7 @@
/>
</svg>
</div>
<h1 class="auth-title">Derez</h1>
<h1 class="auth-title">derez.ai</h1>
<p class="auth-sub">Your AI agents, managed simply.</p>
</div>
@@ -95,7 +95,7 @@
</svg>
</div>
<div>
<h1 class="auth-title">Derez</h1>
<h1 class="auth-title">derez.ai</h1>
<p class="auth-sub">
Your AI agents, managed simply.
</p>
@@ -293,7 +293,7 @@
stroke="none"
/>
</svg>
Derez
derez.ai
</div>
<!-- ── Header comment (centre) ───────────────────── -->
<div class="header-comment" id="header-comment-wrap">
+480
View File
@@ -0,0 +1,480 @@
# style_guide.md — derez.ai Visual Design Spec
> **Scope:** tokens, typography, spacing, colour usage, and every UI component.
> Animations and background effects (star-field, perspective grid, horizon glow) are intentionally excluded — see `styles.css` directly for those.
---
## 1. Design Tokens
All variables live in `:root` inside `styles.css`. **Never hard-code hex values** in HTML or JS — always use `var(--token-name)`.
### 1.1 Colour palette
| Token | Hex / Value | Role |
|---|---|---|
| `--bg` | `#000810` | Page background — deepest layer |
| `--bg-card` | `#010f20` | App shell & auth card surface |
| `--bg-inner` | `#000d1a` | Inner cards, tabs bar |
| `--bg-hover` | `#001a30` | Hover state fills, ghost button bg |
| `--bg-input` | `#000813` | Input, select, textarea background |
| `--border` | `#0a3060` | Default 1 px borders |
| `--border-hi` | `rgba(0,245,255,0.45)` | Shell / auth card outer glow border |
| `--accent` | `#00f5ff` | Electric cyan — primary brand colour |
| `--accent-dim` | `#002535` | Active tab fill, logo icon background |
| `--danger` | `#ff3b3b` | Destructive actions, error states |
| `--danger-dim` | `#3b0000` | Error message background |
| `--success` | `#00ff88` | Positive indicators, active pulse dot |
| `--warning` | `#ffaa00` | Mid-range credit bar, contract warning |
| `--text` | `#c8f0ff` | Primary readable text |
| `--text-muted` | `#2e6a80` | Labels, secondary text, placeholders |
### 1.2 Shadow
```css
--shadow:
0 0 0 1px rgba(0, 245, 255, 0.25), /* inner border glow */
0 0 60px rgba(0, 245, 255, 0.12), /* wide cyan ambient */
0 28px 72px rgba(0, 0, 0, 0.9); /* depth shadow */
```
Used on `.auth-card` and `.app-shell`. Do not apply to inner cards — they use only `--border`.
### 1.3 Border radius
| Token | Value | Applied to |
|---|---|---|
| `--radius` | `8px` | Cards, inputs, badges, modals |
| Hard-coded `20px` | — | Pill shapes: agent tabs, user pill |
| Hard-coded `6px` | — | Buttons (`.btn`) |
| Hard-coded `4px` | — | Progress bars, small badges |
---
## 2. Typography
### 2.1 Font stack
```css
font-family: "Courier New", Courier, monospace;
```
All UI text — body, labels, inputs, buttons — uses this monospace stack. This is a deliberate brand choice for the Digital Grid theme. No external fonts are loaded.
### 2.2 Type scale
| Usage | Size | Weight | Colour token |
|---|---|---|---|
| Auth title (`derez.ai`) | `22px` | `700` | `--text` |
| Auth sub-heading | `13px` | `400` | `--text-muted` |
| App brand (upper-left) | `15px` | `700` | `--accent` |
| Card title | `13px` | `600` | `--text` |
| Body / general | `14px` | `400` | `--text` |
| Labels, secondary | `12px` | `500` | `--text-muted` |
| Monospace values (SSH, keys) | `11.5px` | `400` | `--text` |
| Hints / helper text | `11px` | `400` | `--text-muted` |
| Badges, tiny labels | `1011px` | `600` | varies |
### 2.3 Letter spacing
- App brand: `1.5px` (no text-transform — renders as `derez.ai` lowercase)
- Card titles, tab labels: default (`0`)
- Panel-header uppercase labels (e.g. "Support Chat"): `0.6px`
---
## 3. Spacing
The layout uses a consistent 4-point base grid. Common values:
| Value | Where used |
|---|---|
| `4px` | Tight gaps, small padding |
| `6px` | Button gaps, icon-text gap |
| `8px` | Toast padding, small card gap |
| `10px` | Form gap, tab gap |
| `12px` | Card body padding unit |
| `14px` | Card header margin-bottom, button padding |
| `16px` | Content grid gap, card padding |
| `18px` | Card padding (default), header horizontal padding |
| `20px` | Content grid padding |
| `22px` | Shell header horizontal padding |
---
## 4. Layout
### 4.1 Shell sizing
| Element | Size |
|---|---|
| `.app-shell` | `min(1060px, 100vw 16px)` × `min(780px, 100vh 16px)` |
| `.auth-card` (narrow) | `min(440px, 100vw 24px)` |
| `.auth-card` (auth-layout) | `min(1060px, 100vw 16px)` |
| `.app-header` height | `54px` |
| `.agent-tabs-bar` height | `50px` |
### 4.2 Content grid
```
.content-grid
display: grid
grid-template-columns: 1fr 1fr
gap: 16px
padding: 18px 20px
overflow-y: auto ← only this element scrolls
```
Collapses to single column below `700px` viewport width.
---
## 5. Colour usage rules
### Backgrounds (darkest → lightest)
```
--bg page background
└── --bg-card shell / auth card
└── --bg-inner inner cards, tabs bar
└── --bg-input inputs, textareas, code blocks
```
Use these in order. Never place `--bg-card` inside another `--bg-card` element — use `--bg-inner` for nested surfaces.
### Text hierarchy
- Main content: `--text`
- Labels, secondary: `--text-muted`
- Accent / interactive: `--accent`
- Error: `--danger`
- Success: `--success`
### Borders
- Default borders between sections: `1px solid var(--border)`
- Highlight / outer glow borders (shell, modal): `1px solid var(--border-hi)`
- Focus state on inputs: `border-color: var(--accent)`
---
## 6. Buttons
### 6.1 Variants
#### `.btn-primary` — outlined cyan (primary action)
```css
background: transparent
color: #fff
border: 1px solid var(--accent)
box-shadow: 0 0 8px rgba(0,245,255,0.35), inset 0 0 8px rgba(0,245,255,0.04)
```
Hover: `background: rgba(0,245,255,0.08)` + brighter glow. `opacity` stays `1`.
**Use for:** Open Agent, Sign In, Hire Agent, wizard Next, Send, Invite.
#### `.btn-ghost` — dark fill (secondary action)
```css
background: var(--bg-hover)
color: var(--text)
border: 1px solid var(--border)
```
Hover: `opacity: 0.85`.
**Use for:** Restart Agent, Make Backup, Restore, Extend Contract, Cancel, all card-header utility actions.
#### `.btn-danger` — red fill (destructive confirm)
```css
background: var(--danger)
color: #fff
```
**Use for:** the confirm-dialog "Confirm" button only. Never on card headers.
#### `.btn-success` — green fill
```css
background: var(--success)
color: #000
```
Rarely used; reserved for exceptional positive completions.
### 6.2 Size modifiers
| Modifier | Padding | Font size | Use |
|---|---|---|---|
| *(none)* | `7px 14px` | `13px` | Confirm dialog actions |
| `.btn-sm` | `5px 10px` | `12px` | Card header, inline |
| `.btn-block` | `10px 14px` | `14px` | Auth form full-width submit |
### 6.3 Rules
- Card-header buttons: **text label only** — no SVG icons.
- Two side-by-side header buttons: wrap in `<div style="display:flex;gap:8px;">`.
- `<a>` tags acting as buttons: apply `.btn .btn-ghost .btn-sm``.btn` nulls the underline.
- Loading state: call `btnLoad(btn, label)` to disable + show spinner; `btnReset(btn)` to restore.
- Disabled state: `opacity: 0.4; cursor: not-allowed`.
---
## 7. Cards
Every content block is a `.card`.
```html
<div class="card">
<div class="card-header">
<span class="card-title">
<svg width="14" height="14"></svg>
Title
</span>
<!-- optional: <button class="btn btn-ghost btn-sm">Action</button> -->
</div>
<!-- card body content -->
</div>
```
| Property | Value |
|---|---|
| Background | `var(--bg-inner)` |
| Border | `1px solid var(--border)` |
| Border-radius | `var(--radius)` = `8px` |
| Padding | `16px 18px` |
`.card-full` adds `flex: 1` so the card stretches to fill remaining column height (used on Backups card).
### Card title
```css
.card-title {
display: flex;
align-items: center;
gap: 7px;
font-size: 13px;
font-weight: 600;
color: var(--text);
}
```
Icon size inside `.card-title`: always `14 × 14 px` SVG, `stroke="currentColor"`, `stroke-width="2"`.
---
## 8. Forms & Inputs
### 8.1 Field structure
```html
<div class="form-row"> <!-- optional row wrapper for side-by-side fields -->
<div class="form-group">
<label>Label text</label>
<input type="text" placeholder="…" />
</div>
</div>
```
| Property | Value |
|---|---|
| Label size | `12px`, weight `500`, colour `--text-muted` |
| Input bg | `var(--bg-input)` |
| Input border | `1px solid var(--border)` |
| Input border-radius | `6px` |
| Input padding | `9px 11px` |
| Input font | `13px`, `var(--text)` |
| Focus border | `var(--accent)` |
### 8.2 Inline save button (`.pw-input-wrap`)
Used when a save action lives inside the field (e.g. Instance Password, header comment password):
```html
<div class="pw-input-wrap">
<input type="password" />
<button class="pw-save-btn" style="display:none" >
<!-- 14×14 checkmark SVG -->
</button>
</div>
```
The `.pw-save-btn` is `position: absolute; right: 6px`, shown/hidden by JS based on field content. Colour: `--accent`.
### 8.3 Textarea
Same rules as input. `resize: vertical` only. Font: monospace `12px`.
### 8.4 Select
Same visual as input. Options background: `var(--bg-card)`.
---
## 9. Data display rows
### 9.1 Server info rows
```html
<div class="server-info-row">
<span class="server-info-label">Agent Type</span>
<span class="server-info-val">hermes</span>
</div>
```
- Label: `12px`, `--text-muted`, capitalised
- Value: `11.5px`, `--text`, monospace
- Separator: `border-top: 1px solid var(--border)`
- Clickable row (SSH Access): add `.server-info-row--copy` — hover turns value `--accent` with underline
### 9.2 Backup rows
```html
<div class="backup-row">
<div class="backup-info">
<div class="backup-name">backup-2024-01-15</div>
<div class="backup-date">15 Jan 2024, 14:32</div>
</div>
<button class="btn btn-ghost btn-sm">Restore</button>
</div>
```
- Name: `13px`, weight `500`, `--text`
- Date: `11px`, `--text-muted`
- List scrolls internally at `max-height: 320px`
### 9.3 API Key rows
Key row shows: name + monospace label + credit progress bar + Buy Credits button.
Progress bar colour by usage:
- `< 50 %``.prog-low` (`--success` green)
- `5079 %``.prog-mid` (`--warning` amber)
- `≥ 80 %``.prog-high` (`--danger` red)
---
## 10. Status indicators
### 10.1 Pulse dot (online indicator)
```html
<span class="pulse-dot"></span>
```
- `7px` circle, `background: var(--success)`, CSS `pulse` animation
- Used in user-pill (header) and agent tabs
### 10.2 Contract / status dots
```html
<span class="contract-dot contract-dot--green"></span> <!-- active contract -->
<span class="contract-dot contract-dot--yellow"></span> <!-- expiring -->
<span class="contract-dot contract-dot--red"></span> <!-- expired / none -->
```
`9px` circle with a matching `box-shadow` ring at `20 %` opacity.
---
## 11. Navigation — Agent tabs
```html
<button class="agent-tab active">
<span class="agent-tab-dot"></span>
Agent Name
<span class="agent-tab-badge">fr</span>
</button>
```
| State | Style |
|---|---|
| Default | `border: 1px solid var(--border)`, `color: --text-muted`, transparent bg |
| Hover | `border-color: rgba(0,245,255,0.4)`, `bg: --bg-hover`, `color: --text` |
| Active | `bg: --accent-dim`, `border: --accent`, `color: --accent` |
`.agent-tab-badge` (region code): `10px`, weight `600`, `bg: --bg-hover` default, `bg: rgba(0,245,255,0.2)` when active.
---
## 12. Progress bars
```html
<div class="prog-wrap">
<div class="prog-bar prog-low" style="width: 42%"></div>
</div>
```
- Track: `bg: --bg-input`, `height: 4px`, `border-radius: 4px`
- Fill: `height: 100%`, `border-radius: 4px`, `transition: width 0.5s ease`
- Colour class: `.prog-low` / `.prog-mid` / `.prog-high` (see §9.3)
---
## 13. Loading & feedback
### 13.1 Loading rows
```html
<div class="loading-row"><div class="spinner"></div></div>
```
Centred, `padding: 20px`. The spinner is `18px`, `border: 2px solid var(--border)`, `border-top-color: var(--accent)`.
`.spinner-sm` (13 px) goes inside a button during `btnLoad()`.
### 13.2 Toast notifications
Call `toast(message, type)` — never create toast HTML manually.
| `type` | Left-border colour |
|---|---|
| `'info'` | `--accent` |
| `'success'` | `--success` |
| `'error'` | `--danger` |
| `'warning'` | `--warning` |
Toast body: `bg: --bg-card`, `border: 1px solid --border`, `border-radius: --radius`, auto-removes after 4 s.
### 13.3 Confirm dialog (modal)
```js
const ok = await confirmDialog('Title', 'Message explaining the action.');
if (!ok) return;
```
Modal: `bg: --bg-card`, `border: --border-hi`, `border-radius: 12px`. Footer has Cancel (`.btn-ghost`) + Confirm (`.btn-danger`).
---
## 14. Header layout
```
.app-header (54px tall, padding: 0 22px)
├── .app-brand ← "derez.ai" lowercase, --accent, 15px bold, letter-spacing 1.5px
├── .header-comment ← centred, flex:1, editable agent name label
└── .app-user
├── .user-pill ← pulse-dot + email, border: --border, hover: --accent
└── .btn.btn-ghost.btn-sm ← "Sign Out"
```
Header background: `linear-gradient(90deg, rgba(0,245,255,0.08), transparent 60%)` + `border-bottom: 1px solid var(--border-hi)`.
---
## 15. Auth card
Auth card exists in two layouts controlled by the `body.auth-layout` class added by JS:
| Mode | Width | Layout |
|---|---|---|
| Narrow (no class) | `min(440px, 100vw24px)` | Single column — tab toggle shows Sign In / Hire Agent |
| Wide (auth-layout) | `min(1060px, 100vw16px)` | Two panes side-by-side, tab toggle hidden |
Pricing badge (wide mode only): `bg: --accent-dim`, `border: 1px solid rgba(0,245,255,0.35)`, `border-radius: --radius`.
---
## 16. Rules for new components
1. **Backgrounds:** use `--bg-inner` for cards nested inside the shell. Use `--bg-input` for text entry surfaces only.
2. **Borders:** always `1px solid var(--border)` for structure; `var(--border-hi)` for emphasis (outer glow, focus rings on major panels).
3. **Text:** never set a custom colour — use only `--text`, `--text-muted`, `--accent`, `--danger`, `--success`, `--warning`.
4. **Icons in titles:** always `14 × 14 px`, `stroke="currentColor"`, `stroke-width="2"`.
5. **Inline colour values in JS** are allowed only in `renderKeys()` and `renderContract()` for dynamic progress/status colours.
6. **No raw hex values** anywhere else in HTML or JS.
+312 -50
View File
@@ -7,37 +7,34 @@
padding: 0;
}
/* ─── Design tokens ──────────────────────────────────────────── */
/* ─── Design tokens — THEME 01: DIGITAL GRID (Tron-inspired) ── */
:root {
--bg: #0f1117;
--bg-card: #1a1d27;
--bg-inner: #141720;
--bg-hover: #22263a;
--bg-input: #12151f;
--border: #2a2f45;
--border-hi: rgba(79, 142, 247, 0.28);
--accent: #4f8ef7;
--accent-dim: #1a2d5e;
--danger: #e05252;
--danger-dim: #5a1f1f;
--success: #3fc97e;
--warning: #f0a04b;
--text: #e4e8f5;
--text-muted: #7a82a0;
--bg: #000810;
--bg-card: #010f20;
--bg-inner: #000d1a;
--bg-hover: #001a30;
--bg-input: #000813;
--border: #0a3060;
--border-hi: rgba(0, 245, 255, 0.45);
--accent: #00f5ff;
--accent-dim: #002535;
--danger: #ff3b3b;
--danger-dim: #3b0000;
--success: #00ff88;
--warning: #ffaa00;
--text: #c8f0ff;
--text-muted: #2e6a80;
--radius: 8px;
--shadow:
0 28px 72px rgba(0, 0, 0, 0.72), 0 0 0 1px rgba(79, 142, 247, 0.06);
0 0 0 1px rgba(0, 245, 255, 0.25), 0 0 60px rgba(0, 245, 255, 0.12),
0 28px 72px rgba(0, 0, 0, 0.9);
}
/* ─── Base ───────────────────────────────────────────────────── */
html,
body {
height: 100%;
font-family:
"Segoe UI",
system-ui,
-apple-system,
sans-serif;
font-family: "Courier New", Courier, monospace;
background: var(--bg);
color: var(--text);
font-size: 14px;
@@ -47,21 +44,266 @@ body {
justify-content: center;
}
/* Subtle ambient glow in background */
/* Digital grid — star field, ambient glow, horizon line */
body::before {
content: "";
position: fixed;
inset: 0;
background:
/* ── Stars: solid-core dots, varied size & tint ── */
/* Row 1 — bright feature stars (y 312 %) */
radial-gradient(
ellipse 60% 50% at 25% 30%,
rgba(79, 142, 247, 0.07) 0%,
transparent 70%
circle 5px at 5% 8%,
white 0%,
white 40%,
rgba(180, 245, 255, 0.3) 72%,
transparent 100%
),
radial-gradient(
ellipse 50% 60% at 75% 70%,
rgba(100, 50, 200, 0.05) 0%,
transparent 70%
circle 3px at 15% 5%,
white 0%,
white 42%,
transparent 100%
),
radial-gradient(
circle 3px at 22% 12%,
rgba(180, 235, 255, 1) 0%,
rgba(180, 235, 255, 1) 42%,
transparent 100%
),
radial-gradient(
circle 6px at 31% 4%,
white 0%,
white 38%,
rgba(150, 220, 255, 0.35) 70%,
transparent 100%
),
radial-gradient(
circle 3px at 40% 9%,
rgba(160, 230, 255, 1) 0%,
rgba(160, 230, 255, 1) 42%,
transparent 100%
),
radial-gradient(
circle 3px at 47% 6%,
white 0%,
white 42%,
transparent 100%
),
radial-gradient(
circle 4px at 54% 3%,
rgba(190, 245, 255, 1) 0%,
rgba(190, 245, 255, 1) 42%,
rgba(190, 245, 255, 0.3) 72%,
transparent 100%
),
radial-gradient(
circle 3px at 63% 11%,
white 0%,
white 42%,
transparent 100%
),
radial-gradient(
circle 5px at 71% 7%,
white 0%,
white 40%,
rgba(180, 245, 255, 0.28) 70%,
transparent 100%
),
radial-gradient(
circle 3px at 79% 4%,
rgba(150, 215, 255, 1) 0%,
rgba(150, 215, 255, 1) 42%,
transparent 100%
),
radial-gradient(
circle 3px at 87% 9%,
white 0%,
white 42%,
transparent 100%
),
radial-gradient(
circle 4px at 94% 5%,
rgba(190, 245, 255, 1) 0%,
rgba(190, 245, 255, 1) 42%,
rgba(190, 245, 255, 0.28) 70%,
transparent 100%
),
/* Row 2 — mid brightness (y 1426 %) */
radial-gradient(
circle 2px at 9% 19%,
rgba(255, 255, 255, 0.65) 0%,
rgba(255, 255, 255, 0.65) 45%,
transparent 100%
),
radial-gradient(
circle 3px at 18% 16%,
white 0%,
white 42%,
transparent 100%
),
radial-gradient(
circle 2px at 27% 22%,
rgba(180, 240, 255, 0.7) 0%,
rgba(180, 240, 255, 0.7) 45%,
transparent 100%
),
radial-gradient(
circle 3px at 37% 14%,
white 0%,
white 42%,
transparent 100%
),
radial-gradient(
circle 2px at 50% 25%,
rgba(255, 255, 255, 0.6) 0%,
rgba(255, 255, 255, 0.6) 45%,
transparent 100%
),
radial-gradient(
circle 4px at 57% 17%,
rgba(180, 240, 255, 1) 0%,
rgba(180, 240, 255, 1) 42%,
rgba(180, 240, 255, 0.28) 70%,
transparent 100%
),
radial-gradient(
circle 2px at 66% 23%,
rgba(255, 255, 255, 0.55) 0%,
rgba(255, 255, 255, 0.55) 45%,
transparent 100%
),
radial-gradient(
circle 3px at 75% 15%,
white 0%,
white 42%,
transparent 100%
),
radial-gradient(
circle 2px at 83% 20%,
rgba(160, 225, 255, 0.7) 0%,
rgba(160, 225, 255, 0.7) 45%,
transparent 100%
),
radial-gradient(
circle 2px at 91% 17%,
rgba(255, 255, 255, 0.6) 0%,
rgba(255, 255, 255, 0.6) 45%,
transparent 100%
),
radial-gradient(
circle 3px at 98% 24%,
rgba(180, 240, 255, 1) 0%,
rgba(180, 240, 255, 1) 42%,
transparent 100%
),
/* Row 3 — dim background stars (y 2842 %) */
radial-gradient(
circle 2px at 3% 33%,
rgba(255, 255, 255, 0.4) 0%,
rgba(255, 255, 255, 0.4) 45%,
transparent 100%
),
radial-gradient(
circle 2px at 13% 38%,
rgba(180, 235, 255, 0.45) 0%,
rgba(180, 235, 255, 0.45) 45%,
transparent 100%
),
radial-gradient(
circle 2px at 24% 30%,
rgba(255, 255, 255, 0.38) 0%,
rgba(255, 255, 255, 0.38) 45%,
transparent 100%
),
radial-gradient(
circle 3px at 33% 40%,
rgba(170, 230, 255, 0.55) 0%,
rgba(170, 230, 255, 0.55) 42%,
transparent 100%
),
radial-gradient(
circle 2px at 44% 34%,
rgba(255, 255, 255, 0.38) 0%,
rgba(255, 255, 255, 0.38) 45%,
transparent 100%
),
radial-gradient(
circle 2px at 53% 42%,
rgba(255, 255, 255, 0.35) 0%,
rgba(255, 255, 255, 0.35) 45%,
transparent 100%
),
radial-gradient(
circle 2px at 62% 31%,
rgba(180, 240, 255, 0.45) 0%,
rgba(180, 240, 255, 0.45) 45%,
transparent 100%
),
radial-gradient(
circle 3px at 69% 38%,
white 0%,
white 42%,
transparent 100%
),
radial-gradient(
circle 2px at 77% 29%,
rgba(255, 255, 255, 0.4) 0%,
rgba(255, 255, 255, 0.4) 45%,
transparent 100%
),
radial-gradient(
circle 2px at 85% 36%,
rgba(180, 235, 255, 0.42) 0%,
rgba(180, 235, 255, 0.42) 45%,
transparent 100%
),
radial-gradient(
circle 2px at 96% 32%,
rgba(255, 255, 255, 0.38) 0%,
rgba(255, 255, 255, 0.38) 45%,
transparent 100%
),
/* ── Ambient glow + horizon line ── */
radial-gradient(
ellipse 70% 55% at 50% 48%,
rgba(0, 120, 200, 0.18) 0%,
transparent 68%
),
radial-gradient(
ellipse 100% 4% at 50% 50%,
rgba(0, 245, 255, 0.22) 0%,
transparent 100%
);
pointer-events: none;
z-index: 0;
}
/* 3-D perspective grid floor — recedes to vanishing point */
body::after {
content: "";
position: fixed;
left: -100%;
width: 300%;
height: 62%;
bottom: -8%;
background-image:
linear-gradient(rgba(0, 245, 255, 0.28) 1px, transparent 1px),
linear-gradient(90deg, rgba(0, 245, 255, 0.16) 1px, transparent 1px);
background-size: 80px 40px;
transform: perspective(520px) rotateX(75deg);
transform-origin: center 0%;
-webkit-mask-image: linear-gradient(
to bottom,
transparent 0%,
rgba(0, 0, 0, 0.55) 22%,
black 50%
);
mask-image: linear-gradient(
to bottom,
transparent 0%,
rgba(0, 0, 0, 0.55) 22%,
black 50%
);
pointer-events: none;
z-index: 0;
@@ -74,20 +316,22 @@ body::before {
width: min(440px, calc(100vw - 24px));
background: var(--bg-card);
border: 1px solid var(--border-hi);
border-radius: 18px;
border-radius: var(--radius);
box-shadow: var(--shadow);
overflow: hidden;
animation: fadeUp 0.3s ease both;
animation: fadeUp 1s cubic-bezier(0.65, 0, 0.85, 0.05) 1 both;
}
@keyframes fadeUp {
from {
opacity: 0;
transform: translateY(18px);
transform: scale(0);
filter: blur(6px);
}
to {
opacity: 1;
transform: translateY(0);
transform: scale(1);
filter: blur(0);
}
}
@@ -202,10 +446,10 @@ body::before {
height: min(780px, calc(100vh - 16px));
background: var(--bg-card);
border: 1px solid var(--border-hi);
border-radius: 18px;
border-radius: var(--radius);
box-shadow: var(--shadow);
overflow: hidden;
animation: fadeUp 0.25s ease both;
animation: fadeUp 1s cubic-bezier(0.65, 0, 0.85, 0.05) 1 both;
}
/* App header */
@@ -215,10 +459,10 @@ body::before {
justify-content: space-between;
height: 54px;
padding: 0 22px;
border-bottom: 1px solid var(--border);
border-bottom: 1px solid var(--border-hi);
background: linear-gradient(
90deg,
rgba(79, 142, 247, 0.06) 0%,
rgba(0, 245, 255, 0.08) 0%,
transparent 60%
);
flex-shrink: 0;
@@ -232,7 +476,8 @@ body::before {
font-weight: 700;
font-size: 15px;
color: var(--accent);
letter-spacing: 0.2px;
letter-spacing: 1.5px;
text-shadow: 0 0 14px rgba(0, 245, 255, 0.85);
flex-shrink: 0;
}
@@ -892,6 +1137,8 @@ body::before {
transition:
opacity 0.15s,
background 0.15s,
box-shadow 0.15s,
border-color 0.15s,
transform 0.1s;
flex-shrink: 0;
}
@@ -910,8 +1157,21 @@ body::before {
}
.btn-primary {
background: var(--accent);
background: transparent;
color: #fff;
border: 1px solid var(--accent);
box-shadow:
0 0 8px rgba(0, 245, 255, 0.35),
inset 0 0 8px rgba(0, 245, 255, 0.04);
}
.btn-primary:hover {
opacity: 1;
background: rgba(0, 245, 255, 0.08);
border-color: var(--accent);
box-shadow:
0 0 18px rgba(0, 245, 255, 0.55),
inset 0 0 12px rgba(0, 245, 255, 0.07);
}
.btn-danger {
background: var(--danger);
@@ -1209,9 +1469,10 @@ body::before {
/* ─── Talk to Us panel ──────────────────────────────────────────── */
.talk-wrap {
border-top: 2px solid var(--accent);
border-top: 1px solid var(--border-hi);
flex-shrink: 0;
background: var(--bg-inner);
box-shadow: 0 -4px 20px rgba(0, 245, 255, 0.08);
}
.talk-toggle {
width: 100%;
@@ -1221,7 +1482,7 @@ body::before {
padding: 9px 22px;
background: linear-gradient(
90deg,
rgba(79, 142, 247, 0.08) 0%,
rgba(0, 245, 255, 0.08) 0%,
transparent 70%
);
border: none;
@@ -1237,7 +1498,7 @@ body::before {
.talk-toggle:hover {
background: linear-gradient(
90deg,
rgba(79, 142, 247, 0.16) 0%,
rgba(0, 245, 255, 0.16) 0%,
transparent 70%
);
color: var(--text);
@@ -1246,7 +1507,7 @@ body::before {
color: var(--text);
background: linear-gradient(
90deg,
rgba(79, 142, 247, 0.14) 0%,
rgba(0, 245, 255, 0.14) 0%,
transparent 70%
);
}
@@ -1444,8 +1705,8 @@ body.auth-layout .pricing-badge {
margin: 20px 24px 0;
padding: 14px 20px;
background: var(--accent-dim);
border: 1px solid rgba(79, 142, 247, 0.35);
border-radius: 12px;
border: 1px solid rgba(0, 245, 255, 0.35);
border-radius: var(--radius);
}
.pricing-amount {
font-size: 22px;
@@ -1561,6 +1822,7 @@ body.auth-layout #signin-btn {
width: min(1060px, calc(100vw - 16px));
height: min(500px, calc(100vh - 360px));
flex-shrink: 0;
animation: none; /* prevent double-play alongside auth-card */
}
#app-shell.demo-mode .app-header,
@@ -1624,17 +1886,17 @@ body.auth-layout #signin-btn {
@keyframes shellEnter {
from {
opacity: 0;
transform: translateY(22px);
filter: blur(10px);
transform: scale(0);
filter: blur(6px);
}
to {
opacity: 1;
transform: none;
filter: none;
transform: scale(1);
filter: blur(0);
}
}
#app-shell.app-entering {
animation: shellEnter 0.55s cubic-bezier(0.22, 1, 0.36, 1) forwards;
animation: shellEnter 1s cubic-bezier(0.65, 0, 0.85, 0.05) 1 forwards;
}
/* On screens too narrow for the dual layout, fall back to single column */