design: atmospheric redesign mockups (login + SPA, six dusks)
CI / test (push) Has been cancelled

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:
2026-05-15 09:44:26 -04:00
parent 6c9959c00d
commit 01b6007b1c
34 changed files with 2064 additions and 0 deletions
@@ -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>