Self-contained HTML/CSS mockups proposing the brand-as-surface direction: - Camogli harbor photo as the permanent backdrop on every authenticated view - Six user themes rebuilt as atmospheric "dusks" (tinted overlays + accents) instead of cream variants - Frosted-glass cards on top of the photo - Same type system (Marcellus / Cormorant Garamond italic / Nunito body) shared between login and in-app Includes: - login-cinematic.html: canonical pre-auth example with Ken-Burns + grain - spa/home.html, library.html, settings.html: in-app views with the new chrome - spa/_tokens.css + _chrome.css: dusk system and frosted-glass primitives - favicons/A-D: in-progress icon directions - README.md with serving instructions and the porting checklist Saved as a durable design artifact so the iteration survives /tmp wipes and can be referred back to when porting to Vue. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,183 @@
|
||||
/* Frosted-glass chrome — same vocabulary as the login.
|
||||
Every surface that holds content is a glass card over the harbor backdrop. */
|
||||
|
||||
/* ─── Top app bar — translucent dark band ────────────────────────────── */
|
||||
.app-bar {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 40;
|
||||
background: var(--glass-2);
|
||||
backdrop-filter: saturate(180%) blur(18px);
|
||||
-webkit-backdrop-filter: saturate(180%) blur(18px);
|
||||
border-bottom: 1px solid var(--glass-bord);
|
||||
padding: 12px 18px;
|
||||
padding-top: calc(12px + env(safe-area-inset-top));
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
.app-bar__mark {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
border-radius: 9px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 6px rgba(0,0,0,0.4);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.app-bar__mark img { width: 100%; height: 100%; display: block; }
|
||||
.app-bar__title-group { display: flex; flex-direction: column; }
|
||||
.app-bar__wordmark {
|
||||
font: 400 var(--text-lg)/1 var(--font-display);
|
||||
letter-spacing: 0.005em;
|
||||
color: var(--text);
|
||||
}
|
||||
.app-bar__wordmark .v { color: var(--brand-yellow); }
|
||||
.app-bar__sub {
|
||||
font: italic 400 13px/1 var(--font-accent);
|
||||
color: var(--text-muted);
|
||||
letter-spacing: 0.02em;
|
||||
margin-top: 4px;
|
||||
}
|
||||
.app-bar__spacer { flex: 1; }
|
||||
.app-bar__icon {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--text-muted);
|
||||
background: transparent;
|
||||
border: 0;
|
||||
border-radius: var(--radius-full);
|
||||
cursor: pointer;
|
||||
transition: background var(--duration-fast) var(--ease-out), color var(--duration-fast) var(--ease-out);
|
||||
}
|
||||
.app-bar__icon:hover { background: var(--glass); color: var(--text); }
|
||||
.app-bar__icon svg { width: 20px; height: 20px; stroke: currentColor; fill: none; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
|
||||
|
||||
/* ─── Glass surface mixin ──────────────────────────────────────────────── */
|
||||
.glass {
|
||||
background: var(--glass);
|
||||
backdrop-filter: saturate(160%) blur(20px);
|
||||
-webkit-backdrop-filter: saturate(160%) blur(20px);
|
||||
border: 1px solid var(--glass-bord);
|
||||
box-shadow:
|
||||
0 1px 0 rgba(255,255,255,0.06) inset,
|
||||
0 20px 40px -16px rgba(0,0,0,0.5);
|
||||
}
|
||||
|
||||
/* ─── Bottom nav — translucent dark band ─────────────────────────────── */
|
||||
.bottom-nav {
|
||||
position: fixed;
|
||||
bottom: 0; left: 0; right: 0;
|
||||
background: var(--glass-2);
|
||||
backdrop-filter: saturate(180%) blur(20px);
|
||||
-webkit-backdrop-filter: saturate(180%) blur(20px);
|
||||
border-top: 1px solid var(--glass-bord);
|
||||
display: flex;
|
||||
z-index: 50;
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
.bottom-nav__tab {
|
||||
flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
|
||||
gap: 2px; height: 64px; color: var(--text-muted);
|
||||
text-decoration: none; min-height: 44px;
|
||||
transition: color var(--duration-fast);
|
||||
}
|
||||
.bottom-nav__tab.active {
|
||||
color: var(--brand-yellow);
|
||||
}
|
||||
.bottom-nav__tab.active .label { color: var(--text); }
|
||||
.bottom-nav__tab svg { width: 24px; height: 24px; fill: none; stroke: currentColor; stroke-width: 2; }
|
||||
.bottom-nav__tab .label {
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--text-xs);
|
||||
letter-spacing: 0.16em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.main-scroll {
|
||||
padding-bottom: calc(64px + env(safe-area-inset-bottom) + 32px);
|
||||
min-height: 100dvh;
|
||||
}
|
||||
|
||||
/* ─── Brand signature ─────────────────────────────────────────────────── */
|
||||
.signature {
|
||||
margin-top: 32px;
|
||||
padding: 32px 0 16px;
|
||||
border-top: 1px solid var(--glass-bord);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
.signature__mark {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
opacity: 0.9;
|
||||
}
|
||||
.signature__mark img { width: 100%; height: 100%; display: block; }
|
||||
.signature__text {
|
||||
font: 400 14px/1.2 var(--font-display);
|
||||
letter-spacing: 0.32em;
|
||||
text-transform: uppercase;
|
||||
color: var(--text-muted);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
.signature__text .v-mark { color: var(--brand-yellow); }
|
||||
.signature__version {
|
||||
font: 400 italic 14px/1.3 var(--font-accent);
|
||||
letter-spacing: 0.02em;
|
||||
color: var(--text-muted);
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
/* ─── Theme switcher (mockup only) ─────────────────────────────────────── */
|
||||
.theme-switcher {
|
||||
position: fixed;
|
||||
bottom: 84px;
|
||||
right: 16px;
|
||||
z-index: 60;
|
||||
background: var(--glass-2);
|
||||
backdrop-filter: saturate(180%) blur(20px);
|
||||
border: 1px solid var(--glass-bord);
|
||||
border-radius: var(--radius-md);
|
||||
box-shadow: 0 12px 24px -8px rgba(0,0,0,0.5);
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
max-width: 220px;
|
||||
}
|
||||
.theme-switcher__label {
|
||||
font: var(--type-label);
|
||||
letter-spacing: 0.24em;
|
||||
text-transform: uppercase;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
.theme-switcher__chips {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px;
|
||||
}
|
||||
.theme-switcher__chip {
|
||||
width: 26px; height: 26px;
|
||||
border: 2px solid var(--glass-bord);
|
||||
border-radius: var(--radius-full);
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
transition: transform var(--duration-fast);
|
||||
}
|
||||
.theme-switcher__chip:hover { transform: scale(1.1); }
|
||||
.theme-switcher__chip.active { box-shadow: 0 0 0 2px var(--brand-yellow); }
|
||||
/* each chip shows that theme's accent over its bg-base */
|
||||
.theme-switcher__chip[data-theme="ocean-dusk"] { background: linear-gradient(135deg, #06121f 50%, #4e9fc8 50%); }
|
||||
.theme-switcher__chip[data-theme="amber-dusk"] { background: linear-gradient(135deg, #1a0d05 50%, #e89048 50%); }
|
||||
.theme-switcher__chip[data-theme="sage-dusk"] { background: linear-gradient(135deg, #081208 50%, #88c068 50%); }
|
||||
.theme-switcher__chip[data-theme="rose-dusk"] { background: linear-gradient(135deg, #1a060f 50%, #d878a0 50%); }
|
||||
.theme-switcher__chip[data-theme="mauve-dusk"] { background: linear-gradient(135deg, #100618 50%, #b890d8 50%); }
|
||||
.theme-switcher__chip[data-theme="honey-dusk"] { background: linear-gradient(135deg, #18120a 50%, #e8c050 50%); }
|
||||
@@ -0,0 +1,19 @@
|
||||
<div class="theme-switcher" role="region" aria-label="Theme switcher (mockup only)">
|
||||
<span class="theme-switcher__label">User-pref theme</span>
|
||||
<div class="theme-switcher__chips">
|
||||
<button class="theme-switcher__chip active" data-theme="warm-craft" title="warm-craft"></button>
|
||||
<button class="theme-switcher__chip" data-theme="ocean-dusk" title="ocean-dusk"></button>
|
||||
<button class="theme-switcher__chip" data-theme="sage-cream" title="sage-cream"></button>
|
||||
<button class="theme-switcher__chip" data-theme="playful-pop" title="playful-pop"></button>
|
||||
<button class="theme-switcher__chip" data-theme="dusty-mauve" title="dusty-mauve"></button>
|
||||
<button class="theme-switcher__chip" data-theme="honey-slate" title="honey-slate"></button>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
document.querySelectorAll('.theme-switcher__chip').forEach(chip => {
|
||||
chip.addEventListener('click', () => {
|
||||
document.documentElement.setAttribute('data-theme', chip.dataset.theme);
|
||||
document.querySelectorAll('.theme-switcher__chip').forEach(c => c.classList.toggle('active', c === chip));
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,164 @@
|
||||
/* Atmospheric design tokens — themes as dusks layered over the harbor photo.
|
||||
The whole app shares the login's surface vocabulary. */
|
||||
|
||||
:root {
|
||||
/* Type — same recipe as login */
|
||||
--font-family: 'Nunito', system-ui, sans-serif;
|
||||
--font-display: 'Marcellus', Georgia, serif;
|
||||
--font-accent: 'Cormorant Garamond', Georgia, serif;
|
||||
--font-mono: 'DM Mono', ui-monospace, monospace;
|
||||
|
||||
--text-xs: 11px; --text-sm: 13px; --text-base: 15px; --text-md: 17px;
|
||||
--text-lg: 20px; --text-xl: 24px; --text-2xl: 28px; --text-3xl: 36px;
|
||||
--space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px;
|
||||
--space-5: 20px; --space-6: 24px; --space-8: 32px;
|
||||
--radius-sm: 6px; --radius-md: 12px; --radius-lg: 20px; --radius-full: 9999px;
|
||||
--duration-fast: 150ms; --duration-base: 250ms;
|
||||
--ease-out: cubic-bezier(0, 0, 0.2, 1);
|
||||
|
||||
/* Brand layer — fixed regardless of theme. */
|
||||
--brand-yellow: #f0d000;
|
||||
--brand-yellow-soft: #c4a700;
|
||||
|
||||
/* Editorial recipes */
|
||||
--type-display-xl: 400 var(--text-3xl)/1.05 var(--font-display);
|
||||
--type-display-lg: 400 var(--text-2xl)/1.1 var(--font-display);
|
||||
--type-display-md: 400 var(--text-xl)/1.15 var(--font-display);
|
||||
--type-accent-md: 400 italic var(--text-md)/1.4 var(--font-accent);
|
||||
--type-label: 700 var(--text-xs)/1 var(--font-mono);
|
||||
}
|
||||
|
||||
/* ─── DUSKS ──────────────────────────────────────────────────────────────
|
||||
Each dusk is:
|
||||
--bg-base : the deep base color behind everything
|
||||
--bg-tint : an rgba multiplied over the harbor photo (the "filter")
|
||||
--glass : rgba background of cards (frosted, sits on photo)
|
||||
--glass-2 : a more opaque variant for nav strips
|
||||
--glass-bord : hairline border on glass surfaces
|
||||
--accent : theme accent (was --color-primary) — CTAs that aren't brand
|
||||
--accent-fg : text on accent
|
||||
--text : main text on glass (always light)
|
||||
--text-muted : muted text on glass
|
||||
|
||||
The yellow V brand constant survives across all dusks.
|
||||
*/
|
||||
|
||||
/* OCEAN DUSK — default, closest to login */
|
||||
[data-theme="ocean-dusk"], :root {
|
||||
--bg-base: #06121f;
|
||||
--bg-tint: rgba(8, 22, 38, 0.45);
|
||||
--glass: rgba(10, 28, 48, 0.55);
|
||||
--glass-2: rgba(8, 22, 38, 0.72);
|
||||
--glass-bord: rgba(180, 210, 235, 0.18);
|
||||
--accent: #4e9fc8;
|
||||
--accent-fg: #06121f;
|
||||
--text: #f4eed8;
|
||||
--text-muted: #b8c8d8;
|
||||
}
|
||||
|
||||
/* AMBER DUSK — successor to warm-craft */
|
||||
[data-theme="amber-dusk"] {
|
||||
--bg-base: #1a0d05;
|
||||
--bg-tint: rgba(60, 25, 8, 0.45);
|
||||
--glass: rgba(50, 22, 8, 0.55);
|
||||
--glass-2: rgba(35, 14, 5, 0.72);
|
||||
--glass-bord: rgba(230, 180, 130, 0.2);
|
||||
--accent: #e89048;
|
||||
--accent-fg: #1a0d05;
|
||||
--text: #faecd0;
|
||||
--text-muted: #d8b890;
|
||||
}
|
||||
|
||||
/* SAGE DUSK — successor to sage-cream */
|
||||
[data-theme="sage-dusk"] {
|
||||
--bg-base: #081208;
|
||||
--bg-tint: rgba(20, 40, 22, 0.45);
|
||||
--glass: rgba(18, 38, 22, 0.55);
|
||||
--glass-2: rgba(12, 26, 14, 0.72);
|
||||
--glass-bord: rgba(180, 220, 180, 0.18);
|
||||
--accent: #88c068;
|
||||
--accent-fg: #081208;
|
||||
--text: #ecf3e0;
|
||||
--text-muted: #a8c0a0;
|
||||
}
|
||||
|
||||
/* ROSE DUSK — warmer, classier replacement for playful-pop */
|
||||
[data-theme="rose-dusk"] {
|
||||
--bg-base: #1a060f;
|
||||
--bg-tint: rgba(56, 16, 38, 0.45);
|
||||
--glass: rgba(48, 14, 36, 0.55);
|
||||
--glass-2: rgba(32, 8, 22, 0.72);
|
||||
--glass-bord: rgba(230, 180, 200, 0.2);
|
||||
--accent: #d878a0;
|
||||
--accent-fg: #1a060f;
|
||||
--text: #f8e8ec;
|
||||
--text-muted: #c898ac;
|
||||
}
|
||||
|
||||
/* MAUVE DUSK — replaces dusty-mauve */
|
||||
[data-theme="mauve-dusk"] {
|
||||
--bg-base: #100618;
|
||||
--bg-tint: rgba(40, 18, 56, 0.45);
|
||||
--glass: rgba(36, 14, 50, 0.55);
|
||||
--glass-2: rgba(24, 10, 34, 0.72);
|
||||
--glass-bord: rgba(210, 190, 230, 0.18);
|
||||
--accent: #b890d8;
|
||||
--accent-fg: #100618;
|
||||
--text: #f0e8f8;
|
||||
--text-muted: #b8a8c8;
|
||||
}
|
||||
|
||||
/* HONEY DUSK — replaces honey-slate */
|
||||
[data-theme="honey-dusk"] {
|
||||
--bg-base: #18120a;
|
||||
--bg-tint: rgba(48, 36, 14, 0.45);
|
||||
--glass: rgba(42, 32, 12, 0.55);
|
||||
--glass-2: rgba(28, 22, 8, 0.72);
|
||||
--glass-bord: rgba(232, 200, 130, 0.22);
|
||||
--accent: #e8c050;
|
||||
--accent-fg: #18120a;
|
||||
--text: #faf0d8;
|
||||
--text-muted: #c8b888;
|
||||
}
|
||||
|
||||
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
html, body { background: var(--bg-base); color: var(--text); }
|
||||
body {
|
||||
font-family: var(--font-family);
|
||||
font-size: var(--text-base);
|
||||
line-height: 1.5;
|
||||
min-height: 100dvh;
|
||||
position: relative;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
/* ─── PERMANENT ATMOSPHERIC BACKDROP ──────────────────────────────────── */
|
||||
/* harbor photo fixed under everything */
|
||||
body::before {
|
||||
content: '';
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: url('../assets/harbor.jpg') center/cover no-repeat;
|
||||
filter: brightness(0.6) saturate(0.85);
|
||||
z-index: -3;
|
||||
}
|
||||
/* theme tint multiplied over photo */
|
||||
body::after {
|
||||
content: '';
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: var(--bg-tint);
|
||||
mix-blend-mode: multiply;
|
||||
z-index: -2;
|
||||
pointer-events: none;
|
||||
}
|
||||
/* global vignette + film grain via one extra layer */
|
||||
.atmosphere {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
z-index: -1;
|
||||
background:
|
||||
radial-gradient(ellipse 80% 70% at 50% 45%, transparent 0%, rgba(0,0,0,0.35) 70%, rgba(0,0,0,0.65) 100%),
|
||||
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='320' height='320'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' seed='5'/><feColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.1 0'/></filter><rect width='320' height='320' filter='url(%23n)'/></svg>");
|
||||
}
|
||||
@@ -0,0 +1,310 @@
|
||||
<!doctype html>
|
||||
<html lang="en" data-theme="ocean-dusk">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<title>Home — WeVisto</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700;900&family=Marcellus&family=Cormorant+Garamond:ital,wght@1,400&family=DM+Mono:wght@400;500&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="_tokens.css">
|
||||
<link rel="stylesheet" href="_chrome.css">
|
||||
<style>
|
||||
/* ─── hero — editorial moment, sits directly on the photo ──────────── */
|
||||
.hero {
|
||||
padding: var(--space-6) var(--space-5) var(--space-5);
|
||||
position: relative;
|
||||
}
|
||||
.hero__plate {
|
||||
font: var(--type-label);
|
||||
letter-spacing: 0.32em;
|
||||
text-transform: uppercase;
|
||||
color: var(--text-muted);
|
||||
margin-bottom: var(--space-3);
|
||||
display: flex; align-items: center; gap: 10px;
|
||||
}
|
||||
.hero__plate .roman { color: var(--brand-yellow); font-family: var(--font-display); font-size: var(--text-md); }
|
||||
.hero__plate .sep { width: 24px; height: 1px; background: var(--glass-bord); }
|
||||
.hero__greeting {
|
||||
font: var(--type-display-lg);
|
||||
color: var(--text);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.hero__greeting em {
|
||||
font-family: var(--font-accent);
|
||||
font-style: italic;
|
||||
color: var(--brand-yellow);
|
||||
}
|
||||
.hero__sub {
|
||||
font: var(--type-accent-md);
|
||||
color: var(--text-muted);
|
||||
line-height: 1.5;
|
||||
max-width: 38ch;
|
||||
}
|
||||
.hero__sub strong { color: var(--text); font-style: normal; font-family: var(--font-display); font-weight: 400; }
|
||||
.hero__rule {
|
||||
margin-top: var(--space-4);
|
||||
width: 80px; height: 1px;
|
||||
background: linear-gradient(90deg, var(--brand-yellow), transparent);
|
||||
}
|
||||
|
||||
/* ─── frame card — frosted glass, the user's photo is the inner content ── */
|
||||
.frame-card {
|
||||
margin: var(--space-5);
|
||||
border-radius: var(--radius-lg);
|
||||
overflow: hidden;
|
||||
/* uses .glass class for the frost effect */
|
||||
}
|
||||
.frame-card__hero {
|
||||
aspect-ratio: 4/3;
|
||||
background-image: url('../assets/harbor.jpg');
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
position: relative;
|
||||
/* the user's frame photo — keep at full saturation (it's user content, not brand backdrop) */
|
||||
}
|
||||
.frame-card__status {
|
||||
position: absolute;
|
||||
top: 14px; left: 14px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
background: rgba(8, 18, 30, 0.7);
|
||||
backdrop-filter: blur(8px);
|
||||
padding: 6px 12px;
|
||||
border-radius: var(--radius-full);
|
||||
font: var(--type-label);
|
||||
color: var(--text);
|
||||
letter-spacing: 0.22em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.frame-card__status .dot {
|
||||
width: 7px; height: 7px;
|
||||
background: #6cd498;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 0 0 3px rgba(108, 212, 152, 0.25);
|
||||
}
|
||||
.frame-card__plate {
|
||||
position: absolute;
|
||||
bottom: 14px; left: 14px;
|
||||
font: var(--type-label);
|
||||
background: rgba(8, 18, 30, 0.7);
|
||||
color: var(--text);
|
||||
padding: 5px 10px;
|
||||
letter-spacing: 0.28em;
|
||||
text-transform: uppercase;
|
||||
backdrop-filter: blur(6px);
|
||||
}
|
||||
.frame-card__body { padding: var(--space-5) var(--space-5) var(--space-4); }
|
||||
.frame-card__name {
|
||||
font: var(--type-display-md);
|
||||
color: var(--text);
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.frame-card__meta {
|
||||
font: italic 400 15px/1.4 var(--font-accent);
|
||||
color: var(--text-muted);
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
.frame-card__meta .sep { margin: 0 8px; opacity: 0.4; }
|
||||
.frame-card__schedule {
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
border: 1px solid var(--glass-bord);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--space-4);
|
||||
margin-bottom: var(--space-4);
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: var(--space-3);
|
||||
font-size: var(--text-sm);
|
||||
line-height: 1.5;
|
||||
}
|
||||
.frame-card__schedule svg {
|
||||
width: 18px; height: 18px;
|
||||
stroke: var(--brand-yellow);
|
||||
fill: none;
|
||||
stroke-width: 2;
|
||||
flex-shrink: 0;
|
||||
margin-top: 2px;
|
||||
}
|
||||
.frame-card__schedule strong { font-family: var(--font-display); font-size: var(--text-base); font-weight: 400; color: var(--text); display: block; margin-bottom: 2px; }
|
||||
.frame-card__schedule span { color: var(--text-muted); }
|
||||
.frame-card__actions { display: flex; gap: var(--space-3); }
|
||||
.btn {
|
||||
flex: 1;
|
||||
padding: 14px 20px;
|
||||
font-family: var(--font-family);
|
||||
font-size: var(--text-base);
|
||||
font-weight: 700;
|
||||
border-radius: var(--radius-md);
|
||||
border: 1px solid var(--glass-bord);
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
color: var(--text);
|
||||
cursor: pointer;
|
||||
transition: background var(--duration-fast);
|
||||
display: inline-flex; align-items: center; justify-content: center; gap: 8px;
|
||||
}
|
||||
.btn:hover { background: rgba(255, 255, 255, 0.12); }
|
||||
.btn--primary {
|
||||
background: var(--accent);
|
||||
color: var(--accent-fg);
|
||||
border-color: var(--accent);
|
||||
font-weight: 700;
|
||||
}
|
||||
.btn--primary:hover { filter: brightness(1.08); }
|
||||
.btn svg { width: 16px; height: 16px; stroke: currentColor; fill: none; stroke-width: 2; }
|
||||
|
||||
/* ─── upcoming photos strip — quiet teaser of what's queued ─────────── */
|
||||
.upcoming {
|
||||
margin: var(--space-5);
|
||||
padding: var(--space-5);
|
||||
border-radius: var(--radius-lg);
|
||||
}
|
||||
.upcoming__head {
|
||||
display: flex; align-items: baseline; justify-content: space-between;
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
.upcoming__title {
|
||||
font: var(--type-display-md);
|
||||
color: var(--text);
|
||||
}
|
||||
.upcoming__hint {
|
||||
font: var(--type-accent-md);
|
||||
color: var(--text-muted);
|
||||
}
|
||||
.upcoming__row {
|
||||
display: flex; gap: var(--space-3); overflow-x: auto; padding-bottom: 4px;
|
||||
}
|
||||
.upcoming__row::-webkit-scrollbar { display: none; }
|
||||
.upcoming__row { scrollbar-width: none; }
|
||||
.thumb {
|
||||
flex-shrink: 0;
|
||||
width: 92px; height: 92px;
|
||||
border-radius: var(--radius-md);
|
||||
overflow: hidden;
|
||||
background: rgba(0,0,0,0.3);
|
||||
position: relative;
|
||||
border: 1px solid var(--glass-bord);
|
||||
}
|
||||
.thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
|
||||
.thumb .when {
|
||||
position: absolute;
|
||||
bottom: 4px; left: 4px;
|
||||
font: var(--type-label);
|
||||
background: rgba(0,0,0,0.7);
|
||||
color: var(--text);
|
||||
padding: 2px 6px;
|
||||
letter-spacing: 0.18em;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="atmosphere"></div>
|
||||
|
||||
<header class="app-bar">
|
||||
<div class="app-bar__mark"><img src="../assets/mark-photo-64.png" alt=""></div>
|
||||
<div class="app-bar__title-group">
|
||||
<div class="app-bar__wordmark">We<span class="v">V</span>isto</div>
|
||||
<div class="app-bar__sub">— Margaret's frame</div>
|
||||
</div>
|
||||
<div class="app-bar__spacer"></div>
|
||||
<button class="app-bar__icon" aria-label="Notifications">
|
||||
<svg viewBox="0 0 24 24"><path d="M18 8a6 6 0 0 0-12 0c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/></svg>
|
||||
</button>
|
||||
</header>
|
||||
|
||||
<main class="main-scroll">
|
||||
|
||||
<section class="hero">
|
||||
<div class="hero__plate"><span class="roman">I.</span><span class="sep"></span><span>Plate · today</span></div>
|
||||
<h1 class="hero__greeting">Good morning, <em>Alice.</em></h1>
|
||||
<p class="hero__sub">Margaret's frame is in sync. The next photograph will arrive at <strong>7:00 AM</strong>, quietly, on its own.</p>
|
||||
<div class="hero__rule"></div>
|
||||
</section>
|
||||
|
||||
<article class="frame-card glass">
|
||||
<div class="frame-card__hero">
|
||||
<div class="frame-card__status">
|
||||
<span class="dot"></span><span>Synced 12 min ago</span>
|
||||
</div>
|
||||
<div class="frame-card__plate">Plate XII</div>
|
||||
</div>
|
||||
<div class="frame-card__body">
|
||||
<h2 class="frame-card__name">Margaret's frame</h2>
|
||||
<p class="frame-card__meta">7.3″ landscape <span class="sep">·</span> Camden, Maine <span class="sep">·</span> est. May 2026</p>
|
||||
|
||||
<div class="frame-card__schedule">
|
||||
<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>
|
||||
<div>
|
||||
<strong>Next photograph at 7:00 AM</strong>
|
||||
<span>then again at 12:00 PM and 6:00 PM</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="frame-card__actions">
|
||||
<button class="btn btn--primary">
|
||||
<svg viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
|
||||
Add photograph
|
||||
</button>
|
||||
<button class="btn">
|
||||
<svg viewBox="0 0 24 24"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>
|
||||
Settings
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<section class="upcoming glass">
|
||||
<div class="upcoming__head">
|
||||
<h3 class="upcoming__title">Up next</h3>
|
||||
<span class="upcoming__hint">— in the library queue</span>
|
||||
</div>
|
||||
<div class="upcoming__row">
|
||||
<div class="thumb"><img src="../assets/harbor.jpg" alt=""><span class="when">7am</span></div>
|
||||
<div class="thumb"><img src="../assets/harbor.jpg" alt="" style="filter: hue-rotate(40deg);"><span class="when">noon</span></div>
|
||||
<div class="thumb"><img src="../assets/harbor.jpg" alt="" style="filter: hue-rotate(-30deg) saturate(1.2);"><span class="when">6pm</span></div>
|
||||
<div class="thumb"><img src="../assets/harbor.jpg" alt="" style="filter: brightness(0.85);"><span class="when">tmrw</span></div>
|
||||
<div class="thumb"><img src="../assets/harbor.jpg" alt="" style="filter: sepia(0.4);"><span class="when">+5</span></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
<nav class="bottom-nav">
|
||||
<a class="bottom-nav__tab active" href="home.html">
|
||||
<svg viewBox="0 0 24 24"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9,22 9,12 15,12 15,22"/></svg>
|
||||
<span class="label">Home</span>
|
||||
</a>
|
||||
<a class="bottom-nav__tab" href="library.html">
|
||||
<svg viewBox="0 0 24 24"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/></svg>
|
||||
<span class="label">Library</span>
|
||||
</a>
|
||||
<a class="bottom-nav__tab" href="settings.html">
|
||||
<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>
|
||||
<span class="label">Settings</span>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
<div class="theme-switcher" role="region" aria-label="Theme switcher (mockup only)">
|
||||
<span class="theme-switcher__label">Dusk</span>
|
||||
<div class="theme-switcher__chips">
|
||||
<button class="theme-switcher__chip active" data-theme="ocean-dusk" title="Ocean dusk"></button>
|
||||
<button class="theme-switcher__chip" data-theme="amber-dusk" title="Amber dusk"></button>
|
||||
<button class="theme-switcher__chip" data-theme="sage-dusk" title="Sage dusk"></button>
|
||||
<button class="theme-switcher__chip" data-theme="rose-dusk" title="Rose dusk"></button>
|
||||
<button class="theme-switcher__chip" data-theme="mauve-dusk" title="Mauve dusk"></button>
|
||||
<button class="theme-switcher__chip" data-theme="honey-dusk" title="Honey dusk"></button>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
document.querySelectorAll('.theme-switcher__chip').forEach(chip => {
|
||||
chip.addEventListener('click', () => {
|
||||
document.documentElement.setAttribute('data-theme', chip.dataset.theme);
|
||||
document.querySelectorAll('.theme-switcher__chip').forEach(c => c.classList.toggle('active', c === chip));
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,249 @@
|
||||
<!doctype html>
|
||||
<html lang="en" data-theme="ocean-dusk">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<title>Library — WeVisto</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700;900&family=Marcellus&family=Cormorant+Garamond:ital,wght@1,400&family=DM+Mono:wght@400;500&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="_tokens.css">
|
||||
<link rel="stylesheet" href="_chrome.css">
|
||||
<style>
|
||||
.library-empty {
|
||||
padding: 56px 24px 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
}
|
||||
.library-empty__plate {
|
||||
font: var(--type-label);
|
||||
letter-spacing: 0.32em;
|
||||
text-transform: uppercase;
|
||||
color: var(--text-muted);
|
||||
margin-bottom: var(--space-5);
|
||||
display: flex; align-items: center; gap: 10px;
|
||||
}
|
||||
.library-empty__plate .roman { color: var(--brand-yellow); font-family: var(--font-display); font-size: var(--text-md); }
|
||||
.library-empty__plate .sep { width: 24px; height: 1px; background: var(--glass-bord); }
|
||||
|
||||
.library-empty__halo { position: relative; margin-bottom: var(--space-5); }
|
||||
.library-empty__halo::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%; left: 50%;
|
||||
width: 240px; height: 240px;
|
||||
transform: translate(-50%, -50%);
|
||||
background: radial-gradient(circle, color-mix(in srgb, var(--brand-yellow) 25%, transparent), transparent 65%);
|
||||
border-radius: 50%;
|
||||
pointer-events: none;
|
||||
z-index: -1;
|
||||
}
|
||||
.library-empty__mark {
|
||||
width: 112px;
|
||||
height: 112px;
|
||||
border-radius: 24px;
|
||||
overflow: hidden;
|
||||
box-shadow:
|
||||
0 1px 0 rgba(255,255,255,0.18) inset,
|
||||
0 20px 40px -10px rgba(0,0,0,0.6),
|
||||
0 8px 20px -6px rgba(0,0,0,0.4);
|
||||
}
|
||||
.library-empty__mark img { width: 100%; height: 100%; display: block; }
|
||||
|
||||
.library-empty__title {
|
||||
font: var(--type-display-xl);
|
||||
color: var(--text);
|
||||
margin-bottom: var(--space-2);
|
||||
text-shadow: 0 2px 10px rgba(0,0,0,0.3);
|
||||
}
|
||||
.library-empty__title em {
|
||||
font-family: var(--font-accent);
|
||||
font-style: italic;
|
||||
color: var(--brand-yellow);
|
||||
font-weight: 400;
|
||||
}
|
||||
.library-empty__sub {
|
||||
font: italic 400 18px/1.55 var(--font-accent);
|
||||
color: var(--text-muted);
|
||||
max-width: 36ch;
|
||||
margin-bottom: var(--space-6);
|
||||
}
|
||||
.library-empty__rule {
|
||||
width: 96px; height: 1px;
|
||||
background: linear-gradient(90deg, transparent, var(--brand-yellow), transparent);
|
||||
margin: 0 auto var(--space-6);
|
||||
}
|
||||
.library-empty__cta {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
background: var(--accent);
|
||||
color: var(--accent-fg);
|
||||
padding: 14px 28px;
|
||||
border-radius: var(--radius-full);
|
||||
font-family: var(--font-family);
|
||||
font-weight: 700;
|
||||
font-size: var(--text-base);
|
||||
text-decoration: none;
|
||||
box-shadow: 0 8px 22px -4px color-mix(in srgb, var(--accent) 50%, transparent);
|
||||
transition: transform var(--duration-fast) var(--ease-out), filter var(--duration-fast) var(--ease-out);
|
||||
}
|
||||
.library-empty__cta:hover { transform: translateY(-1px); filter: brightness(1.08); }
|
||||
.library-empty__cta svg { width: 18px; height: 18px; stroke: currentColor; fill: none; stroke-width: 2.5; stroke-linecap: round; }
|
||||
.library-empty__or {
|
||||
margin-top: var(--space-5);
|
||||
font: italic 400 var(--text-md)/1.4 var(--font-accent);
|
||||
color: var(--text-muted);
|
||||
}
|
||||
.library-empty__or a {
|
||||
color: var(--text);
|
||||
border-bottom: 1px solid var(--glass-bord);
|
||||
text-decoration: none;
|
||||
padding-bottom: 1px;
|
||||
}
|
||||
|
||||
/* steps card — frosted */
|
||||
.intro-steps {
|
||||
margin: 48px var(--space-5) 0;
|
||||
padding: var(--space-5) var(--space-5) var(--space-6);
|
||||
border-radius: var(--radius-lg);
|
||||
position: relative;
|
||||
}
|
||||
.intro-steps__rule {
|
||||
position: absolute;
|
||||
top: -1px; left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 60px; height: 1px;
|
||||
background: var(--brand-yellow);
|
||||
}
|
||||
.intro-steps__title {
|
||||
font: var(--type-display-md);
|
||||
color: var(--text);
|
||||
text-align: center;
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
.intro-steps__title .v-mark { color: var(--brand-yellow); }
|
||||
.intro-steps__sub {
|
||||
font: var(--type-accent-md);
|
||||
color: var(--text-muted);
|
||||
text-align: center;
|
||||
margin-bottom: var(--space-5);
|
||||
}
|
||||
.intro-steps__list { display: flex; gap: var(--space-3); }
|
||||
.step { flex: 1; text-align: center; padding: var(--space-3); }
|
||||
.step__num {
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--text-2xl);
|
||||
color: var(--brand-yellow);
|
||||
line-height: 1;
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
.step__label {
|
||||
font-size: var(--text-xs);
|
||||
color: var(--text-muted);
|
||||
line-height: 1.4;
|
||||
}
|
||||
.step__label strong {
|
||||
font-family: var(--font-display);
|
||||
font-weight: 400;
|
||||
font-size: var(--text-sm);
|
||||
color: var(--text);
|
||||
display: block;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.signature { margin: 64px var(--space-5) 0; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="atmosphere"></div>
|
||||
|
||||
<header class="app-bar">
|
||||
<div class="app-bar__mark"><img src="../assets/mark-photo-64.png" alt=""></div>
|
||||
<div class="app-bar__title-group">
|
||||
<div class="app-bar__wordmark">We<span class="v">V</span>isto</div>
|
||||
<div class="app-bar__sub">— the library</div>
|
||||
</div>
|
||||
<div class="app-bar__spacer"></div>
|
||||
<button class="app-bar__icon" aria-label="Filter">
|
||||
<svg viewBox="0 0 24 24"><polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"/></svg>
|
||||
</button>
|
||||
</header>
|
||||
|
||||
<main class="main-scroll">
|
||||
|
||||
<div class="library-empty">
|
||||
<div class="library-empty__plate"><span class="roman">○</span><span class="sep"></span><span>Accession no. 001</span></div>
|
||||
<div class="library-empty__halo">
|
||||
<div class="library-empty__mark"><img src="../assets/mark-photo.png" alt=""></div>
|
||||
</div>
|
||||
<h1 class="library-empty__title">A library, <em>waiting.</em></h1>
|
||||
<p class="library-empty__sub">Photographs you upload will rotate through Margaret's frame, one at a time. We'll hold them here until the frame is ready.</p>
|
||||
<div class="library-empty__rule"></div>
|
||||
<a class="library-empty__cta" href="#">
|
||||
<svg viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
|
||||
Upload the first photograph
|
||||
</a>
|
||||
<div class="library-empty__or">— or <a href="#">invite someone else</a> to send one</div>
|
||||
</div>
|
||||
|
||||
<div class="intro-steps glass">
|
||||
<div class="intro-steps__rule"></div>
|
||||
<div class="intro-steps__title">How <span class="v-mark">V</span>isto works, briefly</div>
|
||||
<div class="intro-steps__sub">— three steps, then forever</div>
|
||||
<div class="intro-steps__list">
|
||||
<div class="step"><div class="step__num">I.</div><div class="step__label"><strong>You upload</strong>family photos</div></div>
|
||||
<div class="step"><div class="step__num">II.</div><div class="step__label"><strong>We hold</strong>them in the library</div></div>
|
||||
<div class="step"><div class="step__num">III.</div><div class="step__label"><strong>Frame picks</strong>one each interval</div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="signature">
|
||||
<div class="signature__mark"><img src="../assets/mark-photo-64.png" alt=""></div>
|
||||
<div class="signature__text">WeVisto <span class="v-mark">·</span> a frame, gifted</div>
|
||||
<div class="signature__version">Edizione I · MMXXVI</div>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
||||
<nav class="bottom-nav">
|
||||
<a class="bottom-nav__tab" href="home.html">
|
||||
<svg viewBox="0 0 24 24"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9,22 9,12 15,12 15,22"/></svg>
|
||||
<span class="label">Home</span>
|
||||
</a>
|
||||
<a class="bottom-nav__tab active" href="library.html">
|
||||
<svg viewBox="0 0 24 24"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/></svg>
|
||||
<span class="label">Library</span>
|
||||
</a>
|
||||
<a class="bottom-nav__tab" href="settings.html">
|
||||
<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>
|
||||
<span class="label">Settings</span>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
<div class="theme-switcher" role="region" aria-label="Theme switcher (mockup only)">
|
||||
<span class="theme-switcher__label">Dusk</span>
|
||||
<div class="theme-switcher__chips">
|
||||
<button class="theme-switcher__chip active" data-theme="ocean-dusk" title="Ocean dusk"></button>
|
||||
<button class="theme-switcher__chip" data-theme="amber-dusk" title="Amber dusk"></button>
|
||||
<button class="theme-switcher__chip" data-theme="sage-dusk" title="Sage dusk"></button>
|
||||
<button class="theme-switcher__chip" data-theme="rose-dusk" title="Rose dusk"></button>
|
||||
<button class="theme-switcher__chip" data-theme="mauve-dusk" title="Mauve dusk"></button>
|
||||
<button class="theme-switcher__chip" data-theme="honey-dusk" title="Honey dusk"></button>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
document.querySelectorAll('.theme-switcher__chip').forEach(chip => {
|
||||
chip.addEventListener('click', () => {
|
||||
document.documentElement.setAttribute('data-theme', chip.dataset.theme);
|
||||
document.querySelectorAll('.theme-switcher__chip').forEach(c => c.classList.toggle('active', c === chip));
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,349 @@
|
||||
<!doctype html>
|
||||
<html lang="en" data-theme="ocean-dusk">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<title>Settings — WeVisto</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700;900&family=Marcellus&family=Cormorant+Garamond:ital,wght@1,400&family=DM+Mono:wght@400;500&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="_tokens.css">
|
||||
<link rel="stylesheet" href="_chrome.css">
|
||||
<style>
|
||||
.page-title {
|
||||
padding: var(--space-6) var(--space-5) var(--space-3);
|
||||
text-align: center;
|
||||
}
|
||||
.page-title__plate {
|
||||
font: var(--type-label);
|
||||
letter-spacing: 0.32em;
|
||||
text-transform: uppercase;
|
||||
color: var(--text-muted);
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
.page-title__plate .v-mark { color: var(--brand-yellow); font-family: var(--font-display); font-size: var(--text-md); margin: 0 8px; }
|
||||
.page-title__title {
|
||||
font: var(--type-display-lg);
|
||||
color: var(--text);
|
||||
text-shadow: 0 2px 10px rgba(0,0,0,0.3);
|
||||
}
|
||||
.page-title__rule {
|
||||
width: 60px; height: 1px;
|
||||
margin: var(--space-3) auto 0;
|
||||
background: linear-gradient(90deg, transparent, var(--brand-yellow), transparent);
|
||||
}
|
||||
|
||||
.section { margin: var(--space-6) var(--space-5) 0; }
|
||||
.section__head {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 12px;
|
||||
margin-bottom: var(--space-3);
|
||||
padding: 0 var(--space-2);
|
||||
}
|
||||
.section__roman {
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--text-lg);
|
||||
color: var(--brand-yellow);
|
||||
line-height: 1;
|
||||
}
|
||||
.section__label {
|
||||
font: var(--type-label);
|
||||
letter-spacing: 0.32em;
|
||||
text-transform: uppercase;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
.section__rule { flex: 1; height: 1px; background: var(--glass-bord); }
|
||||
|
||||
.list {
|
||||
border-radius: var(--radius-lg);
|
||||
overflow: hidden;
|
||||
}
|
||||
.row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-3);
|
||||
padding: var(--space-4) var(--space-5);
|
||||
border-bottom: 1px solid var(--glass-bord);
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
transition: background var(--duration-fast);
|
||||
}
|
||||
.row:last-child { border-bottom: 0; }
|
||||
.row:hover { background: rgba(255,255,255,0.05); }
|
||||
.row__icon { width: 22px; height: 22px; flex-shrink: 0; color: var(--text-muted); }
|
||||
.row__icon svg { width: 100%; height: 100%; stroke: currentColor; fill: none; stroke-width: 2; }
|
||||
.row__label {
|
||||
flex: 1;
|
||||
font-family: var(--font-family);
|
||||
font-size: var(--text-base);
|
||||
font-weight: 700;
|
||||
color: var(--text);
|
||||
}
|
||||
.row__value {
|
||||
font: italic 400 14px/1.3 var(--font-accent);
|
||||
color: var(--text-muted);
|
||||
}
|
||||
.row__chevron { color: var(--text-muted); opacity: 0.6; }
|
||||
|
||||
/* DUSK PICKER */
|
||||
.theme-picker {
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--space-5);
|
||||
}
|
||||
.theme-picker__head {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
.theme-picker__title {
|
||||
font: var(--type-display-md);
|
||||
color: var(--text);
|
||||
}
|
||||
.theme-picker__hint {
|
||||
font: var(--type-accent-md);
|
||||
color: var(--text-muted);
|
||||
}
|
||||
.theme-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-3); }
|
||||
.theme-swatch {
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--space-3);
|
||||
border: 1px solid var(--glass-bord);
|
||||
background: rgba(0,0,0,0.25);
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
transition: transform var(--duration-fast), box-shadow var(--duration-fast);
|
||||
font-family: inherit;
|
||||
color: var(--text);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.theme-swatch.active {
|
||||
border-color: var(--brand-yellow);
|
||||
box-shadow: 0 0 0 2px color-mix(in srgb, var(--brand-yellow) 35%, transparent);
|
||||
}
|
||||
.theme-swatch:hover { transform: translateY(-2px); }
|
||||
/* a tinted preview of harbor inside each swatch */
|
||||
.theme-swatch__preview {
|
||||
aspect-ratio: 3/2;
|
||||
border-radius: var(--radius-sm);
|
||||
overflow: hidden;
|
||||
margin-bottom: var(--space-2);
|
||||
background-image: url('../assets/harbor.jpg');
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
position: relative;
|
||||
}
|
||||
.theme-swatch__preview::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
mix-blend-mode: multiply;
|
||||
}
|
||||
.theme-swatch[data-pref="ocean-dusk"] .theme-swatch__preview::after { background: rgba(8, 22, 38, 0.55); }
|
||||
.theme-swatch[data-pref="amber-dusk"] .theme-swatch__preview::after { background: rgba(60, 25, 8, 0.55); }
|
||||
.theme-swatch[data-pref="sage-dusk"] .theme-swatch__preview::after { background: rgba(20, 40, 22, 0.55); }
|
||||
.theme-swatch[data-pref="rose-dusk"] .theme-swatch__preview::after { background: rgba(56, 16, 38, 0.55); }
|
||||
.theme-swatch[data-pref="mauve-dusk"] .theme-swatch__preview::after { background: rgba(40, 18, 56, 0.55); }
|
||||
.theme-swatch[data-pref="honey-dusk"] .theme-swatch__preview::after { background: rgba(48, 36, 14, 0.55); }
|
||||
.theme-swatch__name {
|
||||
font-family: var(--font-display);
|
||||
font-size: 13px;
|
||||
color: var(--text);
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
.theme-swatch__italic {
|
||||
font: italic 400 12px/1.2 var(--font-accent);
|
||||
color: var(--text-muted);
|
||||
margin-top: 2px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.sign-out { margin: var(--space-6) var(--space-5); text-align: center; }
|
||||
.sign-out a {
|
||||
color: #e08070;
|
||||
font-family: var(--font-family);
|
||||
font-weight: 700;
|
||||
text-decoration: none;
|
||||
font-size: var(--text-base);
|
||||
padding: var(--space-4) var(--space-5);
|
||||
display: inline-block;
|
||||
}
|
||||
.sign-out a:hover { text-decoration: underline; }
|
||||
|
||||
.signature { margin: 0 var(--space-5); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="atmosphere"></div>
|
||||
|
||||
<header class="app-bar">
|
||||
<div class="app-bar__mark"><img src="../assets/mark-photo-64.png" alt=""></div>
|
||||
<div class="app-bar__title-group">
|
||||
<div class="app-bar__wordmark">We<span class="v">V</span>isto</div>
|
||||
<div class="app-bar__sub">— settings</div>
|
||||
</div>
|
||||
<div class="app-bar__spacer"></div>
|
||||
</header>
|
||||
|
||||
<main class="main-scroll">
|
||||
|
||||
<div class="page-title">
|
||||
<div class="page-title__plate">Settings <span class="v-mark">·</span> Plate i</div>
|
||||
<h1 class="page-title__title">A few quiet choices.</h1>
|
||||
<div class="page-title__rule"></div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<div class="section__head"><span class="section__roman">I.</span><span class="section__label">Account</span><span class="section__rule"></span></div>
|
||||
<div class="list glass">
|
||||
<a class="row">
|
||||
<span class="row__icon"><svg viewBox="0 0 24 24"><circle cx="12" cy="8" r="4"/><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/></svg></span>
|
||||
<span class="row__label">Alice Wexler</span>
|
||||
<span class="row__value">alice@example.com</span>
|
||||
<span class="row__chevron">›</span>
|
||||
</a>
|
||||
<a class="row">
|
||||
<span class="row__icon"><svg viewBox="0 0 24 24"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/><polyline points="22,6 12,13 2,6"/></svg></span>
|
||||
<span class="row__label">Notification email</span>
|
||||
<span class="row__value">daily digest</span>
|
||||
<span class="row__chevron">›</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<div class="section__head"><span class="section__roman">II.</span><span class="section__label">Appearance</span><span class="section__rule"></span></div>
|
||||
<div class="theme-picker glass">
|
||||
<div class="theme-picker__head">
|
||||
<div class="theme-picker__title">Dusk</div>
|
||||
<div class="theme-picker__hint">— pick a tint for the room</div>
|
||||
</div>
|
||||
<div class="theme-grid">
|
||||
<button class="theme-swatch active" data-pref="ocean-dusk">
|
||||
<div class="theme-swatch__preview"></div>
|
||||
<div class="theme-swatch__name">Ocean dusk</div>
|
||||
<span class="theme-swatch__italic">— the harbor</span>
|
||||
</button>
|
||||
<button class="theme-swatch" data-pref="amber-dusk">
|
||||
<div class="theme-swatch__preview"></div>
|
||||
<div class="theme-swatch__name">Amber dusk</div>
|
||||
<span class="theme-swatch__italic">— the workshop</span>
|
||||
</button>
|
||||
<button class="theme-swatch" data-pref="sage-dusk">
|
||||
<div class="theme-swatch__preview"></div>
|
||||
<div class="theme-swatch__name">Sage dusk</div>
|
||||
<span class="theme-swatch__italic">— the garden</span>
|
||||
</button>
|
||||
<button class="theme-swatch" data-pref="rose-dusk">
|
||||
<div class="theme-swatch__preview"></div>
|
||||
<div class="theme-swatch__name">Rose dusk</div>
|
||||
<span class="theme-swatch__italic">— the parlor</span>
|
||||
</button>
|
||||
<button class="theme-swatch" data-pref="mauve-dusk">
|
||||
<div class="theme-swatch__preview"></div>
|
||||
<div class="theme-swatch__name">Mauve dusk</div>
|
||||
<span class="theme-swatch__italic">— the study</span>
|
||||
</button>
|
||||
<button class="theme-swatch" data-pref="honey-dusk">
|
||||
<div class="theme-swatch__preview"></div>
|
||||
<div class="theme-swatch__name">Honey dusk</div>
|
||||
<span class="theme-swatch__italic">— the alcove</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<div class="section__head"><span class="section__roman">III.</span><span class="section__label">Frames</span><span class="section__rule"></span></div>
|
||||
<div class="list glass">
|
||||
<a class="row">
|
||||
<span class="row__icon"><svg viewBox="0 0 24 24"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21,15 16,10 5,21"/></svg></span>
|
||||
<span class="row__label">Margaret's frame</span>
|
||||
<span class="row__value">7.3″ landscape</span>
|
||||
<span class="row__chevron">›</span>
|
||||
</a>
|
||||
<a class="row">
|
||||
<span class="row__icon"><svg viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg></span>
|
||||
<span class="row__label">Add another frame</span>
|
||||
<span class="row__chevron">›</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<div class="section__head"><span class="section__roman">IV.</span><span class="section__label">Help</span><span class="section__rule"></span></div>
|
||||
<div class="list glass">
|
||||
<a class="row">
|
||||
<span class="row__icon"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg></span>
|
||||
<span class="row__label">How WeVisto works</span>
|
||||
<span class="row__chevron">›</span>
|
||||
</a>
|
||||
<a class="row">
|
||||
<span class="row__icon"><svg viewBox="0 0 24 24"><path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"/></svg></span>
|
||||
<span class="row__label">Contact us</span>
|
||||
<span class="row__chevron">›</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sign-out"><a href="#">Sign out</a></div>
|
||||
|
||||
<div class="signature">
|
||||
<div class="signature__mark"><img src="../assets/mark-photo-64.png" alt=""></div>
|
||||
<div class="signature__text">WeVisto <span class="v-mark">·</span> a frame, gifted</div>
|
||||
<div class="signature__version">Edizione I · MMXXVI · Camogli</div>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
||||
<nav class="bottom-nav">
|
||||
<a class="bottom-nav__tab" href="home.html">
|
||||
<svg viewBox="0 0 24 24"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9,22 9,12 15,12 15,22"/></svg>
|
||||
<span class="label">Home</span>
|
||||
</a>
|
||||
<a class="bottom-nav__tab" href="library.html">
|
||||
<svg viewBox="0 0 24 24"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/></svg>
|
||||
<span class="label">Library</span>
|
||||
</a>
|
||||
<a class="bottom-nav__tab active" href="settings.html">
|
||||
<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>
|
||||
<span class="label">Settings</span>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
<div class="theme-switcher" role="region" aria-label="Theme switcher (mockup only)">
|
||||
<span class="theme-switcher__label">Dusk</span>
|
||||
<div class="theme-switcher__chips">
|
||||
<button class="theme-switcher__chip active" data-theme="ocean-dusk" title="Ocean dusk"></button>
|
||||
<button class="theme-switcher__chip" data-theme="amber-dusk" title="Amber dusk"></button>
|
||||
<button class="theme-switcher__chip" data-theme="sage-dusk" title="Sage dusk"></button>
|
||||
<button class="theme-switcher__chip" data-theme="rose-dusk" title="Rose dusk"></button>
|
||||
<button class="theme-switcher__chip" data-theme="mauve-dusk" title="Mauve dusk"></button>
|
||||
<button class="theme-switcher__chip" data-theme="honey-dusk" title="Honey dusk"></button>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
document.querySelectorAll('.theme-switcher__chip').forEach(chip => {
|
||||
chip.addEventListener('click', () => {
|
||||
const t = chip.dataset.theme;
|
||||
document.documentElement.setAttribute('data-theme', t);
|
||||
document.querySelectorAll('.theme-switcher__chip').forEach(c => c.classList.toggle('active', c === chip));
|
||||
document.querySelectorAll('.theme-swatch').forEach(s => s.classList.toggle('active', s.dataset.pref === t));
|
||||
});
|
||||
});
|
||||
document.querySelectorAll('.theme-swatch').forEach(sw => {
|
||||
sw.addEventListener('click', () => {
|
||||
const t = sw.dataset.pref;
|
||||
document.documentElement.setAttribute('data-theme', t);
|
||||
document.querySelectorAll('.theme-swatch').forEach(s => s.classList.toggle('active', s === sw));
|
||||
document.querySelectorAll('.theme-switcher__chip').forEach(c => c.classList.toggle('active', c.dataset.theme === t));
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user