99b3fb9e59
CI / test (push) Has been cancelled
Surface was --color-surface (same tone as the multiplied backdrop) so the card blended in. Switched to --color-surface-2 (lighter shade) + stronger shadow + inset highlight so the tile clearly floats above the harbor. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
295 lines
11 KiB
SCSS
295 lines
11 KiB
SCSS
// ─── Design v2 — SPA-specific component styles ──────────────────────────
|
|
// Tokens (CSS vars), font imports, base body bg, and Twig-template overrides
|
|
// live in /public/css/wevisto-design.css — loaded by both Twig and the SPA so
|
|
// changing a v2 color flows everywhere.
|
|
//
|
|
// This file holds only the SPA-specific compositions: side rail, frame card,
|
|
// library/settings inner styling, theme swatches.
|
|
|
|
[data-design="v2"] {
|
|
// ── TopNav: shown at ALL sizes in v2 (v1 hides it below 960px).
|
|
// Mobile/tablet → slim horizontal top bar (~52px) with brand only.
|
|
// Desktop → left side rail (overrides below).
|
|
.top-nav {
|
|
display: flex !important; // beat v1 scoped style's `display: none`
|
|
align-items: center;
|
|
gap: var(--space-3);
|
|
height: 52px;
|
|
padding: 0 var(--space-4);
|
|
padding-top: env(safe-area-inset-top);
|
|
background: color-mix(in srgb, var(--color-bg) 90%, transparent);
|
|
backdrop-filter: saturate(160%) blur(18px);
|
|
-webkit-backdrop-filter: saturate(160%) blur(18px);
|
|
border-bottom-color: var(--color-border);
|
|
|
|
&__wordmark { color: var(--color-text); font-family: var(--font-display-v2); font-weight: 400; }
|
|
&__sub { display: block !important; font-family: var(--font-accent-v2); }
|
|
|
|
// Hide the nav tabs at mobile/tablet — the bottom nav handles routing
|
|
&__tabs { display: none !important; }
|
|
|
|
&__tab {
|
|
color: var(--color-text-muted);
|
|
&:hover { background: var(--color-surface); color: var(--color-text); }
|
|
&--active { background: var(--color-surface); color: var(--brand-yellow); }
|
|
}
|
|
}
|
|
|
|
// Push main content below the mobile/tablet top bar
|
|
@media (max-width: 959px) {
|
|
.top-nav { position: sticky; top: 0; z-index: 30; }
|
|
main { padding-top: var(--space-3); }
|
|
}
|
|
|
|
@media (min-width: 960px) {
|
|
.top-nav {
|
|
position: fixed;
|
|
top: 0; left: 0; bottom: 0;
|
|
width: 240px;
|
|
height: auto;
|
|
flex-direction: column;
|
|
align-items: stretch;
|
|
gap: 0;
|
|
padding: 28px 18px 24px;
|
|
padding-top: calc(28px + env(safe-area-inset-top));
|
|
background: color-mix(in srgb, var(--color-bg) 96%, transparent);
|
|
border-right: 1px solid var(--color-border);
|
|
border-bottom: 0;
|
|
z-index: 50;
|
|
|
|
&__brand {
|
|
padding-bottom: 20px;
|
|
margin-bottom: 16px;
|
|
border-bottom: 1px solid var(--color-border);
|
|
align-items: flex-start;
|
|
}
|
|
&__mark {
|
|
width: 44px !important;
|
|
height: 44px !important;
|
|
border-radius: 10px !important;
|
|
}
|
|
&__wordmark { font-size: var(--text-xl); font-family: var(--font-display-v2); font-weight: 400; }
|
|
|
|
// !important needed because TopNav's scoped style hides these by default
|
|
// at the same specificity and cascades after the main bundle.
|
|
&__sub {
|
|
display: block !important;
|
|
font-family: var(--font-accent-v2);
|
|
}
|
|
|
|
&__tabs {
|
|
display: flex !important; // re-show at desktop (mobile/tablet had display:none)
|
|
flex: 0 0 auto !important;
|
|
flex-direction: column;
|
|
gap: 4px;
|
|
align-items: stretch;
|
|
margin-left: 0;
|
|
}
|
|
&__tab {
|
|
width: 100%;
|
|
justify-content: flex-start;
|
|
padding: 12px 14px;
|
|
gap: 12px;
|
|
border-radius: var(--radius-md);
|
|
|
|
&--active {
|
|
background: var(--color-surface);
|
|
box-shadow: inset 3px 0 0 var(--brand-yellow);
|
|
}
|
|
}
|
|
}
|
|
|
|
body { padding-left: 240px; }
|
|
}
|
|
|
|
.bottom-nav {
|
|
background: color-mix(in srgb, var(--color-bg) 95%, transparent);
|
|
border-top-color: var(--color-border);
|
|
.bottom-nav__tab--active { color: var(--brand-yellow); }
|
|
}
|
|
|
|
// ── Glass cards everywhere v1 uses --color-surface ─────────────────
|
|
.frame-card,
|
|
.home-view__empty-card,
|
|
.library__tile,
|
|
.settings__section-card {
|
|
background: var(--color-surface);
|
|
border-color: var(--color-border);
|
|
box-shadow:
|
|
0 1px 0 color-mix(in srgb, var(--color-text) 8%, transparent) inset,
|
|
0 24px 48px -16px rgba(0,0,0,0.6);
|
|
}
|
|
.frame-card__hero { background: var(--color-surface-2); }
|
|
.frame-card__name {
|
|
font-family: var(--font-display-v2);
|
|
font-weight: 400;
|
|
font-size: var(--text-xl);
|
|
}
|
|
|
|
// FrameCard settings cog: was white (95% opacity) — replace with dark glass + light icon
|
|
.frame-card__settings-btn {
|
|
background: rgba(8, 18, 30, 0.55) !important;
|
|
color: var(--color-text) !important;
|
|
border: 1px solid var(--color-border) !important;
|
|
box-shadow: 0 4px 12px -4px rgba(0,0,0,0.5) !important;
|
|
}
|
|
.frame-card__settings-btn:hover {
|
|
background: rgba(8, 18, 30, 0.75) !important;
|
|
}
|
|
|
|
// Orientation picker: active border in YELLOW (was theme primary)
|
|
.orientation-opt--active {
|
|
border-color: var(--brand-yellow) !important;
|
|
background: color-mix(in srgb, var(--brand-yellow) 12%, var(--color-surface)) !important;
|
|
}
|
|
.orientation-opt {
|
|
background: var(--color-surface);
|
|
border-color: var(--color-border);
|
|
color: var(--color-text);
|
|
}
|
|
.orientation-opt__label { color: var(--color-text); }
|
|
.orientation-opt__sub { color: var(--color-text-muted); }
|
|
.orientation-opt__diagram { color: var(--color-text-muted); }
|
|
.orientation-opt--active .orientation-opt__diagram { color: var(--brand-yellow); }
|
|
|
|
.home-view__empty-title { font-family: var(--font-display-v2); }
|
|
.library__add-btn { background: var(--color-primary); color: var(--color-primary-fg); }
|
|
|
|
// Library tile becomes a single connected card — photo and Manage button
|
|
// share the same surface, no gap between them. Manage gets a button-bar feel.
|
|
// Uses --color-surface-2 (lighter shade) so the card pops above the harbor
|
|
// multiplied backdrop that's already at --color-surface tone.
|
|
.library__item {
|
|
background: var(--color-surface-2);
|
|
border: 1px solid var(--color-border);
|
|
border-radius: var(--radius-md);
|
|
overflow: hidden;
|
|
gap: 0 !important;
|
|
box-shadow:
|
|
0 1px 0 color-mix(in srgb, var(--color-text) 10%, transparent) inset,
|
|
0 12px 28px -8px rgba(0,0,0,0.55);
|
|
backdrop-filter: saturate(160%) blur(20px);
|
|
-webkit-backdrop-filter: saturate(160%) blur(20px);
|
|
}
|
|
.library__thumb {
|
|
border-radius: 0 !important;
|
|
background: var(--color-surface-2);
|
|
}
|
|
.library__manage {
|
|
background: rgba(0,0,0,0.35) !important;
|
|
border-top: 1px solid var(--color-border);
|
|
border-radius: 0 !important;
|
|
padding: var(--space-3) var(--space-4) !important;
|
|
transition: background var(--duration-fast) var(--ease-out);
|
|
|
|
&:hover { background: rgba(0,0,0,0.5) !important; }
|
|
}
|
|
.library__manage-summary {
|
|
color: var(--color-text-muted);
|
|
font-size: var(--text-sm);
|
|
font-family: var(--font-family);
|
|
b { color: var(--color-text); }
|
|
}
|
|
.library__manage-action {
|
|
color: var(--brand-yellow) !important;
|
|
font-weight: 700;
|
|
font-size: var(--text-sm);
|
|
}
|
|
.library__manage-lock { color: var(--color-text-muted); }
|
|
|
|
// ── Settings polish ────────────────────────────────────────────────
|
|
.settings {
|
|
&__title { font-family: var(--font-display-v2); font-weight: 400; letter-spacing: 0.005em; }
|
|
&__section-title {
|
|
font-family: var(--font-mono-v2);
|
|
font-size: 11px;
|
|
letter-spacing: 0.28em;
|
|
color: var(--color-text-muted);
|
|
}
|
|
&__hint {
|
|
font-family: var(--font-accent-v2);
|
|
font-style: italic;
|
|
color: var(--color-text-muted);
|
|
}
|
|
&__install { color: var(--color-primary-fg); font-weight: 700; }
|
|
&__row,
|
|
&__action-link { border-color: var(--color-border); }
|
|
&__row-label { color: var(--color-text-muted); }
|
|
&__row-value,
|
|
&__action-link { color: var(--color-text); }
|
|
&__logout { color: var(--color-destructive); }
|
|
|
|
// Each section gets a glass card background so it reads against the harbor
|
|
&__section {
|
|
background: var(--color-surface);
|
|
border: 1px solid var(--color-border);
|
|
border-radius: var(--radius-lg);
|
|
padding: var(--space-5);
|
|
backdrop-filter: saturate(160%) blur(20px);
|
|
-webkit-backdrop-filter: saturate(160%) blur(20px);
|
|
box-shadow:
|
|
0 1px 0 color-mix(in srgb, var(--color-text) 8%, transparent) inset,
|
|
0 16px 32px -12px rgba(0,0,0,0.5);
|
|
// override the v1 margin-bottom which collapses between cards
|
|
margin-bottom: var(--space-4);
|
|
}
|
|
}
|
|
|
|
// Desktop: 2-column settings layout — first 4 sections in pairs,
|
|
// each section is a column-flex auto. Sections naturally pack in pairs.
|
|
@media (min-width: 960px) {
|
|
.settings {
|
|
display: grid;
|
|
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
|
gap: var(--space-5);
|
|
align-items: start;
|
|
|
|
&__title { grid-column: 1 / -1; }
|
|
&__section { margin-bottom: 0; }
|
|
}
|
|
}
|
|
|
|
.design-toggle__opt {
|
|
background: var(--color-surface);
|
|
border-color: var(--color-border);
|
|
color: var(--color-text);
|
|
&--active { border-color: var(--brand-yellow); background: var(--color-surface-2); }
|
|
}
|
|
.design-toggle__sub { color: var(--color-text-muted); }
|
|
|
|
// ── Theme swatches preview their dusk via the harbor.jpg ───────────
|
|
// `!important` needed because Vue's scoped style on SettingsView
|
|
// (.theme-swatch__preview[data-v-xxx] { background: var(--swatch-bg) })
|
|
// ties on specificity and cascades later. v2 is opt-in so overriding is OK.
|
|
.theme-swatch {
|
|
border-color: var(--color-border);
|
|
background: var(--color-surface) !important;
|
|
color: var(--color-text);
|
|
|
|
&--active { border-color: var(--brand-yellow); }
|
|
&__label { color: var(--color-text); }
|
|
|
|
&__preview {
|
|
background: transparent !important;
|
|
background-image: url('/build/assets/harbor.jpg') !important;
|
|
background-size: cover !important;
|
|
background-position: center !important;
|
|
position: relative;
|
|
overflow: hidden;
|
|
&::after {
|
|
content: '';
|
|
position: absolute; inset: 0;
|
|
mix-blend-mode: multiply;
|
|
}
|
|
}
|
|
}
|
|
.theme-swatch[aria-label*="Warm Craft" i] .theme-swatch__preview::after { background: rgba(60, 25, 8, 0.55); }
|
|
.theme-swatch[aria-label*="Ocean Dusk" i] .theme-swatch__preview::after { background: rgba(8, 22, 38, 0.55); }
|
|
.theme-swatch[aria-label*="Sage" i] .theme-swatch__preview::after { background: rgba(20, 40, 22, 0.55); }
|
|
.theme-swatch[aria-label*="Playful" i] .theme-swatch__preview::after { background: rgba(56, 16, 38, 0.55); }
|
|
.theme-swatch[aria-label*="Dusty" i] .theme-swatch__preview::after { background: rgba(40, 18, 56, 0.55); }
|
|
.theme-swatch[aria-label*="Honey" i] .theme-swatch__preview::after { background: rgba(48, 36, 14, 0.55); }
|
|
.theme-swatch__bar,
|
|
.theme-swatch__dot { display: none; }
|
|
}
|