deckhearth/styles/globals.css
varutasu 87a71f2068
refactor(styles): retire .card; migrate 7 consumers to .glass-panel (#122)
Brief 5 of unify-glass-panel-surfaces convoy. Deletes the legacy
.card class from styles/globals.css and migrates all consumers
(actual count: 7, not 8 as the brief had estimated — one of the
suspected sites was already on a different pattern) to
.glass-panel rounded-3xl p-{4|6}.

A single panel vocabulary across the app — .glass-panel for body
content, .glass-panel-strong for floating chrome/popovers,
.page-header-glass for full-bleed top strips — is the convoy's
success metric. .card predated the gradient-border system and was
the only remaining "opaque solid panel" pattern in user-facing pages.

Consumers migrated:
  - pages/settings.js × 2 (p-4 and p-6 cards)
  - pages/profile.js × 3 (avatar card, stats card, activity card)
  - pages/community/collections.js × 1
  - components/CollectionsPageView.js × 1

Each migration:
  - Replaces `card` with `glass-panel rounded-3xl` in the className.
  - Preserves sibling Tailwind tokens (p-4 / p-6 / text-center /
    mt-6 / group / cursor-pointer).
  - Adds `transition-all duration-{200|300}` explicitly where the
    legacy class baked it in (5 of 7 sites needed this back).
  - Drops hover:shadow-{lg,xl} Tailwind overrides on the 2 community
    sites; the .glass-panel corner-light gradient is the new
    affordance.

CSS change in styles/globals.css:
  - Removed the `.card { @apply rounded-3xl shadow-lg p-6
    transition-all duration-300; background-color:
    var(--bg-primary); border: 1px solid var(--border); }` rule.
  - Added a documentation comment in its place explaining the
    retirement and pointing future consumers at the right alternative.

Verification:
  - rg "className=[\"'\`]card\b" pages/ components/ --type js
    returns 0 matches.
  - rg "^\.card \{" styles/ returns 0 matches.
  - npm run lint passes (1 pre-existing warning unrelated).
  - npm run test:run: 113/113 tests pass.

Acceptance criteria from
.convoys/unify-glass-panel-surfaces/brief-5-retire-card-class.md
all met. No escape-hatch sites needed; all 7 migrations were clean.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-04 15:30:29 -05:00

1368 lines
No EOL
45 KiB
CSS

@tailwind base;
@tailwind components;
@tailwind utilities;
/* Custom styles */
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
transition: background-color 0.3s ease, color 0.3s ease;
}
/* Theme Variables - Deck Hearth Fire-Inspired */
:root {
/* Light Theme - Warm Daylight by the Hearth */
--bg-primary-light: #fefcf8; /* Warm cream, like sunlit stone */
--bg-secondary-light: #f7f3ed; /* Soft beige, like aged parchment */
--bg-tertiary-light: #f0e6d6; /* Light wood tone */
--text-primary-light: #2d1810; /* Dark chocolate brown */
--text-secondary-light: #5d4037; /* Medium brown, like burnt wood */
--text-accent-light: #d84315; /* Ember orange */
--border-light: #e8dcc6; /* Light wood border */
--shadow-light: 0 4px 6px -1px rgba(45, 24, 16, 0.1);
--gradient-primary-light: linear-gradient(135deg, #ff6f00 0%, #d84315 100%); /* Fire gradient */
--gradient-secondary-light: linear-gradient(135deg, #ffab40 0%, #ff6f00 100%); /* Golden flame */
--accent-flame-light: #ff6f00; /* Bright flame orange */
--accent-ember-light: #d84315; /* Deep ember red */
--accent-gold-light: #ffab40; /* Golden flame */
--accent-wood-light: #8d6e63; /* Rich wood tone */
--input-bg-light: #fefcf8;
--input-border-light: #e8dcc6;
--input-text-light: #2d1810;
--input-placeholder-light: #5d4037;
/* RGB color variables for backdrop-blur effects */
--bg-primary-rgb: 254, 252, 248;
--bg-secondary-rgb: 247, 243, 237;
--bg-tertiary-rgb: 240, 230, 214;
--accent-ember-rgb: 216, 67, 21; /* RGB version of #d84315 */
}
[data-theme="dark"] {
/* Dark Theme - Deep Navy Hearth Room (operator mockup, 2026-06-04)
The base is no longer warm-charcoal-brown — that read as "muddy"
and didn't let the ember corners glow. Switched to a deep cool-navy
base so the ember-orange and purple-magenta corner pools have
somewhere to be vivid against. The "fireplace warmth" survives as
gradient corner-glow, accent tokens, and the inner-rim highlights,
NOT as panel fill — same Liquid-Glass principle as the original
epic, just executed at mockup intensity rather than the imperceptible
intensity of PRs #100-#101. */
--bg-primary-dark: #0d0e1a; /* Deep cool-navy, like night sky over coals */
--bg-secondary-dark: #14162a; /* Slightly lighter navy, for inset surfaces */
--bg-tertiary-dark: #1d1f3a; /* Tertiary navy, for nested chrome */
--text-primary-dark: #fff8f0; /* Warm white, like firelight */
--text-secondary-dark: #d7c4b0; /* Soft cream, like candlelight */
--text-accent-dark: #ff8a50; /* Bright flame orange */
--border-dark: #4a2f1f; /* Dark wood border */
--shadow-dark: 0 4px 6px -1px rgba(26, 15, 10, 0.4);
--gradient-primary-dark: linear-gradient(135deg, #ff8a50 0%, #d84315 100%); /* Evening fire */
--gradient-secondary-dark: linear-gradient(135deg, #ffab40 0%, #ff6f00 100%); /* Golden embers */
--accent-flame-dark: #ff8a50; /* Bright flame */
--accent-ember-dark: #d84315; /* Glowing ember */
--accent-gold-dark: #ffab40; /* Golden glow */
--accent-wood-dark: #8d6e63; /* Warm wood */
--input-bg-dark: #2d1b12;
--input-border-dark: #4a2f1f;
--input-text-dark: #fff8f0;
--input-placeholder-dark: #d7c4b0;
--search-bg-dark: #2d1b12;
--search-border-dark: #4a2f1f;
--search-text-dark: #fff8f0;
--search-placeholder-dark: #d7c4b0;
/* RGB color variables for backdrop-blur effects */
--bg-primary-rgb: 26, 15, 10;
--bg-secondary-rgb: 45, 27, 18;
--bg-tertiary-rgb: 61, 35, 23;
--accent-ember-rgb: 216, 67, 21; /* RGB version of #d84315 */
}
/* ============================================================
Liquid Glass tokens — added by liquid-glass-design-tokens convoy
(2026-06-03). See docs/DESIGN_TOKENS.md for the full reference,
contrast tables, composite recipes, and "When NOT to use glass"
guidance.
============================================================ */
:root {
/* Glass surfaces (light) — 3-step legibility ramp.
low: modal panels inside a scrim, card detail, inline sub-panels.
mid: sidebar rail, header strip, mobile bottom-bar.
high: popovers, dropdowns, tooltips (can land over anything). */
--glass-surface-low: rgba(254, 252, 248, 0.55);
--glass-surface-mid: rgba(254, 252, 248, 0.68);
--glass-surface-high: rgba(254, 252, 248, 0.82);
/* Glass blur + saturate (theme-independent; inherited by dark). */
--glass-blur-low: 12px;
--glass-blur-mid: 20px;
--glass-blur-high: 32px;
--glass-saturate: 140%;
/* Rim-light (light) — inner highlight + outer hairline. */
--rim-light-inner: inset 0 1px 0 0 rgba(255, 255, 255, 0.65);
--rim-light-outer: 0 0 0 1px rgba(45, 24, 16, 0.08);
/* Ember rim — composable RGB triple + two preset variants.
Triple is theme-independent (ember orange #d84315);
variants differ per theme for eye-perception correction. */
--ember-rim-color: 216, 67, 21;
--ember-rim-subtle: inset 0 0 0 1px rgba(216, 67, 21, 0.35);
--ember-rim-pronounced:
inset 0 0 0 1px rgba(216, 67, 21, 0.55),
0 0 16px 0 rgba(216, 67, 21, 0.30);
/* Elevation (light) — warm-brown-tinted shadows. */
--elevation-flat: none;
--elevation-ambient:
0 4px 12px -2px rgba(45, 24, 16, 0.08),
0 2px 4px -1px rgba(45, 24, 16, 0.04);
--elevation-pronounced:
0 24px 48px -12px rgba(45, 24, 16, 0.20),
0 12px 24px -6px rgba(45, 24, 16, 0.10),
0 4px 8px -2px rgba(45, 24, 16, 0.06);
/* Modal scrim (light) — warm coffee-brown, NOT pure black. */
--modal-scrim: rgba(45, 24, 16, 0.35);
/* Motion (theme-independent). 4-tier duration taxonomy + 3 easings.
See docs/MOTION_SYSTEM.md for usage, examples, and the
prefers-reduced-motion contract. */
--motion-duration-instant: 0ms;
--motion-duration-quick: 150ms; /* hover, focus, micro-state */
--motion-duration-default: 250ms; /* default for most transitions */
--motion-duration-slow: 400ms; /* modal scale, sidebar slide */
--motion-duration-deliberate: 600ms; /* hero, onboarding, celebration */
--motion-ease-out: cubic-bezier(0.16, 1, 0.3, 1); /* default */
--motion-ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1); /* delight */
--motion-ease-linear: linear; /* progress */
}
[data-theme="dark"] {
/* Glass surfaces (dark) — alpha ramp over the new deep-navy base
(#0d0e1a from the operator mockup, 2026-06-04). RGB is updated
from the prior warm-charcoal (26,15,10) so glass-on-dark blends
with the bg without muddy color shift. */
--glass-surface-low: rgba(20, 22, 42, 0.62);
--glass-surface-mid: rgba(20, 22, 42, 0.74);
--glass-surface-high: rgba(20, 22, 42, 0.86);
/* Rim-light (dark) — softer warm-white inner + faint outer. */
--rim-light-inner: inset 0 1px 0 0 rgba(255, 248, 240, 0.12);
--rim-light-outer: 0 0 0 1px rgba(255, 248, 240, 0.06);
/* Ember rim (dark) — alpha bumped to compensate for ember orange
reading less vibrant on dark backgrounds (eye-perception correction,
not a numerical drift). RGB triple inherits from :root. */
--ember-rim-subtle: inset 0 0 0 1px rgba(216, 67, 21, 0.40);
--ember-rim-pronounced:
inset 0 0 0 1px rgba(216, 67, 21, 0.65),
0 0 16px 0 rgba(216, 67, 21, 0.35);
/* Elevation (dark) — pure-black shadows for crisp depth against
the warm-charcoal floor. */
--elevation-ambient:
0 4px 12px -2px rgba(0, 0, 0, 0.40),
0 2px 4px -1px rgba(0, 0, 0, 0.30);
--elevation-pronounced:
0 24px 48px -12px rgba(0, 0, 0, 0.55),
0 12px 24px -6px rgba(0, 0, 0, 0.40),
0 4px 8px -2px rgba(0, 0, 0, 0.25);
/* Modal scrim (dark) — heavier black; dark theme starts dark so
needs more contrast to feel "behind" the modal. */
--modal-scrim: rgba(0, 0, 0, 0.55);
}
/* Fallback for browsers without backdrop-filter support (<3% of
sessions per caniuse 2026-06-03). Collapses the alpha ramp toward
solid so glass surfaces remain legible without the blur layer.
Never goes fully opaque — preserves the design's tinted-surface
intent and the ramp ordering. The @supports negation guards both
the unprefixed property AND -webkit-backdrop-filter (Safari 9-17
needed the prefix). */
@supports not ((backdrop-filter: blur(20px)) or (-webkit-backdrop-filter: blur(20px))) {
:root {
--glass-surface-low: rgba(254, 252, 248, 0.92);
--glass-surface-mid: rgba(254, 252, 248, 0.95);
--glass-surface-high: rgba(254, 252, 248, 0.98);
}
[data-theme="dark"] {
--glass-surface-low: rgba(20, 22, 42, 0.92);
--glass-surface-mid: rgba(20, 22, 42, 0.95);
--glass-surface-high: rgba(20, 22, 42, 0.98);
}
}
/* Apply theme colors.
The hearth gradient: two diagonal light sources that the floating
chrome chips visually "respond" to via the --corner-light-warm /
--corner-light-cool design tokens (defined further down in :root /
[data-theme="dark"]; consumed as radial-gradient layers on each
chip's BORDER, not as outer drop shadows — see `.glass-panel`).
- Warm ember light source: bottom-left of the viewport.
- Cool purpley-blue light source: top-right of the viewport.
The base linear-gradient runs along the same 45deg diagonal between
the two sources so the page itself reads as a single continuous
wash, not just two corner pools on a flat substrate. Pushed harder
2026-06-04 per operator feedback ("increase the gradient in the
background that goes from our nice warm red to a nice purpley
blue") — alphas roughly doubled vs the prior pass, ellipses
enlarged, and the top-right corner switched from gold to
purpley-blue on light theme so both themes carry the same warm↔
cool diagonal story.
Fixed attachment so scrolling content slides over the gradient
rather than pulling it along — that's what gives glass surfaces
their parallax-blur behavior. */
body {
background-color: var(--bg-primary-light);
background-image:
/* Warm ember pool, bottom-left — primary light source. */
radial-gradient(
ellipse 90% 65% at 5% 110%,
rgba(255, 95, 0, 0.55) 0%,
rgba(255, 130, 25, 0.28) 28%,
rgba(255, 171, 64, 0.10) 55%,
transparent 80%
),
/* Purpley-blue pool, top-right — secondary light source (replaces
the prior gold accent). Indigo→violet so the chip rims that
respond to this source via --corner-light-cool read as cool. */
radial-gradient(
ellipse 85% 65% at 100% -8%,
rgba(99, 102, 241, 0.42) 0%,
rgba(124, 58, 237, 0.20) 30%,
rgba(167, 139, 250, 0.08) 58%,
transparent 80%
),
/* Base diagonal wash: warm-cream bottom-left → cool-violet top-right.
45deg = bottom-left → top-right (matches the two light sources). */
linear-gradient(
45deg,
rgba(255, 240, 220, 1) 0%,
rgba(252, 244, 230, 1) 50%,
rgba(230, 232, 252, 1) 100%
);
background-attachment: fixed;
color: var(--text-primary-light);
}
[data-theme="dark"] body {
background-color: var(--bg-primary-dark);
background-image:
/* Warm ember-red pool, bottom-left — primary light source.
Pushed to 0.72 (was 0.55) so the operator's "nice warm red"
reads as a real glow against deep navy. */
radial-gradient(
ellipse 95% 70% at 5% 110%,
rgba(255, 65, 25, 0.72) 0%,
rgba(255, 95, 0, 0.42) 24%,
rgba(255, 130, 30, 0.16) 52%,
transparent 80%
),
/* Purpley-blue pool, top-right — secondary light source. Pushed
to 0.58 (was 0.26) + a more saturated indigo→violet ramp so
the corner reads unambiguously as the second light source the
chip rims respond to. */
radial-gradient(
ellipse 90% 70% at 100% -10%,
rgba(139, 92, 246, 0.58) 0%,
rgba(99, 102, 241, 0.32) 28%,
rgba(168, 85, 247, 0.12) 55%,
transparent 82%
),
/* Base diagonal wash: warm-tinted deep aubergine bottom-left →
cool-tinted deep indigo top-right. 45deg matches the light
sources. The midpoint stays near the previous deep-navy so
chrome surfaces still have a calm substrate to blur against. */
linear-gradient(
45deg,
rgba(40, 16, 22, 1) 0%,
rgba(17, 18, 38, 1) 50%,
rgba(28, 22, 58, 1) 100%
);
background-attachment: fixed;
color: var(--text-primary-dark);
}
/* .page-header-glass — the recurring "page header strip" pattern
(full-bleed band at the top of authenticated pages: dashboard, my-
cards, cards, collections, community/collections, collection/[id],
scanner). Uses a higher-tint surface than .glass-panel because the
strip spans the whole content width and needs more visual weight,
but inherits the same rim + blur recipe. Pairs with `border-bottom:
1px solid var(--border)` for the separator line below. */
.page-header-glass {
background: var(--glass-surface-high);
backdrop-filter: blur(20px) saturate(180%);
box-shadow:
var(--rim-light-inner),
0 1px 0 var(--border);
}
/* Card Scanner Animations */
@keyframes pulse {
0%, 100% {
opacity: 1;
transform: scale(1);
}
50% {
opacity: 0.8;
transform: scale(1.02);
}
}
/* Default theme variables for light theme */
:root {
--bg-primary: var(--bg-primary-light);
--bg-secondary: var(--bg-secondary-light);
--bg-tertiary: var(--bg-tertiary-light);
--text-primary: var(--text-primary-light);
--text-secondary: var(--text-secondary-light);
--text-accent: var(--text-accent-light);
--border: var(--border-light);
--shadow: var(--shadow-light);
--gradient-primary: var(--gradient-primary-light);
--gradient-secondary: var(--gradient-secondary-light);
--accent-flame: var(--accent-flame-light);
--accent-ember: var(--accent-ember-light);
--accent-gold: var(--accent-gold-light);
--accent-wood: var(--accent-wood-light);
/* Legacy color mappings for compatibility */
--accent-blue: var(--accent-flame-light);
--accent-purple: var(--accent-ember-light);
--accent-pink: var(--accent-gold-light);
--input-bg: var(--input-bg-light);
--input-border: var(--input-border-light);
--input-text: var(--input-text-light);
--input-placeholder: var(--input-placeholder-light);
/* RGB color variables for backdrop-blur effects */
--bg-primary-rgb: 254, 252, 248;
--bg-secondary-rgb: 247, 243, 237;
--bg-tertiary-rgb: 240, 230, 214;
/* Corner-border light tokens (2026-06-04 refinement of the prior
two-light-source pass — operator feedback: "borders are
reflecting the color, not necessarily the drop shadows behind
the cards. In fact, you could probably reduce those box shadows
quite a bit. At least they shouldn't span the entire edge of
the card. Just a subtle bit in the corner.").
The prior `--edge-light-warm` / `--edge-light-cool` tokens were
complete box-shadow declarations with offsets that spanned the
entire bottom-left + top-right edges of every chip. They've
been retired. The replacement is a pair of plain RGBA colors
consumed by radial-gradient layers in the chip's BACKGROUND
(border-box-clipped) — see `.glass-panel` below — so the
warm/cool light response now reads as a corner-concentrated
highlight ON the chip's 1px border, not as an outer drop
shadow extending into the body gradient.
The `--chip-border-base` is a faint diagonal white tint that
paints under the corner gradients so the rest of the rim isn't
completely invisible (gives the chip a sensible edge even far
from either light source).
Two intensity tiers (2026-06-04 refinement, operator feedback
after the original tokens went out — "reduce the vibrancy of
the border gradients on the cards"):
1. `--corner-light-{warm,cool}` (full intensity) — used by
the floating chrome chips (sidebar nav, top header) where
the catch-light SHOULD be the primary visual cue that the
element is a distinct floating surface responding to the
background light sources. Consumed via inline `boxShadow`
in `components/Layout.js` and `components/ui/TopSearchBar.js`.
2. `--corner-light-{warm,cool}-subtle` — used by `.glass-panel`
and `.glass-panel-strong` (data cards: stat cards, deck
cards, list cards, modals, dropdowns). These surfaces are
numerous and tile densely; at full intensity the catch
lights compete with the chrome and overwhelm the page.
Roughly 55% of the full-intensity alpha. */
--corner-light-warm: rgba(255, 110, 0, 0.50);
--corner-light-cool: rgba(99, 102, 241, 0.38);
--corner-light-warm-subtle: rgba(255, 110, 0, 0.28);
--corner-light-cool-subtle: rgba(99, 102, 241, 0.20);
--chip-border-base: linear-gradient(
135deg,
rgba(255, 255, 255, 0.14) 0%,
rgba(255, 255, 255, 0.04) 100%
);
}
/* Dark theme variables */
[data-theme="dark"] {
--bg-primary: var(--bg-primary-dark);
--bg-secondary: var(--bg-secondary-dark);
--bg-tertiary: var(--bg-tertiary-dark);
--text-primary: var(--text-primary-dark);
--text-secondary: var(--text-secondary-dark);
--text-accent: var(--text-accent-dark);
--border: var(--border-dark);
--shadow: var(--shadow-dark);
--gradient-primary: var(--gradient-primary-dark);
--gradient-secondary: var(--gradient-secondary-dark);
--accent-flame: var(--accent-flame-dark);
--accent-ember: var(--accent-ember-dark);
--accent-gold: var(--accent-gold-dark);
--accent-wood: var(--accent-wood-dark);
/* Legacy color mappings for compatibility */
--accent-blue: var(--accent-flame-dark);
--accent-purple: var(--accent-ember-dark);
--accent-pink: var(--accent-gold-dark);
--input-bg: var(--input-bg-dark);
--input-border: var(--input-border-dark);
--input-text: var(--input-text-dark);
--input-placeholder: var(--input-placeholder-dark);
/* Dark-theme corner-border colors — alphas bumped so the warm
and cool catch lights read clearly against the deep substrate.
See :root for the full rationale on the corner-vs-drop-shadow
refinement. The base white border tint drops in alpha here
because the deep canvas absorbs whites more readily.
The `-subtle` variants (used by `.glass-panel*` data cards
per the operator's "reduce the vibrancy" feedback) sit at
roughly 55% of the full-intensity alpha — slightly higher
proportionally than the light theme because dark substrates
swallow chromatic content. */
--corner-light-warm: rgba(255, 130, 30, 0.68);
--corner-light-cool: rgba(139, 92, 246, 0.58);
--corner-light-warm-subtle: rgba(255, 130, 30, 0.38);
--corner-light-cool-subtle: rgba(139, 92, 246, 0.32);
--chip-border-base: linear-gradient(
135deg,
rgba(255, 255, 255, 0.10) 0%,
rgba(255, 255, 255, 0.02) 100%
);
}
/* Custom component styles - Fire-themed */
.btn-primary {
@apply font-bold py-3 px-6 rounded-2xl transition-all duration-300 shadow-lg hover:shadow-xl;
background: var(--gradient-primary);
color: white;
}
.btn-flame {
@apply font-bold py-2 px-4 rounded-lg transition-all duration-300 shadow-md hover:shadow-lg;
background-color: var(--accent-flame);
color: white;
}
.btn-flame:hover {
background-color: var(--accent-ember);
transform: translateY(-1px);
}
.btn-ember {
@apply font-bold py-2 px-4 rounded-lg transition-all duration-300 shadow-md hover:shadow-lg;
background-color: var(--accent-ember);
color: white;
}
.btn-ember:hover {
background: var(--gradient-primary);
transform: translateY(-1px);
}
.btn-gold {
@apply font-bold py-2 px-4 rounded-lg transition-all duration-300 shadow-md hover:shadow-lg;
background-color: var(--accent-gold);
color: white;
}
.btn-gold:hover {
background: var(--gradient-secondary);
transform: translateY(-1px);
}
.gradient-bg-fire {
background: var(--gradient-primary);
}
.gradient-bg-golden {
background: var(--gradient-secondary);
}
.gradient-bg-ember {
background: linear-gradient(135deg, #d84315 0%, #bf360c 100%);
}
/* Fire glow effects */
.fire-glow {
box-shadow: 0 0 20px rgba(255, 111, 0, 0.3);
}
.ember-glow {
box-shadow: 0 0 15px rgba(216, 67, 21, 0.4);
}
/* Navigation Accessibility Enhancements */
/* Nav-item hover/focus — third pass 2026-06-04. Operator feedback
after the spotlight landed (PR #110): "remove the shading around
the hover that makes it feel like it's floating" + "the gradient
is a little too bold." Two changes from the prior pass:
1) Dropped the base background-color tint on the host. With the
bg-tint gone, the item no longer reads as a "floating chip"
against the sidebar — just the radial spotlight remains,
which feels like light pooling under the cursor rather than
a state-color rectangle. Text color shift to --text-primary
stays as the secondary affordance (and for AA contrast on the
label).
2) Toned down the radial-gradient alphas. Light: 35%/18% → 22%/
10%. Dark: 40%/22% → 26%/12%. Same shape, gentler glow. */
/* Hover/focus also surfaces a subtle 1px ember border so the
hit-target of the chip is unambiguous even when the cursor is
near an edge (operator feedback after PR #111: the spotlight-only
hover hid the exact bounds of the interactive surface). The
border is 28% alpha — distinctly visible but lighter than the
active state's full-saturation ember border so the two states
remain readable side-by-side (hover < active). Implemented via
box-shadow inset rather than border: 1px to avoid the 1px layout
shift a real border would cause when toggling on hover. */
.nav-item:hover,
.nav-item-bottom:hover,
.nav-item-hover:hover,
.nav-item:focus-within,
.nav-item-bottom:focus-within,
.nav-item-hover:focus-within {
color: var(--text-primary) !important;
box-shadow: inset 0 0 0 1px rgba(216, 67, 21, 0.28) !important;
}
[data-theme="dark"] .nav-item:hover,
[data-theme="dark"] .nav-item-bottom:hover,
[data-theme="dark"] .nav-item-hover:hover,
[data-theme="dark"] .nav-item:focus-within,
[data-theme="dark"] .nav-item-bottom:focus-within,
[data-theme="dark"] .nav-item-hover:focus-within {
box-shadow: inset 0 0 0 1px rgba(255, 138, 80, 0.34) !important;
}
/* Mouse-tracking radial spotlight on every hoverable nav surface.
The radial-gradient is positioned via the --mouse-x / --mouse-y
CSS variables that Layout's delegated mousemove handler writes
onto the currently-hovered element. Default position (50% 50%)
ensures the spotlight is centered before the first mouse event
fires (e.g. on focus-within from keyboard nav). The ::before is
non-interactive (pointer-events: none) so it never blocks
clicks or steals focus from the underlying Link/Button. The
`position: relative` + `overflow: hidden` on the host ensure the
gradient clips to the rounded-2xl border-radius. */
.nav-item,
.nav-item-bottom,
.nav-item-hover {
position: relative;
overflow: hidden;
}
.nav-item::before,
.nav-item-bottom::before,
.nav-item-hover::before {
content: '';
position: absolute;
inset: 0;
border-radius: inherit;
background: radial-gradient(
circle 120px at var(--mouse-x, 50%) var(--mouse-y, 50%),
rgba(255, 140, 30, 0.22) 0%,
rgba(216, 67, 21, 0.10) 35%,
transparent 70%
);
opacity: 0;
pointer-events: none;
transition: opacity var(--motion-duration-quick) var(--motion-ease-out);
}
.nav-item:hover::before,
.nav-item-bottom:hover::before,
.nav-item-hover:hover::before,
.nav-item:focus-within::before,
.nav-item-bottom:focus-within::before,
.nav-item-hover:focus-within::before {
opacity: 1;
}
[data-theme="dark"] .nav-item::before,
[data-theme="dark"] .nav-item-bottom::before,
[data-theme="dark"] .nav-item-hover::before {
background: radial-gradient(
circle 120px at var(--mouse-x, 50%) var(--mouse-y, 50%),
rgba(255, 160, 70, 0.26) 0%,
rgba(255, 110, 0, 0.12) 35%,
transparent 70%
);
}
/* Ensure the existing nav-item content sits above the ::before
spotlight overlay. Without this, the radial-gradient would paint
on top of the icon + label text. */
.nav-item > *,
.nav-item-bottom > *,
.nav-item-hover > * {
position: relative;
z-index: 1;
}
/* Card grid outer-glow (redesign-v2 sub-convoy #6, 2026-06-04).
The operator's mockup shows TCG card thumbnails in the Featured
Collection grid with a soft warm glow emanating around each card,
suggesting "light cast onto the cards" — the hearth metaphor at
the card level. Applied to the outermost CardItem container so it
sits OUTSIDE the rarity-color glow (which lives on the card's
inner chrome). Single cheap box-shadow per card; safe on long
scroll lists where stacked filters would jank.
AGENTS.md performance budget: "card grids may NOT use glass on
every card item" — this is a single-axis shadow, not a backdrop-
filter, so it stays well under that budget. */
.card-grid-outer-glow {
box-shadow:
0 0 24px -4px rgba(255, 128, 0, 0.18),
0 4px 12px -2px rgba(0, 0, 0, 0.10);
transition: box-shadow var(--motion-duration-default)
var(--motion-ease-out);
}
.card-grid-outer-glow:hover {
box-shadow:
0 0 32px -2px rgba(255, 128, 0, 0.32),
0 8px 16px -4px rgba(0, 0, 0, 0.15);
}
[data-theme="dark"] .card-grid-outer-glow {
box-shadow:
0 0 28px -4px rgba(255, 110, 30, 0.28),
0 4px 12px -2px rgba(0, 0, 0, 0.40);
}
[data-theme="dark"] .card-grid-outer-glow:hover {
box-shadow:
0 0 40px -2px rgba(255, 110, 30, 0.50),
0 8px 16px -4px rgba(0, 0, 0, 0.50);
}
/* Sidebar active-pill — refined again 2026-06-04 (spotlight-hover
refinement, second pass). Operator: "give the background of an
active state a subtle gradient." Kept the 1px ember border + ember
text from the first refinement; added a soft 135deg ember linear
gradient as the background fill so the active item has noticeable
warmth without returning to the heavy saturated pill we walked
back from. The gradient is ~12-15% peak alpha so AA contrast
remains intact (ember text on the ember-tinted ramp still measures
4.5:1+ against the visible substrate).
Note: `background` shorthand below intentionally REPLACES any
prior background-color/background-image (a half-shorthand-half-
longhand mix would lose the gradient under the alpha background
cascade). */
.nav-item-active {
background: linear-gradient(
135deg,
rgba(216, 67, 21, 0.14) 0%,
rgba(255, 110, 0, 0.06) 100%
) !important;
color: var(--accent-ember) !important;
box-shadow: inset 0 0 0 1px var(--accent-ember) !important;
}
[data-theme="dark"] .nav-item-active {
background: linear-gradient(
135deg,
rgba(255, 138, 80, 0.18) 0%,
rgba(255, 110, 0, 0.08) 100%
) !important;
color: rgb(255, 138, 80) !important;
box-shadow: inset 0 0 0 1px rgb(255, 138, 80) !important;
}
/* Hover state — refined 2026-06-04. Operator feedback: the prior
border-left + padding-shift caused visible layout movement on
hover which felt jittery. Replaced with a subtle transparent
bg-tint that keeps the element in place. Same treatment for
focus-within so keyboard nav matches mouse. */
.nav-item-hover:hover,
.nav-item-hover:focus-within {
background-color: rgba(216, 67, 21, 0.08);
}
[data-theme="dark"] .nav-item-hover:hover,
[data-theme="dark"] .nav-item-hover:focus-within {
background-color: rgba(255, 138, 80, 0.10);
}
/* High contrast mode support */
@media (prefers-contrast: high) {
.nav-item:hover,
.nav-item-bottom:hover,
.nav-item:focus-within,
.nav-item-bottom:focus-within {
outline: 2px solid var(--accent-ember);
outline-offset: 2px;
}
}
/* Reduced motion support — site-wide sweep (added by motion-system-pass
convoy, 2026-06-03). Per WCAG SC 2.3.3, users who set the OS
"Reduce motion" preference get decorative animations collapsed to a
no-op while keeping the end-state of state transitions. The 0.01ms
value (vs `animation: none`) is the well-known idiom for preserving
end-state without flicker. Essential motion (e.g. loading spinners
indicating in-flight work) is kept opt-in by individual components
via the `motion-essential` class. */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
.motion-essential,
.motion-essential * {
animation-duration: revert !important;
animation-iteration-count: revert !important;
transition-duration: revert !important;
}
.nav-item,
.nav-item-bottom {
transition: none;
}
}
.btn-secondary {
@apply font-bold py-3 px-6 rounded-2xl transition-all duration-300 shadow-lg hover:shadow-xl;
background: var(--gradient-secondary);
color: white;
}
.input-field {
@apply w-full px-4 py-3 border rounded-2xl shadow-sm focus:outline-none focus:ring-2 focus:ring-offset-0 transition-all duration-200;
background-color: var(--input-bg);
border-color: var(--input-border);
color: var(--input-text);
}
.input-field::placeholder {
color: var(--input-placeholder);
}
/* .card retired by Brief 5 of unify-glass-panel-surfaces convoy
(PR sequence following PR #119). All 7 prior consumers migrated to
.glass-panel rounded-3xl. Use .glass-panel (subtle corner-light
tier, per PR #118) for content panels going forward; use
.glass-panel-strong for elevated chrome and floating popovers; use
.page-header-glass for full-bleed page-top strips. */
/* ============================================================
.glass-panel — canonical "content card" utility for body
surfaces on authenticated pages. The Liquid Glass recipe in
class form so pages can apply it without importing the
<GlassSurface> primitive for every flat container. Added by
glass-body-panels PR after PR #96 left admin/settings/dashboard
body cards on solid --bg-secondary.
Composition matches <GlassSurface tint="mid" rim="subtle"
elevation="ambient" blur="mid">. Always pair with rounded-*
from Tailwind (the class itself doesn't set border-radius
because consumers vary between rounded-xl and rounded-2xl).
============================================================ */
/* IMPORTANT — composing rim + elevation tokens correctly.
The --rim-light-outer / --rim-light-inner / --elevation-* tokens are
COMPLETE box-shadow declarations (each contains offset/spread/color or
the `inset` keyword), not raw color values. They are designed to be
*chained into a single box-shadow*, exactly the way <GlassSurface>'s
`boxShadow: shadowParts.join(', ')` composes them. Do NOT use
`border: 1px solid var(--rim-light-outer)` — that parses
`border-width` from the first token of the shadow string ("0"), which
yields a 0px border. And do NOT wrap --rim-light-inner in another
`inset 0 1px 0` prefix — the token already contains its own `inset`
keyword, so wrapping produces invalid syntax that the browser drops
the entire box-shadow declaration for. PR #98 had both mistakes,
which is why the panels in PR #97/#98 had neither visible border nor
drop shadow despite the backdrop-filter being correct.
Backdrop-filter quirks with Next.js 16's Lightning CSS (also relevant):
1) `backdrop-filter: blur(var(--X)) saturate(var(--Y))` is silently
stripped (var() inside function args breaks the optimizer). Use
LITERAL values here. Tokens stay in :root for the <GlassSurface>
JSX primitive which sets backdropFilter via inline style.
2) Writing both `backdrop-filter` AND `-webkit-backdrop-filter` with
identical values triggers Lightning CSS's buggy de-dup; it keeps
only the `-webkit-` form which modern browsers ignore. Write only
the unprefixed form; Lightning CSS's autoprefixer adds the prefix
per browserslist (ios_saf <18 still needs it). */
/* Glass panels — the canonical floating-chrome surface. 2026-06-04
corner-border pass (refines the prior two-light-source pass):
the warm + cool light response now paints on the chip's 1px
border using the multi-layer background + transparent-border
technique:
1. linear-gradient(surface, surface) padding-box — the chip's
translucent fill, clipped to the padding box so it doesn't
cover the 1px border ring.
2. radial-gradient(at 0% 100%, warm) border-box — warm corner
catch-light, anchored at the chip's bottom-left.
3. radial-gradient(at 100% 0%, cool) border-box — cool corner
catch-light, anchored at the chip's top-right.
4. --chip-border-base border-box — faint diagonal white tint
under the corner gradients so the rest of the rim isn't
invisible (gives the chip a sensible edge far from either
light source).
The `border: 1px solid transparent` is what exposes those
border-box-clipped gradient layers as the visible rim.
Drop-shadow stack is now just rim-light-inner + elevation —
the directional warm/cool outer glows are gone per operator
feedback ("reduce those box shadows quite a bit").
`.glass-panel*` uses the SUBTLE corner-light variants (about 55%
of the full-intensity alpha used by the floating chrome chips in
Layout / TopSearchBar). Data cards tile densely, so at full
intensity the catch lights compete with the chrome and overwhelm
the page (2026-06-04 operator feedback: "reduce the vibrancy of
the border gradients on the cards"). */
.glass-panel {
background:
linear-gradient(var(--glass-surface-mid), var(--glass-surface-mid))
padding-box,
radial-gradient(at 0% 100%, var(--corner-light-warm-subtle) 0%, transparent 42%)
border-box,
radial-gradient(at 100% 0%, var(--corner-light-cool-subtle) 0%, transparent 42%)
border-box,
var(--chip-border-base) border-box;
border: 1px solid transparent;
backdrop-filter: blur(12px) saturate(180%);
box-shadow:
var(--rim-light-inner),
var(--elevation-ambient);
}
.glass-panel-strong {
background:
linear-gradient(var(--glass-surface-high), var(--glass-surface-high))
padding-box,
radial-gradient(at 0% 100%, var(--corner-light-warm-subtle) 0%, transparent 42%)
border-box,
radial-gradient(at 100% 0%, var(--corner-light-cool-subtle) 0%, transparent 42%)
border-box,
var(--chip-border-base) border-box;
border: 1px solid transparent;
backdrop-filter: blur(20px) saturate(180%);
box-shadow:
var(--rim-light-inner),
var(--elevation-pronounced);
}
/* Gradient text effects — Deck Hearth warm palette only.
The pre-Deck-Hearth aliases (.glow-blue / .glow-purple / .glow-pink,
.gradient-text-blue / .gradient-text-purple, .gradient-bg-purple)
were removed by the finish-liquid-glass-design PR after sweeping
their last consumers to --accent-ember equivalents. */
.gradient-text-gold {
background: linear-gradient(135deg, #ffab40 0%, #ff6f00 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.gradient-text-flame {
background: linear-gradient(135deg, #ff6f00 0%, #d84315 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.gradient-text-ember {
background: linear-gradient(135deg, #d84315 0%, #bf360c 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
/* Theme toggle button */
.theme-toggle {
@apply p-2 rounded-2xl transition-all duration-300;
background: var(--bg-secondary);
color: var(--text-primary);
}
/* Header icons */
.header-icon {
@apply p-2 rounded-xl transition-all duration-200;
color: var(--text-secondary);
}
/* Logo styling */
.logo-container {
@apply rounded-2xl flex items-center justify-center transition-all duration-300;
background: var(--gradient-primary);
}
/* Custom scrollbar */
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background: var(--bg-secondary);
}
::-webkit-scrollbar-thumb {
background: var(--text-secondary);
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: var(--text-accent);
}
/* Search bar specific styling */
.search-bar {
@apply w-full px-4 py-3 border rounded-2xl shadow-sm focus:outline-none focus:ring-2 focus:ring-offset-0 transition-all duration-200;
background-color: var(--input-bg);
border-color: var(--input-border);
color: var(--input-text);
}
.search-bar::placeholder {
color: var(--input-placeholder);
}
/* Action buttons with proper gradients */
.action-btn-primary {
@apply font-bold py-3 px-6 rounded-2xl transition-all duration-300 shadow-lg hover:shadow-xl;
background: var(--gradient-primary);
color: white;
}
.action-btn-secondary {
@apply font-bold py-3 px-6 rounded-2xl transition-all duration-300 shadow-lg hover:shadow-xl;
background: var(--gradient-secondary);
color: white;
}
/* Particle Effects for High Rarity Cards */
@keyframes float {
0%, 100% {
transform: translateY(0px) translateX(0px);
opacity: 0.7;
}
25% {
transform: translateY(-8px) translateX(4px);
opacity: 1;
}
50% {
transform: translateY(-4px) translateX(-2px);
opacity: 0.8;
}
75% {
transform: translateY(-12px) translateX(6px);
opacity: 0.9;
}
}
@keyframes sparkle {
0%, 100% {
transform: scale(1) rotate(0deg);
opacity: 0.8;
}
25% {
transform: scale(1.5) rotate(90deg);
opacity: 1;
}
50% {
transform: scale(0.8) rotate(180deg);
opacity: 0.6;
}
75% {
transform: scale(1.2) rotate(270deg);
opacity: 0.9;
}
}
@keyframes aura {
0%, 100% {
opacity: 0.1;
transform: scale(1);
}
50% {
opacity: 0.2;
transform: scale(1.05);
}
}
@keyframes edgeFloat {
0%, 100% {
opacity: 0.7;
transform: translateY(0px) translateX(0px);
}
25% {
opacity: 1;
transform: translateY(-3px) translateX(2px);
}
50% {
opacity: 0.8;
transform: translateY(-1px) translateX(-1px);
}
75% {
opacity: 0.9;
transform: translateY(-4px) translateX(3px);
}
}
@keyframes edgeGlow {
0%, 100% {
opacity: 0.4;
transform: scale(1);
}
25% {
opacity: 0.8;
transform: scale(1.2);
}
50% {
opacity: 0.6;
transform: scale(0.8);
}
75% {
opacity: 0.9;
transform: scale(1.1);
}
}
/* Enhanced glow effects for mythic and enchanted cards */
.card-mythic-glow {
box-shadow:
0 0 20px rgba(255, 215, 0, 0.4),
0 0 40px rgba(255, 215, 0, 0.2),
0 0 60px rgba(255, 215, 0, 0.1);
}
.card-enchanted-glow {
box-shadow:
0 0 20px rgba(168, 85, 247, 0.4),
0 0 40px rgba(168, 85, 247, 0.2),
0 0 60px rgba(168, 85, 247, 0.1);
}
/* Card Hover Panel Styles */
.card-item-container {
position: relative;
}
.card-item-container:hover {
z-index: 50;
}
.card-item-container.selected {
z-index: 60;
}
/* Ensure proper layering during animations */
.card-grid-container {
position: relative;
z-index: 1;
}
/* Prevent text selection during card interactions */
.card-item-container * {
user-select: none;
}
/* Side panel specific styles */
.card-side-panel {
transform-origin: left center;
backdrop-filter: blur(8px);
}
/* Responsive adjustments for side panels */
@media (max-width: 1280px) {
.card-side-panel {
width: 16rem; /* w-64 */
}
}
@media (max-width: 1024px) {
.card-side-panel {
display: none; /* Hide panels on smaller screens */
}
}
/* Dark mode improvements */
@media (prefers-color-scheme: dark) {
.card-side-panel {
backdrop-filter: blur(8px) brightness(0.8);
}
}
/* Smooth panel transitions */
.card-panel-enter {
opacity: 0;
transform: translateX(8px);
}
.card-panel-enter-active {
opacity: 1;
transform: translateX(0);
transition: all 300ms ease-out;
}
/* Rarity Effects */
/* Mythic/Legendary - Golden glow */
.rarity-glow-mythic {
box-shadow:
0 0 25px rgba(251, 191, 36, 0.5),
0 0 50px rgba(251, 191, 36, 0.35),
0 0 75px rgba(251, 191, 36, 0.25);
}
.rarity-particles-mythic::before {
content: '';
position: absolute;
inset: 0;
background: radial-gradient(circle at 20% 30%, rgba(251, 191, 36, 0.3) 0%, transparent 50%),
radial-gradient(circle at 80% 70%, rgba(251, 191, 36, 0.2) 0%, transparent 50%),
radial-gradient(circle at 60% 20%, rgba(251, 191, 36, 0.25) 0%, transparent 50%);
animation: mythic-sparkle 4s ease-in-out infinite;
border-radius: inherit;
}
@keyframes mythic-sparkle {
0%, 100% { opacity: 0.3; }
50% { opacity: 0.7; }
}
/* Rare - Purple glow */
.rarity-glow-rare {
box-shadow:
0 0 20px rgba(168, 85, 247, 0.45),
0 0 40px rgba(168, 85, 247, 0.35),
0 0 60px rgba(168, 85, 247, 0.25);
}
.rarity-particles-rare::before {
content: '';
position: absolute;
inset: 0;
background: radial-gradient(circle at 30% 40%, rgba(168, 85, 247, 0.2) 0%, transparent 40%),
radial-gradient(circle at 70% 60%, rgba(168, 85, 247, 0.15) 0%, transparent 40%);
animation: rare-shimmer 3s ease-in-out infinite;
border-radius: inherit;
}
@keyframes rare-shimmer {
0%, 100% { opacity: 0.2; }
50% { opacity: 0.5; }
}
/* Uncommon - Blue glow */
.rarity-glow-uncommon {
box-shadow:
0 0 12px rgba(96, 165, 250, 0.35),
0 0 25px rgba(96, 165, 250, 0.25);
}
.rarity-particles-uncommon::before {
content: '';
position: absolute;
inset: 0;
background: radial-gradient(circle at 40% 30%, rgba(96, 165, 250, 0.15) 0%, transparent 30%);
animation: uncommon-twinkle 2.5s ease-in-out infinite;
border-radius: inherit;
}
@keyframes uncommon-twinkle {
0%, 100% { opacity: 0.1; }
50% { opacity: 0.3; }
}
/* Enchanted/Secret - Pink/Rainbow glow */
.rarity-glow-enchanted {
box-shadow:
0 0 28px rgba(244, 114, 182, 0.5),
0 0 55px rgba(168, 85, 247, 0.35),
0 0 80px rgba(59, 130, 246, 0.25);
}
.rarity-particles-enchanted::before {
content: '';
position: absolute;
inset: 0;
background:
radial-gradient(circle at 25% 25%, rgba(244, 114, 182, 0.3) 0%, transparent 40%),
radial-gradient(circle at 75% 75%, rgba(168, 85, 247, 0.2) 0%, transparent 40%),
radial-gradient(circle at 50% 50%, rgba(59, 130, 246, 0.25) 0%, transparent 40%);
animation: enchanted-rainbow 3s ease-in-out infinite;
border-radius: inherit;
}
@keyframes enchanted-rainbow {
0%, 100% {
opacity: 0.4;
transform: rotate(0deg);
}
33% {
opacity: 0.6;
transform: rotate(120deg);
}
66% {
opacity: 0.5;
transform: rotate(240deg);
}
}
/* Hover enhancement for rarity effects */
.card-item-container:hover .rarity-glow-mythic {
box-shadow:
0 0 30px rgba(251, 191, 36, 0.6),
0 0 60px rgba(251, 191, 36, 0.5),
0 0 90px rgba(251, 191, 36, 0.4);
}
.card-item-container:hover .rarity-glow-rare {
box-shadow:
0 0 25px rgba(168, 85, 247, 0.6),
0 0 50px rgba(168, 85, 247, 0.5),
0 0 75px rgba(168, 85, 247, 0.4);
}
.card-item-container:hover .rarity-glow-uncommon {
box-shadow:
0 0 20px rgba(96, 165, 250, 0.5),
0 0 40px rgba(96, 165, 250, 0.4);
}
.card-item-container:hover .rarity-glow-enchanted {
box-shadow:
0 0 35px rgba(244, 114, 182, 0.7),
0 0 70px rgba(244, 114, 182, 0.6),
0 0 105px rgba(244, 114, 182, 0.5);
}
/* Utility classes */
.flex-2 {
flex: 2;
}
.line-clamp-2 {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
/* Floating particle animation */
@keyframes float {
0%, 100% {
transform: translateY(0px) translateX(0px) scale(1);
opacity: 0.6;
}
25% {
transform: translateY(-20px) translateX(10px) scale(1.1);
opacity: 0.8;
}
50% {
transform: translateY(-10px) translateX(-15px) scale(0.9);
opacity: 1;
}
75% {
transform: translateY(-25px) translateX(5px) scale(1.05);
opacity: 0.7;
}
}
.animate-float {
animation: float 4s ease-in-out infinite;
}
/* Fire Glow Background Animation */
@keyframes fire-glow {
0%, 100% {
filter: hue-rotate(0deg) brightness(1) saturate(1);
transform: scale(1);
}
25% {
filter: hue-rotate(5deg) brightness(1.05) saturate(1.1);
transform: scale(1.02);
}
50% {
filter: hue-rotate(-3deg) brightness(0.98) saturate(1.05);
transform: scale(0.99);
}
75% {
filter: hue-rotate(8deg) brightness(1.03) saturate(1.08);
transform: scale(1.01);
}
}
.fire-glow-bg {
animation: fire-glow 12s ease-in-out infinite;
}
/* Ember Floating Animation */
@keyframes ember-float {
0% {
transform: translateY(0px) translateX(0px) scale(0.8);
opacity: 0;
}
10% {
opacity: 0.6;
}
20% {
transform: translateY(-30px) translateX(15px) scale(1);
opacity: 0.8;
}
40% {
transform: translateY(-60px) translateX(-10px) scale(0.9);
opacity: 1;
}
60% {
transform: translateY(-90px) translateX(20px) scale(1.1);
opacity: 0.7;
}
80% {
transform: translateY(-120px) translateX(-5px) scale(0.8);
opacity: 0.4;
}
100% {
transform: translateY(-150px) translateX(10px) scale(0.6);
opacity: 0;
}
}
.animate-ember-float {
animation: ember-float 10s linear infinite;
}
/* Mobile Navigation Styles */
.h-safe-area-inset-bottom {
height: env(safe-area-inset-bottom, 0px);
}
/* Mobile responsive adjustments */
@media (max-width: 768px) {
/* Ensure content doesn't get hidden behind mobile nav */
.mobile-content-padding {
padding-bottom: 80px; /* Space for mobile navigation */
}
/* Mobile navigation backdrop blur support */
@supports (backdrop-filter: blur(16px)) {
.mobile-nav-backdrop {
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
}
}
/* Fallback for browsers without backdrop-filter */
@supports not (backdrop-filter: blur(16px)) {
.mobile-nav-backdrop {
background-color: rgba(var(--bg-secondary-rgb), 0.95) !important;
}
}
}