feat: add Hermes WebUI provisioning and English Dragon HD Omni voices
Rebuild & Deploy / rebuild (push) Successful in 2m17s

This commit is contained in:
snowspeeder committed 2026-10-02 16:07:24 -04:00
1 parent 47cc9c88a0
commit 6b8d55fc92
59 files changed
+1175 -70

No files matched your search

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" role="img" aria-labelledby="title"><title id="title">Hope — overlapping speech bubbles</title><rect width="100" height="100" rx="23" fill="#2454df"/><path d="M23 26h39a8 8 0 0 1 8 8v20a8 8 0 0 1-8 8H42L28 73V62h-5a8 8 0 0 1-8-8V34a8 8 0 0 1 8-8Z" fill="#fff"/><path d="M47 40h30a8 8 0 0 1 8 8v17a8 8 0 0 1-8 8h-3v10L61 73H47a8 8 0 0 1-8-8V48a8 8 0 0 1 8-8Z" fill="#a9c0ff" stroke="#2454df" stroke-width="4"/></svg>

After

Width:  |  Height:  |  Size: 478 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

+73
View File
@@ -0,0 +1,73 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="color-scheme" content="light"><title>Hope — CLEAR design demo</title>
<style>
:root{--blue:#2454df;--ink:#192334;--muted:#586578;--line:#e3e8ef;--group:#f3f6fa;--pale:#edf3ff;--red:#b62b36;--green:#197447;font-family:-apple-system,BlinkMacSystemFont,"SF Pro Text","Segoe UI",sans-serif;color:var(--ink);background:#f4f7fb;font-synthesis:none}*{box-sizing:border-box}body{margin:0}button,input,select{font:inherit}button{cursor:pointer;min-height:44px;color:inherit}button:disabled{cursor:default;opacity:.5}button:focus-visible,input:focus-visible,select:focus-visible,a:focus-visible{outline:3px solid var(--blue);outline-offset:4px}button:hover:not(:disabled){filter:brightness(.96)}button:active:not(:disabled){transform:translateY(1px)}a{color:var(--blue)}[hidden]{display:none!important}.sheet{max-width:1140px;margin:auto;min-height:100vh;display:grid;grid-template-columns:1fr 438px;gap:90px;align-items:center;padding:56px 48px}.presentation{max-width:450px}.direction{display:flex;align-items:center;gap:12px;font-size:14px;font-weight:600;color:var(--muted)}.direction:before{content:"";width:25px;height:2px;background:var(--blue)}h1{font-size:76px;letter-spacing:-.04em;line-height:1.05;margin:28px 0 22px;font-weight:650}h1 span{display:block;font-weight:400;color:var(--blue)}.thesis{font-size:20px;line-height:1.6;margin:0;max-width:33ch;letter-spacing:-.015em}.design-notes{margin:34px 0 0;padding:0;list-style:none}.design-notes li{padding:17px 0;border-top:1px solid #dce3ec;font-size:14px;line-height:1.55;color:var(--muted)}.design-notes strong{display:block;font-size:16px;font-weight:600;color:var(--ink);margin-bottom:4px}.identity{margin-top:36px;display:flex;gap:22px;align-items:center}.app-icon{width:96px;height:96px;display:block}.small-icon{width:32px;height:32px}.icon-caption{margin:8px 0 0;color:var(--muted);font-size:12px}.trial{font-size:13px;line-height:1.6;color:var(--muted);margin:28px 0 0;max-width:43ch}.device-wrap{justify-self:center}.device{width:414px;padding:11px;background:#202733;border-radius:53px;box-shadow:0 22px 48px #26364b20,0 2px 4px #26364b25;position:relative}.device:before{content:"";position:absolute;left:-3px;top:160px;width:3px;height:62px;border-radius:2px;background:#384354}.screen{height:780px;overflow:hidden;border-radius:43px;background:white;display:flex;flex-direction:column;position:relative}.statusbar{height:54px;flex-shrink:0;display:flex;align-items:center;justify-content:space-between;padding:0 27px;font-size:14px;font-weight:650;position:relative}.island{position:absolute;left:50%;transform:translateX(-50%);top:10px;width:116px;height:30px;border-radius:18px;background:#18212b}.status-icons{display:flex;gap:6px;align-items:center}.status-icons svg{width:17px;height:17px}.demo-strip{font-size:10px;font-weight:600;letter-spacing:.03em;color:#52617b;text-align:center;padding:7px 6px;background:var(--pale)}.app-header{padding:22px 24px 12px;display:flex;align-items:center;justify-content:space-between;flex-shrink:0}.app-header h2{margin:0;font-size:36px;letter-spacing:-.035em;font-weight:700}.brand-mini{width:38px;height:38px}.icon{width:22px;height:22px;fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round;flex-shrink:0}.icon-button{width:44px;height:44px;padding:10px;display:grid;place-items:center;border:0;background:transparent;border-radius:10px;color:var(--blue)}.app-body{flex:1;overflow-y:auto;overscroll-behavior:contain;padding:0 24px 18px}.welcome{padding:18px 0 25px}.welcome h3{font-size:28px;line-height:1.22;font-weight:600;letter-spacing:-.03em;margin:0 0 12px;max-width:10ch}.welcome p{font-size:15px;line-height:1.55;margin:0;color:var(--muted);max-width:29ch}.segmented{display:flex;background:#edf0f5;border-radius:9px;padding:3px;margin-bottom:14px}.segmented button{flex:1;min-height:44px;border:0;background:transparent;border-radius:7px;display:flex;gap:8px;align-items:center;justify-content:center;font-size:14px;font-weight:600;color:var(--muted)}.segmented button[aria-pressed=true]{background:white;color:var(--ink);box-shadow:0 1px 3px #18233815}.segmented .icon{width:18px;height:18px}.primary{width:100%;min-height:54px;border:0;border-radius:12px;background:var(--blue);color:#fff;display:flex;justify-content:center;align-items:center;gap:10px;font-weight:600;font-size:16px}.local-note{text-align:center;font-size:11px;color:var(--muted);margin:10px 0 0}.section-heading{display:flex;align-items:baseline;justify-content:space-between;margin-top:33px;margin-bottom:9px}.section-heading h3{font-size:18px;letter-spacing:-.015em;margin:0}.section-heading span{font-size:11px;color:var(--muted)}.list{border-top:1px solid var(--line)}.conversation-row{border:0;border-bottom:1px solid var(--line);background:transparent;display:flex;align-items:center;gap:12px;text-align:left;width:100%;padding:17px 0;min-height:78px}.row-symbol{width:36px;height:36px;background:var(--group);border-radius:9px;display:grid;place-items:center;color:var(--muted);flex-shrink:0}.row-text{flex:1;min-width:0}.row-text strong{displLine truncated
@media(max-width:950px){.sheet{gap:35px;padding:40px 28px;grid-template-columns:1fr 414px}h1{font-size:60px}.thesis{font-size:18px}.design-notes{margin-top:25px}}
@media(max-width:760px){.sheet{display:flex;flex-direction:column;padding:32px 20px;gap:30px}.presentation{width:100%;max-width:414px}.direction{font-size:12px}h1{font-size:48px;margin:18px 0 15px}h1 span{display:inline}.thesis{max-width:36ch;font-size:17px}.design-notes{display:none}.identity{margin-top:20px;gap:14px}.app-icon{width:58px;height:58px}.trial{margin-top:18px}.device-wrap{max-width:100%;width:414px}.device{width:100%;padding:8px;border-radius:45px}.screen{height:780px;border-radius:37px}.device-caption{line-height:1.5}}@media(max-width:430px){.sheet{padding:24px 12px}.device{padding:6px;border-radius:39px}.screen{border-radius:33px}.app-body{padding-left:20px;padding-right:20px}.app-header{padding-left:20px;padding-right:20px}.statusbar{padding-left:23px;padding-right:23px}.presentation{padding:0 8px}h1{font-size:44px}}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation:none!important;transition:none!important;scroll-behavior:auto!important}}
</style>
</head>
<body>
<svg aria-hidden="true" width="0" height="0" style="position:absolute"><defs>
<symbol id="hope-mark" viewBox="0 0 100 100"><rect width="100" height="100" rx="23" fill="#2454df"/><path d="M23 26h39a8 8 0 0 1 8 8v20a8 8 0 0 1-8 8H42L28 73V62h-5a8 8 0 0 1-8-8V34a8 8 0 0 1 8-8Z" fill="#fff"/><path d="M47 40h30a8 8 0 0 1 8 8v17a8 8 0 0 1-8 8h-3v10L61 73H47a8 8 0 0 1-8-8V48a8 8 0 0 1 8-8Z" fill="#a9c0ff" stroke="#2454df" stroke-width="4"/></symbol>
<symbol id="mic" viewBox="0 0 24 24"><rect x="9" y="3" width="6" height="12" rx="3"/><path d="M5 11v2a7 7 0 0 0 14 0v-2M12 20v2M8 22h8"/></symbol>
<symbol id="bubble" viewBox="0 0 24 24"><path d="M5 4h14a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H9l-6 4V6a2 2 0 0 1 2-2Z"/><path d="M7 9h10M7 13h6"/></symbol>
<symbol id="activity" viewBox="0 0 24 24"><path d="M3 12h4l3-8 4 16 3-8h4"/></symbol>
<symbol id="settings" viewBox="0 0 24 24"><path d="m10 3-.7 2.2-2 .9-2.2-.7-2 3.4 1.6 1.6v2.3L3 14.3l2 3.4 2.2-.7 2 .9.8 2.1h4l.8-2.1 2-.9 2.2.7 2-3.4-1.7-1.6v-2.3L21 8.8l-2-3.4-2.2.7-2-.9L14 3Z"/><circle cx="12" cy="11.5" r="3"/></symbol>
<symbol id="chevron" viewBox="0 0 24 24"><path d="m9 5 7 7-7 7"/></symbol><symbol id="arrow-back" viewBox="0 0 24 24"><path d="m15 5-7 7 7 7"/></symbol><symbol id="arrow" viewBox="0 0 24 24"><path d="M12 19V5m-6 6 6-6 6 6"/></symbol><symbol id="mic-muted" viewBox="0 0 24 24"><path d="m3 3 18 18M9 9v3a3 3 0 0 0 5 2M9 5a3 3 0 0 1 6 0v6M5 11v2a7 7 0 0 0 12 5M19 11v2M12 20v2"/></symbol><symbol id="stop" viewBox="0 0 24 24"><rect x="6" y="6" width="12" height="12" rx="2"/></symbol><symbol id="check" viewBox="0 0 24 24"><path d="m5 12 4 4L19 6"/></symbol>
</defs></svg>
<main class="sheet">
<section class="presentation" aria-label="Design direction">
<a href="index.html" style="display:inline-flex;align-items:center;min-height:44px;font-size:14px;text-decoration:none;margin-bottom:18px">← All three directions</a><div class="direction">Hope for iOS · Design direction CLEAR</div>
<h1>A little<br>more <span>clarity.</span></h1>
<p class="thesis">A conversation should feel easy to start. And just as easy to come back to.</p>
<ul class="design-notes"><li><strong>Conversation comes first.</strong>A welcoming home, a single starting point, and recent conversations within reach.</li><li><strong>Daylight, not a light show.</strong>White space, readable system type, and cobalt where there’s something to do.</li><li><strong>A mark that means something.</strong>Two voices, two overlapping bubbles. Distinct at 32 pixels. No glow required.</li></ul>
<div class="identity"><svg class="app-icon" role="img" aria-label="Hope app icon: overlapping speech bubbles on cobalt"><use href="#hope-mark"/></svg><div><svg class="small-icon" role="img" aria-label="Hope icon at 32 pixels"><use href="#hope-mark"/></svg><p class="icon-caption">An exchange, not an orb.</p></div></div>
<p class="trial">Interactive design demo. Try a conversation, switch to text, or explore Activity and Settings. All content is sample data; no microphone, network, or account access.</p>
</section>
<section class="device-wrap" aria-label="Interactive iPhone demo">
<div class="device"><div class="screen">
<div class="statusbar" aria-hidden="true"><span>9:41</span><span class="island"></span><span class="status-icons"><svg viewBox="0 0 20 20" fill="currentColor"><rect x="1" y="12" width="3" height="5" rx="1"/><rect x="6" y="9" width="3" height="8" rx="1"/><rect x="11" y="6" width="3" height="11" rx="1"/><rect x="16" y="3" width="3" height="14" rx="1"/></svg><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 9a14 14 0 0 1 18 0M6 12a9 9 0 0 1 12 0M9 15a4 4 0 0 1 6 0"/><circle cx="12" cy="18" r="1" fill="currentColor"/></svg><svg viewBox="0 0 25 16" fill="none" stroke="currentColor"><rect x="1" y="2" width="20" height="12" rx="3"/><rect x="3" y="4" width="16" height="8" rx="1" fill="currentColor"/><path d="M23 6v4" stroke-width="2"/></svg></span></div>
<div class="demo-strip">INTERACTIVE DEMO · SAMPLE DATA · NO MIC ACCESS</div>
<header class="app-header"><h2 id="page-title">Hope</h2><svg id="header-mark" class="brand-mini" aria-label="Hope" role="img"><use href="#hope-mark"/></svg></header>
<div class="app-body" id="app-body" tabindex="-1">
<section class="welcome"><h3>What’s on<br>your mind?</h3><p>Talk it through, make a plan,<br>or follow a little curiosity.</p></section>
<div class="segmented" aria-label="Conversation input"><button type="button" data-mode="voice" aria-pressed="true"><svg class="icon"><use href="#mic"/></svg>Voice</button><button type="button" data-mode="text" aria-pressed="false"><svg class="icon"><use href="#bubble"/></svg>Text</button></div>
<button class="primary" id="start"><svg class="icon"><use href="#mic"/></svg>Start a conversation</button><p class="local-note">A simulated conversation. Your mic stays off.</p>
<div class="section-heading"><h3>Recent conversations</h3><span>Sample data</span></div>
<div class="list" id="recent-list"><button class="conversation-row" data-sample="0"><span class="row-symbol"><svg class="icon"><use href="#bubble"/></svg></span><span class="row-text"><strong>A slower Sunday</strong><small>Today · A little room to recharge</small></span><svg class="icon chevron"><use href="#chevron"/></svg></button><button class="conversation-row" data-sample="1"><span class="row-symbol"><svg class="icon"><use href="#bubble"/></svg></span><span class="row-text"><strong>Something good for dinner</strong><small>Yesterday · What’s in the fridge</small></span><svg class="icon chevron"><use href="#chevron"/></svg></button><button class="conversation-row" data-sample="2"><span class="row-symbol"><svg class="icon"><use href="#bubble"/></svg></span><span class="row-text"><strong>A thought worth keeping</strong><small>Monday · An idea for the weekend</small></span><svg class="icon chevron"><use href="#chevron"/></svg></button></div>
</div>
<nav class="tabbar" aria-label="App navigation"><button data-page="home" aria-current="page"><svg class="icon"><use href="#bubble"/></svg>Talk</button><button data-page="activity"><svg class="icon"><use href="#activity"/></svg>Activity</button><button data-page="settings"><svg class="icon"><use href="#settings"/></svg>Settings</button></nav><div class="home-indicator" aria-hidden="true"></div><div id="announcement" class="sr-only" role="status" aria-live="polite"></div>
</div></div><p class="device-caption">CLEAR · An interactive proposal, not the live app</p>
</section>
</main>
<script>
(()=>{'use strict';
const body=document.getElementById('app-body'),title=document.getElementById('page-title'),mark=document.getElementById('header-mark'),homeHTML=body.innerHTML,announce=document.getElementById('announcement');
const samples=[{title:'A slower Sunday',user:'I’d like a quieter Sunday. Where should I start?',reply:'Leave the first hour unplanned. A walk, a slow breakfast, and one thing you’re looking forward to could be enough.'},{title:'Something good for dinner',user:'I have chickpeas, tomatoes, and a little feta.',reply:'Try warm chickpeas with tomatoes and olive oil, then crumble the feta on top. Some toasted bread would make it a lovely dinner.'},{title:'A thought worth keeping',user:'Maybe we could take the train to the coast this weekend.',reply:'That sounds like a good change of pace. Start with a morning train and leave the afternoon open for a walk by the water.'}];
let mode='voice',page='home',timers=[],muted=false,state='idle',events=[],voice='Ava',spoken=true,session=0;
const icon=(name)=>`<svg class="icon" aria-hidden="true"><use href="#${name}"/></svg>`;
function clearTimers(){timers.forEach(clearTimeout);timers=[];session++;}
function later(fn,ms){const current=session;timers.push(setTimeout(()=>{if(current===session)fn();},ms));}
function say(text){announce.textContent=text;}
function setPage(next){clearTimers();page=next;state='idle';title.textContent=next==='home'?'Hope':next==='activity'?'Activity':next==='settings'?'Settings':'Conversation';title.style.fontSize=next==='conversation'?'28px':'';mark.hidden=next!=='home';document.querySelectorAll('[data-page]').forEach(b=>{if(b.dataset.page===(next==='conversation'?'home':next))b.setAttribute('aria-current','page');else b.removeAttribute('aria-current');});body.scrollTop=0;}
function modePicker(){return `<div class="segmented" aria-label="Conversation input"><button data-mode="voice" aria-pressed="${mode==='voice'}">${icon('mic')}Voice</button><button data-mode="text" aria-pressed="${mode==='text'}">${icon('bubble')}Text</button></div>`;}
function updateMode(){body.querySelectorAll('[data-mode]').forEach(b=>b.setAttribute('aria-pressed',String(b.dataset.mode===mode)));if(page==='home'){document.getElementById('start').innerHTML=icon(mode==='voice'?'mic':'bubble')+(mode==='voice'?'Start a conversation':'Write a message');body.querySelector('.local-note').textContent=mode==='voice'?'A simulated conversation. Your mic stays off.':'A local text demo. Nothing is sent.';}}
function home(){setPage('home');body.innerHTML=homeHTML;updateMode();}
function addMessage(role,text){const box=document.createElement('div');box.className='message '+(role==='You'?'user':'hope');const label=document.createElement('small');label.textContent=role;const p=document.createElement('p');p.textContent=text;box.append(label,p);document.getElementById('transcript').append(box);body.scrollTop=body.scrollHeight;}
function conversation(sample){setPage('conversation');muted=false;body.innerHTML=`<button class="back" id="back">${icon('arrow-back')}All conversations</button><h3 class="conversation-heading" id="conversation-title">New conversation</h3><p class="conversation-meta">Local demo · No audio is recorded</p><div id="transcript" class="transcript" role="log" aria-live="polite" aria-label="Conversation transcript"></div>${modePicker()}<div id="interaction"></div>`;if(sample){document.getElementById('conversation-title').textContent=sample.title;addMessage('You',sample.user);addMessage('Hope',sample.reply);}renderInteraction(!sample);}
function renderInteraction(startVoice){clearTimers();const el=document.getElementById('interaction');if(mode==='text'){state='text';el.innerHTML=`<form class="composer" id="text-form"><label for="message" class="sr-only">Message Hope</label><input id="message" placeholder="Message Hope…" maxlength="2000" autocomplete="off" required><button aria-label="Send message">${icon('arrow')}</button></form><p class="hint">Demo replies are prewritten. Your text stays on this page.</p>`;if(startVoice)document.getElementById('message').focus();}else{el.innerHTML=`<div class="voice-panel"><div class="mic-emblem" id="mic-emblem">${icon('mic')}</div><h3 id="voice-status">Ready to listen</h3><p id="voice-detail">Your real microphone is off.</p><div class="voice-controls"><button class="control" id="mute">${icon('mic-muted')}Mute</button><button class="control end" id="end">${icon('stop')}End</button></div></div><button class="primary" id="listen">${icon('mic')}Try a voice turn</button><p class="hint">Simulated voice only. No sound is played or recorded.</p>`;state='idle';if(startVoice)listen();}}
function status(next,heading,detail){state=next;const s=document.getElementById('voice-status');if(!s)return;s.textContent=heading;document.getElementById('voice-detail').textContent=detail;say(heading+'. '+detail);}
function listen(){clearTimers();muted=false;document.getElementById('mute').disabled=false;document.getElementById('end').disabled=false;document.getElementById('mute').innerHTML=icon('mic-muted')+'Mute';document.getElementById('mute').setAttribute('aria-pressed','false');document.getElementById('listen').disabled=true;document.getElementById('mic-emblem').innerHTML=icon('mic');status('listening','Listening…','Simulated mic on · Try Mute or End');later(()=>{addMessage('You','Help me make a little space in my day.');status('working','Thinking it through…','Mic paused · Preparing a sample reply');},2400);later(()=>{addMessage('Hope','Pick one thing that can wait, and give yourself ten minutes without a plan. What would you like that little break to feel like?');status('reply','Hope is replying','Simulated reply · No audio is playing');events.unshift({title:'A little space in the day',description:'Completed a simulated voice turn.'});},4100);later(()=>{status('idle','Ready when you are','Simulated mic off · Tap below to try again');document.getElementById('listen').disabled=false;},6200);}
function activity(){setPage('activity');body.innerHTML=`<p class="activity-intro">A simple record of your conversations.<br>Everything here is local sample data.</p><div class="section-heading"><h3>Today</h3><span>On this page</span></div><div id="activity-events"></div><div class="event"><span class="row-symbol">${icon('check')}</span><div><strong>A slower Sunday</strong><p>A sample conversation about making room to recharge.</p><time>9:12 AM · Sample</time></div></div><div class="section-heading"><h3>Yesterday</h3></div><div class="event"><span class="row-symbol">${icon('bubble')}</span><div><strong>Something good for dinner</strong><p>A sample conversation with a simple dinner idea.</p><time>6:24 PM · Sample</time></div></div><p class="live-note">Try a voice or text conversation to add a demo event here. This record resets when you reload.</p>`;events.forEach(e=>{const row=document.createElement('div');row.className='event';const symbol=document.createElement('span');symbol.className='row-symbol';symbol.innerHTML=icon('check');const detail=document.createElement('div');const strong=document.createElement('strong');strong.textContent=e.title;const p=document.createElement('p');p.textContent=e.description;const time=document.createElement('time');time.textContent='Just now · Demo';detail.append(strong,p,time);row.append(symbol,detail);document.getElementById('activity-events').append(row);});}
function settings(){setPage('settings');body.innerHTML=`<p class="activity-intro">Make Hope feel comfortable for you.</p><div class="group-label">Conversation</div><div class="grouped"><label class="setting-row" for="voice-choice"><span>Voice preference<small>Used for simulated voice only</small></span><select id="voice-choice"><option>Ava</option><option>Andrew</option><option>Emma</option></select></label><label class="setting-row" for="spoken"><span>Spoken replies<small>Preference only; no audio plays</small></span><input type="checkbox" id="spoken"></label></div><p class="settings-note">Preferences stay in this demo until you reload. Voice choice doesn’t change the sample transcript.</p><div class="group-label">About this demo</div><div class="grouped"><div class="setting-row"><span>Hope for iOS</span><span style="color:var(--muted)">CLEAR</span></div><div class="setting-row"><span>Data & privacy<small>No account, microphone, or network access.<br>All conversations are local examples.</small></span></div></div><div class="group-label">Account</div><div class="grouped"><div class="setting-row"><span>Demo account<small>You are not signed in to a real account.</small></span></div><button class="danger-button" id="signout">Simulate sign out</button></div><div id="account-message" role="status"></div>`;document.getElementById('voice-choice').value=voice;document.getElementById('spoken').checked=spoken;}
body.addEventListener('click',e=>{const button=e.target.closest('button');if(!button)return;if(button.dataset.mode){mode=button.dataset.mode;if(page==='home')updateMode();else renderInteraction(false);say(mode==='voice'?'Voice mode. Microphone access is simulated.':'Text mode. Messages stay on this page.');return;}if(button.dataset.sample!==undefined){conversation(samples[Number(button.dataset.sample)]);return;}switch(button.id){case'start':conversation();break;case'back':home();break;case'listen':listen();break;case'mute':muted=!muted;clearTimers();button.setAttribute('aria-pressed',String(muted));button.innerHTML=icon(muted?'mic':'mic-muted')+(muted?'Unmute':'Mute');if(muted){status('muted','Microphone muted','Simulation paused · Unmute to try again');document.getElementById('mic-emblem').innerHTML=icon('mic-muted');document.getElementById('listen').disabled=true;}else listen();break;case'end':clearTimers();status('ended','Conversation ended','Demo stopped · Your real mic was never on');document.getElementById('mute').disabled=true;document.getElementById('end').disabled=true;document.getElementById('listen').disabled=false;document.getElementById('listen').innerHTML=icon('mic')+'Start another voice turn';events.unshift({title:'Conversation ended',description:'Stopped the simulated conversation.'});break;case'signout':document.getElementById('account-message').innerHTML='<div class="notice"><strong>Simulated sign out</strong><br>No real account was signed out. This is only a design demo.<br><button id="reset-account">Return to demo account</button></div>';button.disabled=true;break;case'reset-account':document.getElementById('account-message').innerHTML='';document.getElementById('signout').disabled=false;say('Demo account restored. No real account action occurred.');break;}});
body.addEventListener('change',e=>{if(e.target.id==='voice-choice'){voice=e.target.value;say(voice+' selected for this demo.');}if(e.target.id==='spoken'){spoken=e.target.checked;say('Spoken replies '+(spoken?'enabled':'disabled')+' as a demo preference. No audio plays.');}});
body.addEventListener('submit',e=>{if(e.target.id!=='text-form')return;e.preventDefault();const field=document.getElementById('message'),text=field.value.trim();if(!text)return;addMessage('You',text);field.value='';addMessage('Hope','Let’s take it one step at a time. What’s the part you’d most like to talk through? (This is a prewritten demo reply.)');events.unshift({title:'Text conversation',description:'Sent a local demo message. Nothing was transmitted.'});field.focus();say('Local demo message added.');});
document.querySelector('.tabbar').addEventListener('click',e=>{const b=e.target.closest('[data-page]');if(!b)return;if(b.dataset.page==='home')home();else if(b.dataset.page==='activity')activity();else settings();body.focus({preventScroll:true});say(title.textContent+' page');});
})();
</script>
</body>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 253 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"><rect width="1024" height="1024" fill="#db6137"/><g transform="translate(112 112) scale(8)"><path fill="#fff" d="M18 19h64v48H51L31 83V67H18z"/><path d="M36 34v19m14-24v29m14-24v19" stroke="#db6137" stroke-width="6" stroke-linecap="round"/></g></svg>

After

Width:  |  Height:  |  Size: 315 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

+10
View File
@@ -0,0 +1,10 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover"><title>Hope — Gather</title><style>
:root{--bg:#edf1ef;--ink:#183d34;--quiet:#52685f;--tint:#17614d;--wash:#e5eee9;--line:#d6e0da;--surface:#fff;--on:#fff}*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--ink);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;-webkit-font-smoothing:antialiased}button,input,select{font:inherit}button{cursor:pointer;color:inherit;min-height:44px;border:0;background:none}button:focus-visible,a:focus-visible,input:focus-visible,select:focus-visible{outline:3px solid #b14d22;outline-offset:3px}a{color:inherit}h1,h2,p{margin:0}h1,h2{text-wrap:balance}[hidden]{display:none!important}.studio{max-width:1260px;margin:auto;min-height:100vh;display:grid;grid-template-columns:1fr 390px 200px;gap:50px;align-items:center;padding:44px}.intro{align-self:start;padding-top:70px}.back{font-size:14px;text-decoration:none;display:inline-flex;align-items:center;min-height:44px}.direction{display:block;margin:38px 0 18px;font-size:15px;font-weight:600}.intro h1{font-family:Georgia,serif;font-size:64px;font-weight:400;letter-spacing:-.035em;line-height:1.06}.lede{font-size:18px;line-height:1.6;margin-top:24px;max-width:33ch}.notes{margin-top:40px}.note{border-top:1px solid #c8d5cd;padding:18px 0;font-size:14px;line-height:1.55}.note strong{display:block;font-size:15px;margin-bottom:4px}.prototype-label{font-size:12px;margin:0 0 12px;text-align:center;color:var(--quiet)}.phone{width:390px;height:804px;background:var(--surface);border:8px solid #19352c;border-radius:48px;position:relative;overflow:hidden;display:flex;flex-direction:column}.statusbar{height:48px;flex-shrink:0;display:flex;align-items:center;justify-content:space-between;padding:10px 26px 0;font-size:14px;font-weight:650}.island{position:absolute;top:9px;left:50%;transform:translateX(-50%);width:110px;height:28px;background:#19352c;border-radius:20px}.topbar{display:flex;align-items:center;justify-content:space-between;padding:18px 20px 12px}.brand{font-size:28px;font-weight:650;letter-spacing:-.035em;display:flex;gap:9px;align-items:center}.brand svg{width:27px;height:27px;color:#db6137}.account{border:1px solid var(--line);border-radius:50%;width:44px;font-size:14px;font-weight:600}.view{flex:1;overflow:auto;padding:0 20px 18px;min-height:0}.welcome{padding:21px 0 23px}.welcome h2{font-family:Georgia,serif;font-size:34px;font-weight:400;line-height:1.16;letter-spacing:-.025em}.welcome p{color:var(--quiet);font-size:15px;line-height:1.5;margin-top:12px}.meta{display:flex;align-items:center;gap:7px;color:var(--quiet);font-size:12px;margin:0 0 18px}.dot{width:7px;height:7px;background:var(--tint);border-radius:50%}.topic{display:flex;justify-content:space-between;align-items:center;margin-bottom:18px;font-size:13px;color:var(--quiet)}.tag{background:var(--wash);padding:6px 10px;border-radius:6px;color:var(--ink)}.messages{display:flex;flex-direction:column;gap:22px}.message{font-size:16px;line-height:1.55}.who{font-size:12px;color:var(--quiet);font-weight:600;margin-bottom:7px}.message.user{margin-left:36px;background:var(--wash);padding:12px 15px;border-radius:12px}.message.assistant{padding-right:7px}.message p{white-space:pre-wrap;overflow-wrap:anywhere}.suggestion{display:flex;justify-content:space-between;width:100%;text-align:left;border-top:1px solid var(--line);border-bottom:1px solid var(--line);font-size:14px;margin-top:24px;padding:10px 0;color:var(--tint)}.dock{padding:14px 20px 15px;border-top:1px solid var(--line)}.voice-line{display:flex;align-items:center;justify-content:space-between;margin-bottom:10px}.voice-status{font-size:13px;font-weight:600}.voice-sub{font-size:12px;color:var(--quiet);margin-top:4px}.wave{height:24px;display:flex;align-items:center;gap:3px;color:var(--tint)}.wave i{width:3px;height:7px;background:currentColor;border-radius:3px}.wave i:nth-child(2n){height:17px}.wave i:nth-child(3n){height:24px}.controls{display:flex;gap:8px}.primary{background:var(--tint);color:var(--on);border-radius:12px;font-weight:600;flex:1;min-height:52px}.secondary{background:var(--wash);border-radius:12px;padding:0 14px;min-height:52px}.end{color:#9b352a;border:1px solid var(--line);border-radius:12px;padding:0 12px}.tabs{display:flex;justify-content:space-around;padding:7px 12px 17px;border-top:1px solid var(--line);flex-shrink:0}.tab{display:flex;flex-direction:column;gap:4px;align-items:center;color:var(--quiet);min-width:80px;font-size:11px;padding:4px}.tab svg{width:23px;height:23px}.tab[aria-selected=true]{color:var(--tint);font-weight:700}.home{position:absolute;bottom:6px;width:120px;height:4px;background:var(--ink);left:50%;transform:translateX(-50%);border-radius:3px}.app-icon{width:150px;height:150px;border-radius:34px;background:#db6137;display:grid;place-items:center}.app-icon svg{width:110px;height:110px;color:#fff}.icon-title{font-size:17px;font-weight:650;margin-top:20px}.icon-caption{font-size:14px;line-height:1.6;margin-top:10px;color:var(--quiet)}.small-icons{display:flex;gap:14px;align-items:end;margLine truncated
</style></head><body><svg width="0" height="0" style="position:absolute" aria-hidden="true"><defs><symbol id="mark" viewBox="0 0 100 100"><path fill="currentColor" d="M18 19h64v48H51L31 83V67H18z"/><path d="M36 34v19m14-24v29m14-24v19" stroke="#db6137" stroke-width="6" stroke-linecap="round"/></symbol><symbol id="talk" viewBox="0 0 24 24"><path d="M4 4h16v12H10l-5 4v-4H4z"/></symbol><symbol id="activity" viewBox="0 0 24 24"><path d="M9 5h11M9 12h11M9 19h11M3 5l1 1 2-3M3 12l1 1 2-3M3 19l1 1 2-3"/></symbol><symbol id="settings" viewBox="0 0 24 24"><path d="M3 7h18M3 17h18"/><circle cx="8" cy="7" r="3"/><circle cx="16" cy="17" r="3"/></symbol></defs></svg>
<main class="studio"><section class="intro"><a class="back" href="index.html">← All three directions</a><span class="direction">Gather / conversation first</span><h1>A place for<br>your thoughts.</h1><p class="lede">Less dashboard. More conversation. A readable thread that keeps your words—and Hope’s answers—at the center.</p><div class="notes"><div class="note"><strong>The transcript is the interface.</strong>No oversized visualizer. Pick up a conversation without hunting for its context.</div><div class="note"><strong>Voice stays within reach.</strong>One persistent dock for talking, muting, or switching to text.</div><div class="note"><strong>A warmer identity, without the glow.</strong>Forest-green controls. A terracotta speech mark that reads clearly on your home screen.</div></div></section>
<section class="demo" aria-label="Interactive Gather prototype"><p class="prototype-label">Interactive iOS concept · sample conversation</p><div class="phone" id="phone"><div class="statusbar"><span>9:41</span><div class="island"></div><span aria-hidden="true">▮▮▮ ▰</span></div><header class="topbar"><div class="brand">Hope <svg aria-hidden="true"><use href="#mark"/></svg></div><button class="account" id="account" aria-label="Open account settings">S</button></header><section class="view" id="talk-view" aria-label="Conversation"><div class="welcome"><h2>Let’s make room<br>for a good weekend.</h2><p>One conversation. Speak or type.</p></div><div class="meta"><span class="dot"></span>Your personal assistant · demo</div><div class="topic"><span class="tag">Weekend plans</span><span>Today, 9:38</span></div><div class="messages" id="messages" aria-live="polite"><article class="message user"><div class="who">You</div><p>I want a quiet weekend. Help me find a starting point?</p></article><article class="message assistant"><div class="who">Hope</div><p>Start with one thing you don’t want to rush. A morning walk, a good book, or cooking something new. What sounds good to you?</p></article></div><button class="suggestion" id="suggestion"><span>Let’s start with a morning walk</span><span aria-hidden="true">↗</span></button></section>
<section class="view" id="activity-view" aria-label="Assistant activity" hidden><h2 class="section-title">Activity</h2><p class="section-sub">See what Hope is working on, without leaving your conversation.</p><div class="row"><strong id="task-title">No task running</strong><p id="task-detail">Start the voice demo to see progress here.</p><small id="task-status">Ready</small></div><div class="row"><strong>Weekend conversation</strong><p>Your latest conversation is available in Talk.</p><small>Sample history · Today, 9:38</small></div></section><section class="view" id="settings-view" aria-label="Settings" hidden><h2 class="section-title">Settings</h2><p class="section-sub">Your voice, your preferences.</p><div class="group"><div class="setting"><span>Account</span><strong>Shane · demo</strong></div><label class="setting"><span>Hope’s voice</span><select id="voice"><option>Ava</option><option>Andrew</option><option>Emma</option></select></label><label class="setting"><span>Read replies aloud</span><input class="switch" type="checkbox" checked></label><label class="setting"><span>Dark appearance</span><input class="switch" id="dark-switch" type="checkbox"></label></div><p class="notice">Preferences are local to this demonstration. No server or account is connected.</p><button class="suggestion" id="signout">Sign out of demo <span aria-hidden="true">→</span></button><p class="notice" id="settings-note" role="status"></p></section>
<div class="dock" id="dock"><div class="voice-line"><div><div class="voice-status" id="voice-status" role="status">Ready when you are</div><div class="voice-sub" id="voice-sub">Microphone off · simulated audio</div></div><div class="wave" aria-hidden="true"><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i></div></div><div class="controls" id="voice-controls"><button class="primary" id="start">Talk to Hope</button><button class="secondary" id="text" aria-label="Switch to text">Aa</button><button class="end" id="end" hidden>End</button></div><form class="composer" id="composer" hidden><label class="sr-only" for="input">Message Hope</label><input id="input" placeholder="Message Hope…" maxlength="1000" autocomplete="off"><button aria-label="Send message" type="submit">↑</button></form><button class="mode-back" id="voice-back" hidden>Switch to voice</button></div>
<nav class="tabs" role="tablist" aria-label="Main sections"><button class="tab" role="tab" aria-selected="true" aria-controls="talk-view" data-view="talk"><svg fill="none" stroke="currentColor" stroke-width="1.7" aria-hidden="true"><use href="#talk"/></svg>Talk</button><button class="tab" role="tab" aria-selected="false" aria-controls="activity-view" data-view="activity"><svg fill="none" stroke="currentColor" stroke-width="1.7" aria-hidden="true"><use href="#activity"/></svg>Activity</button><button class="tab" role="tab" aria-selected="false" aria-controls="settings-view" data-view="settings"><svg fill="none" stroke="currentColor" stroke-width="1.7" aria-hidden="true"><use href="#settings"/></svg>Settings</button></nav><div class="home" aria-hidden="true"></div></div></section>
<aside class="icons"><div class="app-icon" aria-label="New Gather app icon"><svg aria-hidden="true"><use href="#mark"/></svg></div><h2 class="icon-title">The speech mark</h2><p class="icon-caption">A conversation bubble with three voice bars. Clear silhouette. No capsule, no halo.</p><div class="small-icons" aria-label="Icon at home-screen and small sizes"><div class="small-icon"><svg aria-hidden="true"><use href="#mark"/></svg></div><div class="small-icon tiny"><svg aria-hidden="true"><use href="#mark"/></svg></div></div><button class="theme" id="theme">Preview dark appearance</button><p class="demo-note">Try Talk to Hope, text input, Activity, and Settings. All replies and progress are simulated; this page never accesses your microphone.</p></aside></main>
<script>const $=id=>document.getElementById(id);let active=false,muted=false,timers=[],busy=false;function stopTimers(){timers.forEach(clearTimeout);timers=[];busy=false}function status(title,sub){$('voice-status').textContent=title;$('voice-sub').textContent=sub}function show(view){document.querySelectorAll('.view').forEach(el=>el.hidden=el.id!==view+'-view');document.querySelectorAll('.tab').forEach(el=>el.setAttribute('aria-selected',String(el.dataset.view===view)));$('dock').hidden=view==='settings'}document.querySelectorAll('.tab').forEach(btn=>btn.onclick=()=>show(btn.dataset.view));$('account').onclick=()=>show('settings');function add(role,text){let a=document.createElement('article');a.className='message '+role;let who=document.createElement('div');who.className='who';who.textContent=role==='user'?'You':'Hope';let p=document.createElement('p');p.textContent=text;a.append(who,p);$('messages').append(a);$('suggestion').hidden=true;$('talk-view').scrollTop=$('talk-view').scrollHeight}function reply(text){if(busy)return;busy=true;add('user',text);status('Finding a starting point…','Working · sample response');$('task-title').textContent='Putting together a suggestion';$('task-detail').textContent='Hope is preparing a response for your conversation.';$('task-status').textContent='In progress · simulated';timers.push(setTimeout(()=>{add('assistant','Keep it simple: choose a nearby route, leave your headphones at home, and give yourself thirty minutes with no schedule. Want to plan the rest of the day?');status(active&&!muted?'Listening':muted?'Microphone muted':'Ready when you are',active?'Demo session · no microphone access':'Microphone off · simulated audio');$('task-title').textContent='Suggestion ready';$('task-detail').textContent='Hope’s reply is in your conversation.';$('task-status').textContent='Completed · simulated';busy=false},1400))}function begin(){active=true;muted=false;$('start').textContent='Mute';$('start').setAttribute('aria-pressed','false');$('end').hidden=false;status('Listening','Demo session · no microphone access');timers.push(setTimeout(()=>{if(active&&!muted)reply('Let’s start with a morning walk.')},2000))}$('start').onclick=()=>{if(!active){begin();return}muted=!muted;$('start').textContent=muted?'Unmute':'Mute';$('start').setAttribute('aria-pressed',String(muted));status(muted?'Microphone muted':'Listening','Demo session · no microphone access')};$('end').onclick=()=>{stopTimers();active=false;muted=false;$('start').textContent='Talk to Hope';$('start').removeAttribute('aria-pressed');$('end').hidden=true;status('Conversation ended','Microphone off · sample transcript kept');$('task-status').textContent='Stopped'};function textMode(on){$('voice-controls').hidden=on;$('composer').hidden=!on;$('voice-back').hidden=!on;if(on){muted=active;status('Type to Hope','Voice input off');$('input').focus()}else status(active?'Microphone muted':'Ready when you are','Microphone off · simulated audio')}$('text').onclick=()=>textMode(true);$('voice-back').onclick=()=>{textMode(false);if(active)$('start').textContent='Unmute'};$('composer').onsubmit=e=>{e.preventDefault();const val=$('input').value.trim();if(val&&!busy){$('input').value='';reply(val)}};$('suggestion').onclick=()=>reply('Let’s start with a morning walk.');function dark(on){$('phone').classList.toggle('dark',on);$('dark-switch').checked=on;$('theme').textContent=on?'Preview light appearance':'Preview dark appearance'}$('theme').onclick=()=>dark(!$('phone').classList.contains('dark'));$('dark-switch').onchange=e=>dark(e.target.checked);$('voice').onchange=e=>$('settings-note').textContent='Demo voice set to '+e.target.value+'.';$('signout').onclick=()=>{$('end').click();$('settings-note').textContent='Demo signed out. No real account was changed. Reload to reset the sample.'};document.querySelector('.tabs').addEventListener('keydown',e=>{if(!['ArrowLeft','ArrowRight','Home','End'].includes(e.key))return;e.preventDefault();let tabs=[...document.querySelectorAll('.tab')],i=tabs.indexOf(document.activeElement);i=e.key==='Home'?0:e.key==='End'?tabs.length-1:(i+(e.key==='ArrowRight'?1:-1)+tabs.length)%tabs.length;tabs[i].focus();tabs[i].click()});</script></body></html>
+1
View File
@@ -0,0 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Hope — Three new directions</title><style>*{box-sizing:border-box}body{margin:0;background:#f4f6f7;color:#20313b;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}main{max-width:1360px;margin:auto;padding:54px 40px}header{display:flex;align-items:start;justify-content:space-between;gap:30px;margin-bottom:38px}h1{font-size:48px;letter-spacing:-.035em;margin:12px 0 16px;line-height:1.08;font-weight:600}p{line-height:1.6;margin:0;max-width:64ch;color:#51616b}.wordmark{font-size:19px;font-weight:700}.badge{border:1px solid #c3cdd3;padding:10px 16px;border-radius:8px;font-size:13px;white-space:nowrap}.options{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:28px}.option{text-decoration:none;color:inherit;display:block}.preview{background:#e5ecf2;aspect-ratio:410/830;overflow:hidden;border-radius:16px;margin-bottom:22px}.preview img{width:100%;height:100%;object-fit:cover;display:block}.option h2{font-size:25px;letter-spacing:-.02em;margin:0 0 10px}.option p{font-size:15px;line-height:1.6}.open{display:inline-flex;align-items:center;gap:14px;min-height:44px;font-weight:600;font-size:14px;margin-top:15px;color:#235fc0}.option:focus-visible{outline:3px solid #235fc0;outline-offset:8px}.recommendation{margin-top:42px;padding-top:24px;border-top:1px solid #cbd5da;display:flex;gap:38px;align-items:baseline}.recommendation strong{font-size:18px;min-width:190px}.footer{font-size:13px;margin-top:28px;color:#51616b}@media(min-width:1100px){.preview{max-height:630px;aspect-ratio:390/804;margin-left:auto;margin-right:auto}}@media(max-width:760px){main{padding:30px 20px}header{display:block}h1{font-size:36px}.badge{display:inline-block;margin-top:20px}.options{grid-template-columns:1fr;gap:38px}.preview{max-width:390px;margin-left:auto;margin-right:auto}.recommendation{display:block}.recommendation p{margin-top:12px}}@media(prefers-reduced-motion:reduce){*{scroll-behavior:auto}}</style></head><body><main><header><div><div class="wordmark">Hope / design exploration</div><h1>Three ways to feel at home.</h1><p>Three different interaction models, not three color swaps. Each includes a new app icon and an interactive iPhone-sized demonstration.</p></div><div class="badge">HTML prototypes · no live services</div></header><section class="options" aria-label="Three design options"><a class="option" href="clear.html"><div class="preview"><img src="clear-phone.png" alt="Clear concept: a bright native-feeling Hope interface" width="390" height="804"></div><h2>Clear</h2><p>Bright, familiar, and practical. A clear starting point, compact voice controls, and recent conversations.</p><span class="open">Explore Clear <span aria-hidden="true">↗</span></span></a><a class="option" href="signal.html"><div class="preview"><img src="signal-phone.png" alt="Signal concept: a dark focused voice interface" width="390" height="804"></div><h2>Signal</h2><p>Voice comes first. A low-light audio interface with precise feedback and a waveform instead of an LED matrix.</p><span class="open">Explore Signal <span aria-hidden="true">↗</span></span></a><a class="option" href="gather.html"><div class="preview"><img src="gather-phone.png" alt="Gather concept: a readable green conversation interface" width="390" height="804"></div><h2>Gather</h2><p>The conversation is the canvas. Readable replies, context always visible, and voice one tap away.</p><span class="open">Explore Gather <span aria-hidden="true">↗</span></span></a></section><section class="recommendation"><strong>My pick: Clear.</strong><p>It makes the biggest usability improvement with the least learning. Pick Signal if Hope is mostly a hands-free voice app; pick Gather if you regularly read and type as well as talk. The icon can be chosen independently.</p></section><p class="footer">All conversation data, audio states, progress, and account actions are simulated. Nothing changes the installed iOS app, server, or microphone permissions.</p></main></body></html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 689 KiB

+1
View File
@@ -0,0 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Hope — A softer direction</title><style>*{box-sizing:border-box}body{margin:0;background:linear-gradient(120deg,#f2e8e4,#eee7f4 45%,#ececf7);color:#342a3d;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}main{max-width:1360px;margin:auto;padding:50px 40px}header{max-width:750px;margin-bottom:38px}.brand{font-size:17px;font-weight:600}h1{font-weight:450;font-size:49px;letter-spacing:-.035em;line-height:1.1;margin:18px 0}h1 em{font-family:Georgia,serif;font-weight:400;color:#9464aa}p{font-size:16px;line-height:1.7;color:#685b73;margin:0}.options{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:34px}.option{display:block;text-decoration:none;color:inherit}.preview{height:650px;display:flex;justify-content:center;overflow:hidden;margin-bottom:23px}.preview img{height:100%;width:auto;max-width:100%;object-fit:contain}.icon-row{display:flex;gap:10px;align-items:center;margin:14px 0 4px;font-size:12px;color:#685b73}.icon-row img{width:38px;height:38px;border-radius:9px}.option h2{font-weight:500;font-size:27px;letter-spacing:-.02em;margin:0 0 11px}.option p{font-size:14px}.open{display:inline-flex;align-items:center;min-height:44px;color:#815099;font-size:14px;font-weight:600;margin-top:12px}.option:focus-visible{outline:3px solid #815099;outline-offset:7px}.note{display:flex;gap:35px;border-top:1px solid #d7c9e0;margin-top:35px;padding-top:24px}.note strong{font-size:17px;font-weight:500;white-space:nowrap}.note p{font-size:14px;max-width:75ch}.footer{font-size:12px;margin-top:25px}@media(max-width:850px){main{padding:30px 20px}.options{gap:20px}.preview{height:510px}h1{font-size:40px}}@media(max-width:680px){.options{grid-template-columns:1fr;gap:40px}.preview{height:690px;max-width:390px;margin:auto auto 22px}h1{font-size:36px}.note{display:block}.note p{margin-top:10px}.option p{max-width:45ch}}</style></head><body><main><header><div class="brand">hope / a new design exploration</div><h1>A softer space.<br><em>Three fresh possibilities.</em></h1><p>Inspired by your reference: luminous white, pearlescent color, sculptural voice visuals, and lighter controls. Three new interfaces—not variations of the first set.</p></header><section class="options" aria-label="New design directions"><a class="option" href="opal.html"><div class="preview"><img src="opal-phone.png" alt="Opal: luminous white home with a pearlescent sphere"></div><h2>Opal</h2><div class="icon-row"><img src="opal-icon.svg" alt="New Opal app icon">New icon direction</div><p>A luminous home, a reflective pearl, and a personal welcome. The closest to your inspiration, with voice and text sharing one floating composer.</p><span class="open">Try Opal ↗</span></a><a class="option" href="ribbon.html"><div class="preview"><img src="ribbon-phone.png" alt="Ribbon: translucent sculptural waveform and focused voice controls"></div><h2>Ribbon</h2><div class="icon-row"><img src="ribbon-icon.svg" alt="New Ribbon app icon">New icon direction</div><p>A flowing pastel ribbon turns voice into a sculptural listening space. Focused, spacious, and designed around speaking rather than browsing.</p><span class="open">Try Ribbon ↗</span></a><a class="option" href="prism.html"><div class="preview"><img src="prism-phone.png" alt="Prism: a soft conversation interface with pearlescent sculptural forms"></div><h2>Prism</h2><div class="icon-row"><img src="prism-icon.svg" alt="New Prism app icon">New icon direction</div><p>A quiet conversation that unfolds into useful answers. A compact pearlescent identity, readable replies, and a floating voice-and-text composer.</p><span class="open">Try Prism ↗</span></a></section><section class="note"><strong>My pick: Opal.</strong><p>It captures the reference’s personality most directly. Ribbon is the strongest voice-first option; Prism gives the most space to reading replies. Each demo includes a different replacement app icon, shown large and small.</p></section><p class="footer">Interactive HTML concepts only. All replies and voice states are simulated. No microphone access, live account actions, or changes to the installed app.</p></main></body></html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" role="img" aria-label="Hope: two pearlescent circular speech forms"><defs><linearGradient id="pearl" x1="0" y1="0" x2="1" y2="1"><stop stop-color="white"/><stop offset=".4" stop-color="#f2ddec"/><stop offset=".7" stop-color="#dbe8f8"/><stop offset="1" stop-color="#cbb7eb"/></linearGradient></defs><rect width="100" height="100" rx="23" fill="#9b7fbe"/><circle cx="40" cy="42" r="25" fill="url(#pearl)"/><path d="m23 56-3 16 16-9" fill="url(#pearl)"/><circle cx="63" cy="58" r="23" fill="url(#pearl)" stroke="#9b7fbe" stroke-width="2"/><path d="m70 77 13 9-2-17" fill="url(#pearl)"/><path d="M21 39C23 28 31 22 42 21M46 57C46 46 53 39 63 38" stroke="#fff" stroke-width="2" stroke-linecap="round" opacity=".9" fill="none"/><path d="M55 23C69 34 65 53 52 63" stroke="#b5a2d1" fill="none" opacity=".7"/></svg>

After

Width:  |  Height:  |  Size: 868 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 284 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

+44
View File
@@ -0,0 +1,44 @@
<!doctype html>
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="color-scheme" content="light"><title>Hope · Opal / Pink Persona</title><style>
:root{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;color:#302b40;background:#eeeaf7;--ink:#302b40;--muted:#6e657c;--violet:#7453ab;--pink:#f8edf2;--lilac:#f1edfa;--ice:#eaf4fb}*{box-sizing:border-box}body{margin:0}button,input,select{font:inherit}button,a,input,select{-webkit-tap-highlight-color:transparent}button{cursor:pointer;color:inherit;border:0;min-width:44px;min-height:44px;background:none}button:hover{background-color:#f2eef8}button:active{transform:scale(.97)}button:focus-visible,a:focus-visible,input:focus-visible,select:focus-visible{outline:3px solid #8763bd;outline-offset:4px}a{color:inherit}button,select{transition:background .18s,transform .18s}[hidden]{display:none!important}.layout{min-height:100vh;max-width:1150px;margin:auto;display:grid;grid-template-columns:1fr 414px;gap:115px;align-items:center;padding:58px 48px}.presentation{max-width:430px}.back-link{display:inline-flex;min-height:44px;align-items:center;gap:10px;text-decoration:none;font-size:13px;color:#675d79;margin-bottom:37px}.concept{font-size:13px;color:#675d79;display:flex;gap:10px;align-items:center}.concept:before{content:"";height:7px;width:7px;border-radius:50%;background:#a281c2}.presentation h1{font-size:82px;font-weight:400;letter-spacing:-.04em;line-height:1;margin:19px 0 23px}.lead{font-size:23px;letter-spacing:-.025em;line-height:1.5;max-width:25ch;margin:0 0 35px}.notes{padding:0;list-style:none;margin:0}.notes li{padding:18px 0;border-top:1px solid #d8d0e6;font-size:14px;line-height:1.6;color:#675d79}.notes strong{display:block;font-weight:550;font-size:15px;color:#302b40;margin-bottom:3px}.identity{display:flex;align-items:center;gap:24px;margin-top:29px}.icon-large{width:100px;height:100px;filter:drop-shadow(0 8px 12px #64508118)}.icon-small{width:32px;height:32px}.identity p{font-size:12px;color:#675d79;line-height:1.6;margin:8px 0 0}.demo-note{font-size:12px;line-height:1.75;color:#675d79;margin-top:28px;max-width:43ch}.device{width:414px;padding:11px;background:#faf9fd;border-radius:53px;box-shadow:0 28px 65px #5e4f7c20,0 0 0 1px #ffffffaa,inset 0 0 0 2px #e8e3ed}.screen{width:390px;height:800px;border-radius:43px;background:#fff;overflow:hidden;position:relative;isolation:isolate;box-shadow:0 0 0 1px #ded9e6}.statusbar{height:52px;display:flex;align-items:center;justify-content:space-between;padding:0 27px;font-size:14px;font-weight:600;position:relative}.island{width:110px;height:29px;border-radius:30px;background:#201d26;position:absolute;left:50%;top:10px;transform:translateX(-50%)}.status-icons{display:flex;gap:5px;align-items:center}.status-icons svg{width:15px;height:15px}.status-icons .battery{width:23px}.app-header{height:66px;display:flex;align-items:center;padding:0 21px;gap:8px}.brand{display:flex;align-items:center;gap:8px;margin-right:auto;font-size:21px;font-weight:530;letter-spacing:-.03em}.brand svg{width:28px;height:28px}.round-button{display:grid;place-items:center;border-radius:50%;width:44px;height:44px}.round-button svg,.glyph{width:21px;height:21px;fill:none;stroke:currentColor;stroke-width:1.65;stroke-linecap:round;stroke-linejoin:round}.app-header .round-button{color:#7b708b}.content{height:552px;overflow-y:auto;scrollbar-width:thin;padding:0 27px}.home{text-align:center;padding-top:26px}.greeting{font-size:32px;line-height:1.24;letter-spacing:-.035em;font-weight:400;margin:0}.greeting em{font-family:Georgia,serif;font-weight:400}.welcome-copy{color:var(--muted);font-size:13px;margin:15px 0 0;line-height:1.6}.pearl-wrap{width:240px;height:210px;margin:8px auto 0;position:relative}.pearl{width:100%;height:100%;overflow:visible}.pearl-shadow{position:absolute;width:120px;height:8px;bottom:6px;left:calc(50% - 60px);background:#c9c0df;opacity:.22;filter:blur(8px);border-radius:50%}.voice-start{display:flex;gap:10px;align-items:center;justify-content:center;margin:5px auto 0;font-size:14px;font-weight:500;padding:0 17px 0 7px;border-radius:40px;background:#faf7fc;min-height:52px}.mic-halo{width:39px;height:39px;display:grid;place-items:center;border-radius:50%;background:radial-gradient(circle at 35% 20%,#fff 0,#eee1f5 60%,#eadff6 100%);box-shadow:0 0 0 5px #f8f2fb;color:#775393}.mic-halo svg{width:19px}.prompts{display:flex;flex-wrap:wrap;justify-content:center;gap:8px;margin-top:23px}.prompt{font-size:12px;border-radius:30px;padding:0 15px;min-height:44px;color:#63586f}.prompt:nth-child(1){background:var(--pink)}.prompt:nth-child(2){background:var(--lilac)}.prompt:nth-child(3){background:var(--ice)}.composer-zone{position:absolute;bottom:27px;left:19px;right:19px;z-index:2}.composer{display:flex;align-items:center;height:64px;padding:8px 9px 8px 19px;border-radius:34px;background:#fff;box-shadow:0 5px 22px #69587814,0 1px 4px #69587812;gap:5px}.composer input{min-width:0;flex:1;border:0;outline:0;background:none;font-size:14px;color:var(--ink);height:44px}.composer input::placeholder{color:#756b81}.composer input:focus-visible{outline:0}.composer:focus-within{box-Line truncated
@media(max-width:1050px){.layout{gap:55px;padding:40px 30px}.presentation h1{font-size:70px}.lead{font-size:21px}}@media(max-width:780px){.layout{display:flex;flex-direction:column;padding:30px 20px;gap:35px}.presentation{width:100%;max-width:414px}.presentation h1{font-size:56px;margin:12px 0 14px}.back-link{margin-bottom:20px}.lead{font-size:19px;margin-bottom:20px;max-width:33ch}.notes{display:none}.identity{margin-top:20px}.icon-large{width:64px;height:64px}.demo-note{margin-top:18px}.device-wrap{max-width:100%}}@media(max-width:440px){body{background:#fff}.layout{padding:0;gap:0}.presentation,.device-caption{display:none}.device{width:100vw;padding:0;border-radius:0;background:#fff;box-shadow:none}.screen{width:100%;height:100svh;min-height:760px;border-radius:0;box-shadow:none}.content{height:calc(100% - 248px)}.home{padding-top:20px}.composer-zone{bottom:max(27px,env(safe-area-inset-bottom))}.statusbar{padding-left:29px;padding-right:29px}.home-indicator{bottom:8px}.live{bottom:21px}}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation:none!important;transition:none!important;scroll-behavior:auto!important}}
:root{background:#f6eaf0;--violet:#a64270;--pink:#faedf3;--lilac:#f8eef4;--ice:#f7eff4}.layout{background:radial-gradient(ellipse at 80% 20%,#fff9,transparent 55%)}.screen{background:#fffdfd}.greeting em,.live-state,.back,.thread-title{color:#a64270}.concept:before{background:#d17ba0}.prompt{background:#f9edf3!important;color:#7c3e59}.mic-button,.send-button{background:#f4dce8!important;color:#984269}.voice-start{background:#fcf1f6}.mic-halo{background:radial-gradient(circle,#f7e0eb,#fff5fa)}.state-dot{background:#c75e8d}.live-controls .listen{background:#f6deea!important}.live{background:#fffdfd!important}.persona-stage{height:210px;margin:18px auto 15px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px}.persona-panel{width:184px;height:184px;border-radius:16px;background:#fff2f7;border:1px solid #f2d9e5;overflow:hidden;flex-shrink:0}.persona{display:block;width:100%;height:100%}.persona-caption{font-size:11px;color:#975875}.live-persona{width:178px;height:178px;margin:18px auto 21px}.live h2{margin-top:12px}.preview-states{display:flex;gap:6px;flex-wrap:wrap;margin:20px 0}.preview-states button{border:1px solid #e6bfd0;border-radius:8px;background:#fff9fc;padding:0 12px;min-height:44px;font-size:12px;color:#8d3c60}.preview-states button[aria-pressed=true]{background:#a64270;border-color:#a64270;color:#fff}.demo-note{margin-top:18px}.persona-note{font-size:12px;line-height:1.6;color:#806172}.presentation h1{font-size:72px}.live-log{min-height:68px}button:focus-visible,a:focus-visible,input:focus-visible,select:focus-visible{outline-color:#a64270}@media(max-width:440px){.persona-stage{margin-top:20px;margin-bottom:15px}.live-persona{width:172px;height:172px}}@media(prefers-reduced-motion:reduce){.persona{transition:none}}
</style></head><body>
<svg width="0" height="0" aria-hidden="true" style="position:absolute"><defs>
<linearGradient id="opal-fill" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#fef7fc" stop-opacity=".75"/><stop offset=".26" stop-color="#eae4ff" stop-opacity=".35"/><stop offset=".57" stop-color="#fff" stop-opacity=".05"/><stop offset=".79" stop-color="#d8edf9" stop-opacity=".45"/><stop offset="1" stop-color="#e4d7f4" stop-opacity=".8"/></linearGradient>
<radialGradient id="pearl-core" cx="40%" cy="30%" r="74%"><stop stop-color="white" stop-opacity=".05"/><stop offset=".54" stop-color="#fff" stop-opacity=".02"/><stop offset=".79" stop-color="#e2daf5" stop-opacity=".3"/><stop offset=".92" stop-color="#e2d1ed" stop-opacity=".65"/><stop offset=".98" stop-color="#faf6fd"/><stop offset="1" stop-color="#bdb2d8" stop-opacity=".6"/></radialGradient>
<linearGradient id="rim" x1="0" y1="1" x2="1" y2="0"><stop stop-color="#e7c9e7"/><stop offset=".24" stop-color="#fff"/><stop offset=".42" stop-color="#c3d4ed"/><stop offset=".68" stop-color="#fff"/><stop offset=".86" stop-color="#dcc6ea"/><stop offset="1" stop-color="#f8e8f7"/></linearGradient>
<linearGradient id="pink-reflection" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#e4c1dd" stop-opacity=".8"/><stop offset=".35" stop-color="#f8e6f1" stop-opacity=".6"/><stop offset=".7" stop-color="#fff" stop-opacity="0"/><stop offset="1" stop-color="#bcade1" stop-opacity=".7"/></linearGradient>
<linearGradient id="blue-reflection" x1="1" y1="0" x2="0" y2="1"><stop stop-color="#d0e9f8" stop-opacity=".1"/><stop offset=".5" stop-color="#b7d9f0" stop-opacity=".6"/><stop offset=".78" stop-color="#e2d3f5" stop-opacity=".3"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></linearGradient>
<linearGradient id="shine" x1="0" y1="0" x2="0" y2="1"><stop stop-color="#fff" stop-opacity=".95"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></linearGradient><filter id="soft"><feGaussianBlur stdDeviation="2.7"/></filter><filter id="soft-light"><feGaussianBlur stdDeviation=".6"/></filter>
<symbol id="pearl-art" viewBox="0 0 280 280"><circle cx="140" cy="136" r="110" fill="url(#opal-fill)"/><circle cx="140" cy="136" r="110" fill="url(#pearl-core)"/>
<path d="M62 61C91 25 142 16 182 37C132 26 106 52 99 93C88 143 74 166 45 175C33 135 36 91 62 61Z" fill="url(#pink-reflection)" filter="url(#soft)"/>
<path d="M205 58C240 91 254 152 229 196C211 226 171 247 128 244C194 227 179 189 201 165C226 138 239 105 205 58Z" fill="url(#blue-reflection)"/>
<path d="M50 92C76 32 156 22 205 64C144 23 106 54 99 104C90 155 59 189 45 166C62 175 86 139 89 99C91 62 117 36 150 36C111 24 68 46 50 92Z" fill="url(#shine)" opacity=".87"/>
<path d="M47 163C70 182 105 134 126 112C152 85 181 84 213 102C194 95 174 100 155 114C120 140 96 189 68 190C58 187 52 178 47 163Z" fill="url(#pink-reflection)" opacity=".62" filter="url(#soft)"/>
<path d="M64 187C110 218 174 121 218 141C173 136 142 222 101 224C82 221 71 207 64 187Z" fill="url(#blue-reflection)" opacity=".63"/>
<path d="M84 223C142 250 196 221 223 181" fill="none" stroke="white" stroke-width="3" opacity=".8" filter="url(#soft-light)"/>
<circle cx="140" cy="136" r="110" fill="none" stroke="url(#rim)" stroke-width="1.6"/><circle cx="140" cy="136" r="106.5" fill="none" stroke="white" stroke-width=".8" opacity=".8"/>
<path d="M40 106C47 75 69 49 95 39" fill="none" stroke="white" stroke-width="4" stroke-linecap="round" opacity=".85"/><path d="M167 31C209 40 239 73 247 111" fill="none" stroke="#f1d9ee" stroke-width="2" opacity=".8"/><path d="M240 173C228 213 194 240 153 245" fill="none" stroke="#d7daf6" stroke-width="2.2"/><ellipse cx="77" cy="69" rx="6" ry="14" transform="rotate(40 77 69)" fill="#fff" opacity=".9" filter="url(#soft)"/>
</symbol>
<linearGradient id="icon-pearl" x1="0" y1="0" x2="1" y2="1"><stop stop-color="white"/><stop offset=".4" stop-color="#f2ddec"/><stop offset=".7" stop-color="#dbe8f8"/><stop offset="1" stop-color="#cbb7eb"/></linearGradient>
<symbol id="app-icon" viewBox="0 0 100 100"><rect width="100" height="100" rx="23" fill="#9b7fbe"/><circle cx="40" cy="42" r="25" fill="url(#icon-pearl)"/><path d="m23 56-3 16 16-9" fill="url(#icon-pearl)"/><circle cx="63" cy="58" r="23" fill="url(#icon-pearl)" stroke="#9b7fbe" stroke-width="2"/><path d="m70 77 13 9-2-17" fill="url(#icon-pearl)"/><path d="M21 39C23 28 31 22 42 21M46 57C46 46 53 39 63 38" stroke="#fff" stroke-width="2" stroke-linecap="round" opacity=".9" fill="none"/><path d="M55 23C69 34 65 53 52 63" stroke="#b5a2d1" fill="none" opacity=".7"/></symbol>
<symbol id="brand-mark" viewBox="0 0 32 32"><circle cx="13" cy="13" r="9" fill="#d9c9ec"/><path d="m6 18-1 6 6-4" fill="#d9c9ec"/><circle cx="21" cy="21" r="8" fill="#eddef0" stroke="white" stroke-width="1.5"/><path d="m24 26 5 4-1-6" fill="#eddef0"/></symbol>
<symbol id="mic" viewBox="0 0 24 24"><rect x="9" y="3" width="6" height="12" rx="3"/><path d="M5 11v2a7 7 0 0 0 14 0v-2M12 20v2M8 22h8"/></symbol><symbol id="mute" viewBox="0 0 24 24"><path d="m3 3 18 18M9 9v3a3 3 0 0 0 5 2M9 5a3 3 0 0 1 6 0v6M5 11v2a7 7 0 0 0 12 5M19 11v2M12 20v2"/></symbol><symbol id="history" viewBox="0 0 24 24"><path d="M4 8a9 9 0 1 1-1 7M4 3v5h5M12 7v5l3 2"/></symbol><symbol id="settings" viewBox="0 0 24 24"><path d="M4 7h16M4 17h16"/><circle cx="9" cy="7" r="3" fill="white"/><circle cx="16" cy="17" r="3" fill="white"/></symbol><symbol id="arrow" viewBox="0 0 24 24"><path d="M12 19V5m-6 6 6-6 6 6"/></symbol><symbol id="back" viewBox="0 0 24 24"><path d="m14 6-6 6 6 6"/></symbol><symbol id="chevron" viewBox="0 0 24 24"><path d="m9 6 6 6-6 6"/></symbol><symbol id="chat" viewBox="0 0 24 24"><path d="M20 11a8 8 0 0 1-8 8 9 9 0 0 1-4-1l-5 3 1-6a8 8 0 1 1 16-4Z"/></symbol><symbol id="end" viewBox="0 0 24 24"><path d="M5 16v-4h14v4M3 12c4-5 14-5 18 0"/></symbol>
</defs></svg>
<main class="layout"><aside class="presentation" aria-label="Design direction"><a class="back-link" href="new-index.html">← Explore the new directions</a><div class="concept">Hope · A new direction</div><h1>OPAL<span style="display:block;font-size:27px;margin-top:15px;letter-spacing:-.02em;color:#a64270">Pink persona</span></h1><p class="lead">A little space to think.<br>The familiar agent, in pink.</p><ul class="notes"><li><strong>The same presence as the web.</strong>A square, 21 × 21 reactive dot matrix replaces the pearl. Soft pink at rest; a brighter bloom when Hope speaks.</li><li><strong>The conversation has room.</strong>A luminous white canvas. A personal greeting. Everyday prompts that don’t compete for attention.</li><li><strong>Always within reach.</strong>One floating composer for a thought in text or a conversation out loud. Voice opens into a focused, uncluttered space.</li></ul><div class="identity"><svg class="icon-large" role="img" aria-label="Hope icon, two overlapping pearlescent circular speech forms on violet"><use href="#app-icon"/></svg><div><svg class="icon-small" role="img" aria-label="Hope icon at 32 pixels"><use href="#app-icon"/></svg><p>Opal’s icon stays separate.<br>This preview changes the in-app persona.</p></div></div><div class="preview-states" aria-label="Preview persona states"><button data-persona-state="idle" aria-pressed="true">Ready</button><button data-persona-state="listening" aria-pressed="false">Listening</button><button data-persona-state="working" aria-pressed="false">Working</button><button data-persona-state="speaking" aria-pressed="false">Speaking</button><button data-persona-state="muted" aria-pressed="false">Muted</button></div><p class="persona-note">Preview a state above, or tap Let’s talk to see the full simulated conversation. Pink intensity and dot size follow the same reactive bloom as the web UI.</p><p class="demo-note">Interactive design study. All conversations are simulated and stay on this page. No microphone, audio, network, or account access.</p></aside>
<section class="device-wrap" aria-label="Interactive Hope phone"><div class="device"><div class="screen" id="screen"><div class="statusbar" aria-hidden="true"><span>9:41</span><span class="island"></span><div class="status-icons"><svg viewBox="0 0 20 20" fill="currentColor"><rect x="1" y="12" width="3" height="5" rx="1"/><rect x="6" y="9" width="3" height="8" rx="1"/><rect x="11" y="6" width="3" height="11" rx="1"/><rect x="16" y="3" width="3" height="14" rx="1"/></svg><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 9a14 14 0 0 1 18 0M6 12a9 9 0 0 1 12 0M9 15a4 4 0 0 1 6 0"/><circle cx="12" cy="18" r="1" fill="currentColor"/></svg><svg class="battery" viewBox="0 0 25 16" fill="none" stroke="currentColor"><rect x="1" y="2" width="20" height="12" rx="3"/><rect x="3" y="4" width="16" height="8" rx="1" fill="currentColor"/><path d="M23 6v4" stroke-width="2"/></svg></div></div>
<header class="app-header"><div class="brand"><svg aria-hidden="true"><use href="#brand-mark"/></svg>hope</div><button class="round-button" id="history-button" aria-label="Open history"><svg class="glyph"><use href="#history"/></svg></button><button class="round-button" id="settings-button" aria-label="Open settings"><svg class="glyph"><use href="#settings"/></svg></button></header>
<div class="content" id="content" tabindex="-1"><section class="home"><h2 class="greeting">A little room for you,<br><em>Shane.</em></h2><p class="welcome-copy">No perfect words needed. Start anywhere.</p><div class="persona-stage"><div class="persona-panel"><canvas class="persona" width="440" height="440" aria-hidden="true"></canvas></div><span class="persona-caption" id="home-persona-caption">Ready when you are</span></div><button class="voice-start" id="start-voice"><span class="mic-halo"><svg class="glyph"><use href="#mic"/></svg></span>Let’s talk</button><div class="prompts"><button class="prompt" data-prompt="day">Talk through my day</button><button class="prompt" data-prompt="idea">Explore an idea</button><button class="prompt" data-prompt="plan">Make a plan</button></div></section></div>
<div class="composer-zone"><form class="composer" id="composer"><label for="message" class="sr-only">Message Hope</label><input id="message" placeholder="What’s on your mind?" maxlength="2000" autocomplete="off"><button type="submit" class="send-button" id="send-message" aria-label="Send message" hidden><svg class="glyph"><use href="#arrow"/></svg></button><button type="button" class="mic-button" id="composer-mic" aria-label="Start voice conversation"><svg class="glyph"><use href="#mic"/></svg></button></form><p class="simulation">Local demo · Your microphone stays off</p></div>
<section class="live" id="live" aria-label="Simulated voice conversation" hidden><div class="live-top"><strong>With Hope</strong><span>Simulated voice</span></div><div class="persona-panel live-persona"><canvas class="persona" width="440" height="440" aria-hidden="true"></canvas></div><h2 id="live-heading">I’m here. Take your time.</h2><div class="live-state" role="status"><span class="state-dot"></span><span id="voice-state">Listening</span></div><div class="elapsed" id="elapsed">00:00</div><div class="live-log" id="live-log" role="log" aria-label="Voice transcript" aria-live="polite"></div><div class="live-controls"><div class="control-group"><button id="mute-button" aria-label="Mute simulated microphone" aria-pressed="false"><svg class="glyph"><use href="#mute"/></svg></button><span id="mute-label">Mute</span></div><div class="control-group"><button class="listen" id="voice-turn" aria-label="Try a simulated voice turn"><svg class="glyph"><use href="#mic"/></svg></button><span>Speak again</span></div><div class="control-group"><button class="end" id="end-call" aria-label="End conversation"><svg class="glyph"><use href="#end"/></svg></button><span>End</span></div></div><p class="live-note">No audio is recorded or played</p></section><div class="home-indicator" aria-hidden="true"></div><div id="announce" class="sr-only" role="status"></div></div></div><p class="device-caption">OPAL · A luminous space for conversation</p></section></main>
<script>
(()=>{'use strict';const $=id=>document.getElementById(id),content=$('content'),homeMarkup=content.innerHTML,live=$('live'),field=$('message');let page='home',voice='Ava',spoken=true,muted=false,interval=null,timers=[],seconds=0,active=null;const history=[{title:'A little breathing room',when:'Today · 9:12 am',messages:[['You','Today feels a little full. I don’t know where to start.'],['Hope','Let’s make it smaller. What’s one thing that needs your attention, and one thing that can wait?']]},{title:'An idea for the weekend',when:'Yesterday · 6:40 pm',messages:[['You','I’d love to spend a day by the sea.'],['Hope','A morning train, a long walk, and lunch somewhere unhurried. Want to start with a place or a date?']]}];const prompts={day:['Talk through my day','What’s been taking up the most space in your day? We can start there.'],idea:['Explore an idea','Tell me the rough version. It doesn’t need to make sense yet.'],plan:['Make a plan','What would you like to make room for? We can find a small first step.']};const icon=name=>'<svg class="glyph" aria-hidden="true"><use href="#'+name+'"/></svg>';const announce=text=>$('announce').textContent=text;function cancel(){timers.forEach(clearTimeout);timers=[]}function schedule(fn,time){timers.push(setTimeout(fn,time))}function show(markup,next){page=next;content.innerHTML=markup;content.scrollTop=0;content.focus({preventScroll:true})}function home(){active=null;show(homeMarkup,'home');field.placeholder='What’s on your mind?'}function back(){return '<button class="back" id="back-home">'+icon('back')+'Back to your space</button>'}function message(target,role,text){const el=document.createElement('div');el.className='message '+(role==='You'?'you':'hope');const label=document.createElement('small');label.textContent=role;const p=document.createElement('p');p.textContent=text;el.append(label,p);target.append(el)}function renderThread(item){active=item;show(back()+'<h2 class="thread-title" id="thread-title"></h2><div class="transcript" id="transcript" role="log" aria-live="polite" aria-label="Conversation transcript"></div>','thread');$('thread-title').textContent=item.title;item.messages.forEach(m=>message($('transcript'),...m));field.placeholder='Keep the thought going…'}function newThread(title,first,reply){const item={title,when:'Just now · Demo',messages:[['You',first],['Hope',reply]]};history.unshift(item);renderThread(item)}function showHistory(){show(back()+'<h2 class="page-heading">Your conversations</h2><p class="page-description">Thoughts you can come back to.<br>Sample threads and your local demo conversations.</p><div class="history-label">Recently</div><div id="history-list"></div>','history');history.forEach((item,index)=>{const button=document.createElement('button');button.className='history-row';button.dataset.thread=index;button.innerHTML='<span class="history-symbol">'+icon('chat')+'</span><span><strong></strong><small></small></span>'+icon('chevron');button.querySelector('strong').textContent=item.title;button.querySelector('small').textContent=item.when;$('history-list').append(button)})}function settings(){show(back()+'<h2 class="page-heading">Make yourself at home.</h2><p class="page-description">A few small choices for your conversations.</p><div class="settings-group"><h3>Conversation</h3><label class="setting"><span>Hope’s voice<small>A preference for this demo</small></span><select id="voice-choice" aria-label="Hope voice"><option>Ava</option><option>Emma</option><option>Andrew</option></select></label><label class="setting"><span>Spoken replies<small>No audio plays in this demo</small></span><input type="checkbox" id="spoken"></label></div><div class="settings-group"><h3>Privacy</h3><div class="setting"><span>Just between us<small>Your text stays on this page.<br>No account or microphone is connected.</small></span>'+icon('chat')+'</div></div><button class="settings-save" id="save-settings">Save preferences</button><p class="saved-note" id="saved-note" role="status"></p><p class="settings-footer">Hope · OPAL design study<br>Preferences and conversations reset when you reload.</p>','settings');$('voice-choice').value=voice;$('spoken').checked=spoken}function state(text,heading){$('voice-state').textContent=text;if(heading)$('live-heading').textContent=heading;live.classList.toggle('listening',text==='Listening');announce(text)}function turn(){cancel();if(muted)return;state('Listening','I’m here. Take your time.');$('voice-turn').disabled=true;schedule(()=>{const text='Help me make a little space in my day.';message($('live-log'),'You',text);active.messages.push(['You',text]);state('Thinking','Let’s find a little room.');},1800);schedule(()=>{const text='Choose one thing that can wait. Then give yourself ten minutes with nothing to solve. What would feel good in that little space?';message($('live-log'),'Hope',text);active.messages.push(['Hope',text]);$('live-log').scrollTop=$('live-log').scrollHeight;state(spoken?'HopLine truncated
$('history-button').onclick=showHistory;$('settings-button').onclick=settings;$('composer-mic').onclick=startVoice;content.onclick=e=>{const b=e.target.closest('button');if(!b)return;if(b.id==='back-home')home();if(b.id==='start-voice')startVoice();if(b.dataset.prompt){const p=prompts[b.dataset.prompt];newThread(p[0],p[0],p[1]);field.focus()}if(b.dataset.thread!==undefined)renderThread(history[Number(b.dataset.thread)]);if(b.id==='save-settings'){voice=$('voice-choice').value;spoken=$('spoken').checked;$('saved-note').textContent='Preferences saved for this demo.';announce('Preferences saved')}};field.oninput=()=>{$('send-message').hidden=!field.value.trim()};$('composer').onsubmit=e=>{e.preventDefault();const text=field.value.trim();if(!text)return;const reply='Let’s take it one thought at a time. What feels most important about that to you?';if(page!=='thread')newThread('A thought to talk through',text,reply);else{active.messages.push(['You',text],['Hope',reply]);message($('transcript'),'You',text);message($('transcript'),'Hope',reply);content.scrollTop=content.scrollHeight}field.value='';$('send-message').hidden=true;field.focus();announce('Local message added. Hope’s reply is a prewritten example.')};$('mute-button').onclick=()=>{muted=!muted;cancel();$('mute-button').setAttribute('aria-pressed',String(muted));$('mute-button').setAttribute('aria-label',muted?'Unmute simulated microphone':'Mute simulated microphone');$('mute-label').textContent=muted?'Unmute':'Mute';$('voice-turn').disabled=muted;state(muted?'Microphone muted · simulation paused':'Listening',muted?'A quiet moment.':'Ready when you are.');if(!muted)turn()};$('voice-turn').onclick=turn;$('end-call').onclick=endVoice;document.addEventListener('keydown',e=>{if(e.key==='Escape'){if(!live.hidden)endVoice();else if(page!=='home')home()}});live.addEventListener('keydown',e=>{if(e.key!=='Tab')return;const buttons=[...live.querySelectorAll('button:not(:disabled)')];if(e.shiftKey&&document.activeElement===buttons[0]){e.preventDefault();buttons.at(-1).focus()}else if(!e.shiftKey&&document.activeElement===buttons.at(-1)){e.preventDefault();buttons[0].focus()}});
})();
</script>
<script>
(()=>{const reduced=matchMedia('(prefers-reduced-motion: reduce)');let mode='idle',manual=false,frame=0;const captions={idle:'Ready when you are',listening:'Listening · demo',working:'Working on your thought · demo',speaking:'Hope is speaking · demo',muted:'Microphone muted · demo'};function set(next){mode=next;document.querySelectorAll('[data-persona-state]').forEach(b=>b.setAttribute('aria-pressed',String(b.dataset.personaState===next)));const caption=document.getElementById('home-persona-caption');if(caption)caption.textContent=captions[next];document.querySelectorAll('.persona-panel').forEach(p=>p.dataset.state=next);draw(0)}function draw(t){const phaseTime=reduced.matches?0:t/55;let level=mode==='listening'?.17+.12*Math.sin(t/450):mode==='speaking'?.55+.25*Math.sin(t/240):0;document.querySelectorAll('canvas.persona').forEach(canvas=>{if(canvas.closest('[hidden]'))return;const c=canvas.getContext('2d');c.clearRect(0,0,440,440);for(let r=0;r<21;r++)for(let col=0;col<21;col++){const dx=(col-10)/10.5,dy=(r-10)/10.5,rad=Math.hypot(dx,dy),phase=(Math.sin(r*12.9898+col*78.233)*43758.5453%1)*Math.PI*2;let vis,size=1;if(mode==='idle'||mode==='muted'){vis=(mode==='muted'?.14:.23)-rad*.085}else if(level>.005){const lvl=Math.min(1,level*1.3),falloff=Math.exp(-rad*rad*(2-lvl*1.1)),ripple=.62+.38*Math.sin(phaseTime*.32+phase);vis=falloff*(.35+lvl)*ripple;size=1+(1-rad)*1.4*lvl;if(mode!=='speaking')vis*=.55}else{const breathe=.5+.5*Math.sin(phaseTime*.12+phase);vis=.2-rad*.06+.09*breathe;size=1+(1-rad)*.3}c.globalAlpha=Math.max(.035,Math.min(1,vis));c.fillStyle=mode==='muted'?'#a98998':'#c54d84';c.beginPath();c.arc(30+col*19,30+r*19,2.05*size,0,Math.PI*2);c.fill()}c.globalAlpha=1})}document.querySelectorAll('[data-persona-state]').forEach(b=>b.onclick=()=>{manual=true;set(b.dataset.personaState)});const state=document.getElementById('voice-state');new MutationObserver(()=>{manual=false;const s=state.textContent.toLowerCase();set(s.includes('muted')?'muted':s.includes('speaking')||s.includes('replying')?'speaking':s.includes('thinking')||s.includes('working')||s.includes('finding')?'working':s.includes('listening')?'listening':'idle')}).observe(state,{childList:true,subtree:true,characterData:true});new MutationObserver(()=>{if(document.getElementById('live').hidden){manual=false;set('idle')}}).observe(document.getElementById('live'),{attributes:true,attributeFilter:['hidden']});set('idle');function loop(t){if(!document.hidden&&t-frame>=50){draw(t);frame=t}requestAnimationFrame(loop)}requestAnimationFrame(loop);window.personaPreview=set;
})();
</script></body></html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

+38
View File
@@ -0,0 +1,38 @@
<!doctype html>
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="color-scheme" content="light"><title>Hope · OPAL</title><style>
:root{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;color:#302b40;background:#eeeaf7;--ink:#302b40;--muted:#6e657c;--violet:#7453ab;--pink:#f8edf2;--lilac:#f1edfa;--ice:#eaf4fb}*{box-sizing:border-box}body{margin:0}button,input,select{font:inherit}button,a,input,select{-webkit-tap-highlight-color:transparent}button{cursor:pointer;color:inherit;border:0;min-width:44px;min-height:44px;background:none}button:hover{background-color:#f2eef8}button:active{transform:scale(.97)}button:focus-visible,a:focus-visible,input:focus-visible,select:focus-visible{outline:3px solid #8763bd;outline-offset:4px}a{color:inherit}button,select{transition:background .18s,transform .18s}[hidden]{display:none!important}.layout{min-height:100vh;max-width:1150px;margin:auto;display:grid;grid-template-columns:1fr 414px;gap:115px;align-items:center;padding:58px 48px}.presentation{max-width:430px}.back-link{display:inline-flex;min-height:44px;align-items:center;gap:10px;text-decoration:none;font-size:13px;color:#675d79;margin-bottom:37px}.concept{font-size:13px;color:#675d79;display:flex;gap:10px;align-items:center}.concept:before{content:"";height:7px;width:7px;border-radius:50%;background:#a281c2}.presentation h1{font-size:82px;font-weight:400;letter-spacing:-.04em;line-height:1;margin:19px 0 23px}.lead{font-size:23px;letter-spacing:-.025em;line-height:1.5;max-width:25ch;margin:0 0 35px}.notes{padding:0;list-style:none;margin:0}.notes li{padding:18px 0;border-top:1px solid #d8d0e6;font-size:14px;line-height:1.6;color:#675d79}.notes strong{display:block;font-weight:550;font-size:15px;color:#302b40;margin-bottom:3px}.identity{display:flex;align-items:center;gap:24px;margin-top:29px}.icon-large{width:100px;height:100px;filter:drop-shadow(0 8px 12px #64508118)}.icon-small{width:32px;height:32px}.identity p{font-size:12px;color:#675d79;line-height:1.6;margin:8px 0 0}.demo-note{font-size:12px;line-height:1.75;color:#675d79;margin-top:28px;max-width:43ch}.device{width:414px;padding:11px;background:#faf9fd;border-radius:53px;box-shadow:0 28px 65px #5e4f7c20,0 0 0 1px #ffffffaa,inset 0 0 0 2px #e8e3ed}.screen{width:390px;height:800px;border-radius:43px;background:#fff;overflow:hidden;position:relative;isolation:isolate;box-shadow:0 0 0 1px #ded9e6}.statusbar{height:52px;display:flex;align-items:center;justify-content:space-between;padding:0 27px;font-size:14px;font-weight:600;position:relative}.island{width:110px;height:29px;border-radius:30px;background:#201d26;position:absolute;left:50%;top:10px;transform:translateX(-50%)}.status-icons{display:flex;gap:5px;align-items:center}.status-icons svg{width:15px;height:15px}.status-icons .battery{width:23px}.app-header{height:66px;display:flex;align-items:center;padding:0 21px;gap:8px}.brand{display:flex;align-items:center;gap:8px;margin-right:auto;font-size:21px;font-weight:530;letter-spacing:-.03em}.brand svg{width:28px;height:28px}.round-button{display:grid;place-items:center;border-radius:50%;width:44px;height:44px}.round-button svg,.glyph{width:21px;height:21px;fill:none;stroke:currentColor;stroke-width:1.65;stroke-linecap:round;stroke-linejoin:round}.app-header .round-button{color:#7b708b}.content{height:552px;overflow-y:auto;scrollbar-width:thin;padding:0 27px}.home{text-align:center;padding-top:26px}.greeting{font-size:32px;line-height:1.24;letter-spacing:-.035em;font-weight:400;margin:0}.greeting em{font-family:Georgia,serif;font-weight:400}.welcome-copy{color:var(--muted);font-size:13px;margin:15px 0 0;line-height:1.6}.pearl-wrap{width:240px;height:210px;margin:8px auto 0;position:relative}.pearl{width:100%;height:100%;overflow:visible}.pearl-shadow{position:absolute;width:120px;height:8px;bottom:6px;left:calc(50% - 60px);background:#c9c0df;opacity:.22;filter:blur(8px);border-radius:50%}.voice-start{display:flex;gap:10px;align-items:center;justify-content:center;margin:5px auto 0;font-size:14px;font-weight:500;padding:0 17px 0 7px;border-radius:40px;background:#faf7fc;min-height:52px}.mic-halo{width:39px;height:39px;display:grid;place-items:center;border-radius:50%;background:radial-gradient(circle at 35% 20%,#fff 0,#eee1f5 60%,#eadff6 100%);box-shadow:0 0 0 5px #f8f2fb;color:#775393}.mic-halo svg{width:19px}.prompts{display:flex;flex-wrap:wrap;justify-content:center;gap:8px;margin-top:23px}.prompt{font-size:12px;border-radius:30px;padding:0 15px;min-height:44px;color:#63586f}.prompt:nth-child(1){background:var(--pink)}.prompt:nth-child(2){background:var(--lilac)}.prompt:nth-child(3){background:var(--ice)}.composer-zone{position:absolute;bottom:27px;left:19px;right:19px;z-index:2}.composer{display:flex;align-items:center;height:64px;padding:8px 9px 8px 19px;border-radius:34px;background:#fff;box-shadow:0 5px 22px #69587814,0 1px 4px #69587812;gap:5px}.composer input{min-width:0;flex:1;border:0;outline:0;background:none;font-size:14px;color:var(--ink);height:44px}.composer input::placeholder{color:#756b81}.composer input:focus-visible{outline:0}.composer:focus-within{box-Line truncated
@media(max-width:1050px){.layout{gap:55px;padding:40px 30px}.presentation h1{font-size:70px}.lead{font-size:21px}}@media(max-width:780px){.layout{display:flex;flex-direction:column;padding:30px 20px;gap:35px}.presentation{width:100%;max-width:414px}.presentation h1{font-size:56px;margin:12px 0 14px}.back-link{margin-bottom:20px}.lead{font-size:19px;margin-bottom:20px;max-width:33ch}.notes{display:none}.identity{margin-top:20px}.icon-large{width:64px;height:64px}.demo-note{margin-top:18px}.device-wrap{max-width:100%}}@media(max-width:440px){body{background:#fff}.layout{padding:0;gap:0}.presentation,.device-caption{display:none}.device{width:100vw;padding:0;border-radius:0;background:#fff;box-shadow:none}.screen{width:100%;height:100svh;min-height:760px;border-radius:0;box-shadow:none}.content{height:calc(100% - 248px)}.home{padding-top:20px}.composer-zone{bottom:max(27px,env(safe-area-inset-bottom))}.statusbar{padding-left:29px;padding-right:29px}.home-indicator{bottom:8px}.live{bottom:21px}}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation:none!important;transition:none!important;scroll-behavior:auto!important}}
</style></head><body>
<svg width="0" height="0" aria-hidden="true" style="position:absolute"><defs>
<linearGradient id="opal-fill" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#fef7fc" stop-opacity=".75"/><stop offset=".26" stop-color="#eae4ff" stop-opacity=".35"/><stop offset=".57" stop-color="#fff" stop-opacity=".05"/><stop offset=".79" stop-color="#d8edf9" stop-opacity=".45"/><stop offset="1" stop-color="#e4d7f4" stop-opacity=".8"/></linearGradient>
<radialGradient id="pearl-core" cx="40%" cy="30%" r="74%"><stop stop-color="white" stop-opacity=".05"/><stop offset=".54" stop-color="#fff" stop-opacity=".02"/><stop offset=".79" stop-color="#e2daf5" stop-opacity=".3"/><stop offset=".92" stop-color="#e2d1ed" stop-opacity=".65"/><stop offset=".98" stop-color="#faf6fd"/><stop offset="1" stop-color="#bdb2d8" stop-opacity=".6"/></radialGradient>
<linearGradient id="rim" x1="0" y1="1" x2="1" y2="0"><stop stop-color="#e7c9e7"/><stop offset=".24" stop-color="#fff"/><stop offset=".42" stop-color="#c3d4ed"/><stop offset=".68" stop-color="#fff"/><stop offset=".86" stop-color="#dcc6ea"/><stop offset="1" stop-color="#f8e8f7"/></linearGradient>
<linearGradient id="pink-reflection" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#e4c1dd" stop-opacity=".8"/><stop offset=".35" stop-color="#f8e6f1" stop-opacity=".6"/><stop offset=".7" stop-color="#fff" stop-opacity="0"/><stop offset="1" stop-color="#bcade1" stop-opacity=".7"/></linearGradient>
<linearGradient id="blue-reflection" x1="1" y1="0" x2="0" y2="1"><stop stop-color="#d0e9f8" stop-opacity=".1"/><stop offset=".5" stop-color="#b7d9f0" stop-opacity=".6"/><stop offset=".78" stop-color="#e2d3f5" stop-opacity=".3"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></linearGradient>
<linearGradient id="shine" x1="0" y1="0" x2="0" y2="1"><stop stop-color="#fff" stop-opacity=".95"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></linearGradient><filter id="soft"><feGaussianBlur stdDeviation="2.7"/></filter><filter id="soft-light"><feGaussianBlur stdDeviation=".6"/></filter>
<symbol id="pearl-art" viewBox="0 0 280 280"><circle cx="140" cy="136" r="110" fill="url(#opal-fill)"/><circle cx="140" cy="136" r="110" fill="url(#pearl-core)"/>
<path d="M62 61C91 25 142 16 182 37C132 26 106 52 99 93C88 143 74 166 45 175C33 135 36 91 62 61Z" fill="url(#pink-reflection)" filter="url(#soft)"/>
<path d="M205 58C240 91 254 152 229 196C211 226 171 247 128 244C194 227 179 189 201 165C226 138 239 105 205 58Z" fill="url(#blue-reflection)"/>
<path d="M50 92C76 32 156 22 205 64C144 23 106 54 99 104C90 155 59 189 45 166C62 175 86 139 89 99C91 62 117 36 150 36C111 24 68 46 50 92Z" fill="url(#shine)" opacity=".87"/>
<path d="M47 163C70 182 105 134 126 112C152 85 181 84 213 102C194 95 174 100 155 114C120 140 96 189 68 190C58 187 52 178 47 163Z" fill="url(#pink-reflection)" opacity=".62" filter="url(#soft)"/>
<path d="M64 187C110 218 174 121 218 141C173 136 142 222 101 224C82 221 71 207 64 187Z" fill="url(#blue-reflection)" opacity=".63"/>
<path d="M84 223C142 250 196 221 223 181" fill="none" stroke="white" stroke-width="3" opacity=".8" filter="url(#soft-light)"/>
<circle cx="140" cy="136" r="110" fill="none" stroke="url(#rim)" stroke-width="1.6"/><circle cx="140" cy="136" r="106.5" fill="none" stroke="white" stroke-width=".8" opacity=".8"/>
<path d="M40 106C47 75 69 49 95 39" fill="none" stroke="white" stroke-width="4" stroke-linecap="round" opacity=".85"/><path d="M167 31C209 40 239 73 247 111" fill="none" stroke="#f1d9ee" stroke-width="2" opacity=".8"/><path d="M240 173C228 213 194 240 153 245" fill="none" stroke="#d7daf6" stroke-width="2.2"/><ellipse cx="77" cy="69" rx="6" ry="14" transform="rotate(40 77 69)" fill="#fff" opacity=".9" filter="url(#soft)"/>
</symbol>
<linearGradient id="icon-pearl" x1="0" y1="0" x2="1" y2="1"><stop stop-color="white"/><stop offset=".4" stop-color="#f2ddec"/><stop offset=".7" stop-color="#dbe8f8"/><stop offset="1" stop-color="#cbb7eb"/></linearGradient>
<symbol id="app-icon" viewBox="0 0 100 100"><rect width="100" height="100" rx="23" fill="#9b7fbe"/><circle cx="40" cy="42" r="25" fill="url(#icon-pearl)"/><path d="m23 56-3 16 16-9" fill="url(#icon-pearl)"/><circle cx="63" cy="58" r="23" fill="url(#icon-pearl)" stroke="#9b7fbe" stroke-width="2"/><path d="m70 77 13 9-2-17" fill="url(#icon-pearl)"/><path d="M21 39C23 28 31 22 42 21M46 57C46 46 53 39 63 38" stroke="#fff" stroke-width="2" stroke-linecap="round" opacity=".9" fill="none"/><path d="M55 23C69 34 65 53 52 63" stroke="#b5a2d1" fill="none" opacity=".7"/></symbol>
<symbol id="brand-mark" viewBox="0 0 32 32"><circle cx="13" cy="13" r="9" fill="#d9c9ec"/><path d="m6 18-1 6 6-4" fill="#d9c9ec"/><circle cx="21" cy="21" r="8" fill="#eddef0" stroke="white" stroke-width="1.5"/><path d="m24 26 5 4-1-6" fill="#eddef0"/></symbol>
<symbol id="mic" viewBox="0 0 24 24"><rect x="9" y="3" width="6" height="12" rx="3"/><path d="M5 11v2a7 7 0 0 0 14 0v-2M12 20v2M8 22h8"/></symbol><symbol id="mute" viewBox="0 0 24 24"><path d="m3 3 18 18M9 9v3a3 3 0 0 0 5 2M9 5a3 3 0 0 1 6 0v6M5 11v2a7 7 0 0 0 12 5M19 11v2M12 20v2"/></symbol><symbol id="history" viewBox="0 0 24 24"><path d="M4 8a9 9 0 1 1-1 7M4 3v5h5M12 7v5l3 2"/></symbol><symbol id="settings" viewBox="0 0 24 24"><path d="M4 7h16M4 17h16"/><circle cx="9" cy="7" r="3" fill="white"/><circle cx="16" cy="17" r="3" fill="white"/></symbol><symbol id="arrow" viewBox="0 0 24 24"><path d="M12 19V5m-6 6 6-6 6 6"/></symbol><symbol id="back" viewBox="0 0 24 24"><path d="m14 6-6 6 6 6"/></symbol><symbol id="chevron" viewBox="0 0 24 24"><path d="m9 6 6 6-6 6"/></symbol><symbol id="chat" viewBox="0 0 24 24"><path d="M20 11a8 8 0 0 1-8 8 9 9 0 0 1-4-1l-5 3 1-6a8 8 0 1 1 16-4Z"/></symbol><symbol id="end" viewBox="0 0 24 24"><path d="M5 16v-4h14v4M3 12c4-5 14-5 18 0"/></symbol>
</defs></svg>
<main class="layout"><aside class="presentation" aria-label="Design direction"><a class="back-link" href="new-index.html">← Explore the new directions</a><div class="concept">Hope · A new direction</div><h1>OPAL</h1><p class="lead">A little space to think.<br>A softer way to be heard.</p><ul class="notes"><li><strong>Light, held in a pearl.</strong>Transparent layers, curved reflections, and an iridescent edge give Hope a quiet physical presence.</li><li><strong>The conversation has room.</strong>A luminous white canvas. A personal greeting. Everyday prompts that don’t compete for attention.</li><li><strong>Always within reach.</strong>One floating composer for a thought in text or a conversation out loud. Voice opens into a focused, uncluttered space.</li></ul><div class="identity"><svg class="icon-large" role="img" aria-label="Hope icon, two overlapping pearlescent circular speech forms on violet"><use href="#app-icon"/></svg><div><svg class="icon-small" role="img" aria-label="Hope icon at 32 pixels"><use href="#app-icon"/></svg><p>Two voices, a shared space.<br>App icon · 100 / 32 px</p></div></div><p class="demo-note">Interactive design study. All conversations are simulated and stay on this page. No microphone, audio, network, or account access.</p></aside>
<section class="device-wrap" aria-label="Interactive Hope phone"><div class="device"><div class="screen" id="screen"><div class="statusbar" aria-hidden="true"><span>9:41</span><span class="island"></span><div class="status-icons"><svg viewBox="0 0 20 20" fill="currentColor"><rect x="1" y="12" width="3" height="5" rx="1"/><rect x="6" y="9" width="3" height="8" rx="1"/><rect x="11" y="6" width="3" height="11" rx="1"/><rect x="16" y="3" width="3" height="14" rx="1"/></svg><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 9a14 14 0 0 1 18 0M6 12a9 9 0 0 1 12 0M9 15a4 4 0 0 1 6 0"/><circle cx="12" cy="18" r="1" fill="currentColor"/></svg><svg class="battery" viewBox="0 0 25 16" fill="none" stroke="currentColor"><rect x="1" y="2" width="20" height="12" rx="3"/><rect x="3" y="4" width="16" height="8" rx="1" fill="currentColor"/><path d="M23 6v4" stroke-width="2"/></svg></div></div>
<header class="app-header"><div class="brand"><svg aria-hidden="true"><use href="#brand-mark"/></svg>hope</div><button class="round-button" id="history-button" aria-label="Open history"><svg class="glyph"><use href="#history"/></svg></button><button class="round-button" id="settings-button" aria-label="Open settings"><svg class="glyph"><use href="#settings"/></svg></button></header>
<div class="content" id="content" tabindex="-1"><section class="home"><h2 class="greeting">A little room for you,<br><em>Shane.</em></h2><p class="welcome-copy">No perfect words needed. Start anywhere.</p><div class="pearl-wrap"><span class="pearl-shadow"></span><svg class="pearl" role="img" aria-label="A translucent pearl with pink, lilac and ice-blue reflections"><use href="#pearl-art"/></svg></div><button class="voice-start" id="start-voice"><span class="mic-halo"><svg class="glyph"><use href="#mic"/></svg></span>Let’s talk</button><div class="prompts"><button class="prompt" data-prompt="day">Talk through my day</button><button class="prompt" data-prompt="idea">Explore an idea</button><button class="prompt" data-prompt="plan">Make a plan</button></div></section></div>
<div class="composer-zone"><form class="composer" id="composer"><label for="message" class="sr-only">Message Hope</label><input id="message" placeholder="What’s on your mind?" maxlength="2000" autocomplete="off"><button type="submit" class="send-button" id="send-message" aria-label="Send message" hidden><svg class="glyph"><use href="#arrow"/></svg></button><button type="button" class="mic-button" id="composer-mic" aria-label="Start voice conversation"><svg class="glyph"><use href="#mic"/></svg></button></form><p class="simulation">Local demo · Your microphone stays off</p></div>
<section class="live" id="live" aria-label="Simulated voice conversation" hidden><div class="live-top"><strong>With Hope</strong><span>Simulated voice</span></div><svg class="live-pearl" aria-hidden="true"><use href="#pearl-art"/></svg><h2 id="live-heading">I’m here. Take your time.</h2><div class="live-state" role="status"><span class="state-dot"></span><span id="voice-state">Listening</span></div><div class="elapsed" id="elapsed">00:00</div><svg class="ribbon" viewBox="0 0 320 65" aria-hidden="true"><defs><linearGradient id="ribbon-color"><stop stop-color="#eacbde"/><stop offset=".5" stop-color="#d8c7ed"/><stop offset="1" stop-color="#c4e1f0"/></linearGradient></defs><path d="M0 34C35 34 42 10 76 17S114 57 147 36 190 7 217 27 258 54 284 37 309 29 320 33" fill="none" stroke="url(#ribbon-color)" stroke-width="1.3"/><path d="M0 34C32 34 53 29 77 28S116 44 147 34 189 17 219 31 261 41 284 35 309 32 320 33" fill="none" stroke="url(#ribbon-color)" stroke-width="6" opacity=".4"/><path d="M0 34C34 33 49 44 78 41S115 14 145 31 183 56 217 38 257 20 284 31 309 35 320 33" fill="none" stroke="url(#ribbon-color)" stroke-width="1" opacity=".8"/></svg><div class="live-log" id="live-log" role="log" aria-label="Voice transcript" aria-live="polite"></div><div class="live-controls"><div class="control-group"><button id="mute-button" aria-label="Mute simulated microphone" aria-pressed="false"><svg class="glyph"><use href="#mute"/></svg></button><span id="mute-label">Mute</span></div><div class="control-group"><button class="listen" id="voice-turn" aria-label="Try a simulated voice turn"><svg class="glyph"><use href="#mic"/></svg></button><span>Speak again</span></div><div class="control-group"><button class="end" id="end-call" aria-label="End conversation"><svg class="glyph"><use href="#end"/></svg></button><span>End</span></div></div><p class="live-note">No audio is recorded or played</p></section><div class="home-indicator" aria-hidden="true"></div><div id="announce" class="sr-only" role="status"></div></div></div><p class="device-caption">OPAL · A luminous space for conversation</p></section></main>
<script>
(()=>{'use strict';const $=id=>document.getElementById(id),content=$('content'),homeMarkup=content.innerHTML,live=$('live'),field=$('message');let page='home',voice='Ava',spoken=true,muted=false,interval=null,timers=[],seconds=0,active=null;const history=[{title:'A little breathing room',when:'Today · 9:12 am',messages:[['You','Today feels a little full. I don’t know where to start.'],['Hope','Let’s make it smaller. What’s one thing that needs your attention, and one thing that can wait?']]},{title:'An idea for the weekend',when:'Yesterday · 6:40 pm',messages:[['You','I’d love to spend a day by the sea.'],['Hope','A morning train, a long walk, and lunch somewhere unhurried. Want to start with a place or a date?']]}];const prompts={day:['Talk through my day','What’s been taking up the most space in your day? We can start there.'],idea:['Explore an idea','Tell me the rough version. It doesn’t need to make sense yet.'],plan:['Make a plan','What would you like to make room for? We can find a small first step.']};const icon=name=>'<svg class="glyph" aria-hidden="true"><use href="#'+name+'"/></svg>';const announce=text=>$('announce').textContent=text;function cancel(){timers.forEach(clearTimeout);timers=[]}function schedule(fn,time){timers.push(setTimeout(fn,time))}function show(markup,next){page=next;content.innerHTML=markup;content.scrollTop=0;content.focus({preventScroll:true})}function home(){active=null;show(homeMarkup,'home');field.placeholder='What’s on your mind?'}function back(){return '<button class="back" id="back-home">'+icon('back')+'Back to your space</button>'}function message(target,role,text){const el=document.createElement('div');el.className='message '+(role==='You'?'you':'hope');const label=document.createElement('small');label.textContent=role;const p=document.createElement('p');p.textContent=text;el.append(label,p);target.append(el)}function renderThread(item){active=item;show(back()+'<h2 class="thread-title" id="thread-title"></h2><div class="transcript" id="transcript" role="log" aria-live="polite" aria-label="Conversation transcript"></div>','thread');$('thread-title').textContent=item.title;item.messages.forEach(m=>message($('transcript'),...m));field.placeholder='Keep the thought going…'}function newThread(title,first,reply){const item={title,when:'Just now · Demo',messages:[['You',first],['Hope',reply]]};history.unshift(item);renderThread(item)}function showHistory(){show(back()+'<h2 class="page-heading">Your conversations</h2><p class="page-description">Thoughts you can come back to.<br>Sample threads and your local demo conversations.</p><div class="history-label">Recently</div><div id="history-list"></div>','history');history.forEach((item,index)=>{const button=document.createElement('button');button.className='history-row';button.dataset.thread=index;button.innerHTML='<span class="history-symbol">'+icon('chat')+'</span><span><strong></strong><small></small></span>'+icon('chevron');button.querySelector('strong').textContent=item.title;button.querySelector('small').textContent=item.when;$('history-list').append(button)})}function settings(){show(back()+'<h2 class="page-heading">Make yourself at home.</h2><p class="page-description">A few small choices for your conversations.</p><div class="settings-group"><h3>Conversation</h3><label class="setting"><span>Hope’s voice<small>A preference for this demo</small></span><select id="voice-choice" aria-label="Hope voice"><option>Ava</option><option>Emma</option><option>Andrew</option></select></label><label class="setting"><span>Spoken replies<small>No audio plays in this demo</small></span><input type="checkbox" id="spoken"></label></div><div class="settings-group"><h3>Privacy</h3><div class="setting"><span>Just between us<small>Your text stays on this page.<br>No account or microphone is connected.</small></span>'+icon('chat')+'</div></div><button class="settings-save" id="save-settings">Save preferences</button><p class="saved-note" id="saved-note" role="status"></p><p class="settings-footer">Hope · OPAL design study<br>Preferences and conversations reset when you reload.</p>','settings');$('voice-choice').value=voice;$('spoken').checked=spoken}function state(text,heading){$('voice-state').textContent=text;if(heading)$('live-heading').textContent=heading;live.classList.toggle('listening',text==='Listening');announce(text)}function turn(){cancel();if(muted)return;state('Listening','I’m here. Take your time.');$('voice-turn').disabled=true;schedule(()=>{const text='Help me make a little space in my day.';message($('live-log'),'You',text);active.messages.push(['You',text]);state('Thinking','Let’s find a little room.');},1800);schedule(()=>{const text='Choose one thing that can wait. Then give yourself ten minutes with nothing to solve. What would feel good in that little space?';message($('live-log'),'Hope',text);active.messages.push(['Hope',text]);$('live-log').scrollTop=$('live-log').scrollHeight;state(spoken?'HopLine truncated
$('history-button').onclick=showHistory;$('settings-button').onclick=settings;$('composer-mic').onclick=startVoice;content.onclick=e=>{const b=e.target.closest('button');if(!b)return;if(b.id==='back-home')home();if(b.id==='start-voice')startVoice();if(b.dataset.prompt){const p=prompts[b.dataset.prompt];newThread(p[0],p[0],p[1]);field.focus()}if(b.dataset.thread!==undefined)renderThread(history[Number(b.dataset.thread)]);if(b.id==='save-settings'){voice=$('voice-choice').value;spoken=$('spoken').checked;$('saved-note').textContent='Preferences saved for this demo.';announce('Preferences saved')}};field.oninput=()=>{$('send-message').hidden=!field.value.trim()};$('composer').onsubmit=e=>{e.preventDefault();const text=field.value.trim();if(!text)return;const reply='Let’s take it one thought at a time. What feels most important about that to you?';if(page!=='thread')newThread('A thought to talk through',text,reply);else{active.messages.push(['You',text],['Hope',reply]);message($('transcript'),'You',text);message($('transcript'),'Hope',reply);content.scrollTop=content.scrollHeight}field.value='';$('send-message').hidden=true;field.focus();announce('Local message added. Hope’s reply is a prewritten example.')};$('mute-button').onclick=()=>{muted=!muted;cancel();$('mute-button').setAttribute('aria-pressed',String(muted));$('mute-button').setAttribute('aria-label',muted?'Unmute simulated microphone':'Mute simulated microphone');$('mute-label').textContent=muted?'Unmute':'Mute';$('voice-turn').disabled=muted;state(muted?'Microphone muted · simulation paused':'Listening',muted?'A quiet moment.':'Ready when you are.');if(!muted)turn()};$('voice-turn').onclick=turn;$('end-call').onclick=endVoice;document.addEventListener('keydown',e=>{if(e.key==='Escape'){if(!live.hidden)endVoice();else if(page!=='home')home()}});live.addEventListener('keydown',e=>{if(e.key!=='Tab')return;const buttons=[...live.querySelectorAll('button:not(:disabled)')];if(e.shiftKey&&document.activeElement===buttons[0]){e.preventDefault();buttons.at(-1).focus()}else if(!e.shiftKey&&document.activeElement===buttons.at(-1)){e.preventDefault();buttons[0].focus()}});
})();
</script></body></html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 239 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"><defs><linearGradient id="a" x1="0" x2="1" y1="0" y2="1"><stop stop-color="#fff5ef"/><stop offset=".35" stop-color="#def3fb"/><stop offset=".65" stop-color="#e9c9f0"/><stop offset="1" stop-color="#f4afcf"/></linearGradient><linearGradient id="b"><stop stop-color="#dfc2f1"/><stop offset=".5" stop-color="#f8e2e5"/><stop offset="1" stop-color="#e1f2ff"/></linearGradient></defs><rect width="1024" height="1024" fill="#8e59a9"/><g transform="translate(112 112) scale(8)"><path d="M26 16C10 28 11 57 28 73C36 80 45 77 48 66L57 36C62 18 42 4 26 16Z" fill="url(#a)" stroke="#fff7"/><path d="M69 21C54 11 42 29 47 46L58 77C63 91 85 78 85 59C85 39 81 29 69 21Z" fill="url(#b)" stroke="#fff8"/><path d="M29 19C18 26 17 42 20 50M68 24C77 31 79 39 80 48" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round"/></g></svg>

After

Width:  |  Height:  |  Size: 887 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

+5
View File
@@ -0,0 +1,5 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Hope / Prism</title><style>
*{box-sizing:border-box}body{margin:0;color:#302639;background:#eee9f3;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;-webkit-font-smoothing:antialiased}button,input,select{font:inherit}button{border:0;background:none;color:inherit;min-height:44px;cursor:pointer}button:focus-visible,input:focus-visible,select:focus-visible,a:focus-visible{outline:3px solid #8b52ba;outline-offset:4px}a{color:inherit}h1,h2,p{margin:0}[hidden]{display:none!important}.stage{min-height:100vh;max-width:1230px;display:grid;grid-template-columns:1fr 400px 180px;align-items:center;gap:48px;padding:54px 42px;margin:auto}.intro{align-self:start;padding-top:55px}.back{display:inline-flex;align-items:center;min-height:44px;font-size:13px;text-decoration:none}.name{font-size:15px;margin:30px 0 20px;color:#674878}.intro h1{font-size:66px;line-height:1.07;letter-spacing:-.035em;font-weight:450}.intro h1 em{font-family:Georgia,serif;font-weight:400;color:#9251ad}.lede{font-size:17px;line-height:1.7;margin-top:26px;max-width:34ch;color:#675c6e}.features{margin-top:38px}.feature{padding:17px 0;border-top:1px solid #d7ccde;font-size:14px;line-height:1.6;color:#675c6e}.feature strong{display:block;font-size:15px;color:#302639;margin-bottom:4px}.phone{height:824px;width:390px;border:7px solid #fcfbfd;border-radius:48px;overflow:hidden;position:relative;background:linear-gradient(160deg,#fff 0%,#fdfbff 55%,#f0edf8 100%);box-shadow:0 6px 8px #5340640c;display:flex;flex-direction:column}.statusbar{height:48px;display:flex;align-items:center;justify-content:space-between;padding:12px 25px 0;font-size:14px;font-weight:600;flex-shrink:0}.island{position:absolute;top:9px;left:50%;transform:translateX(-50%);width:103px;height:27px;border-radius:20px;background:#292331}.header{display:flex;align-items:center;justify-content:space-between;padding:14px 22px 9px;flex-shrink:0}.header button{width:44px;background:#fff;border-radius:50%;font-size:20px}.wordmark{font-size:20px;font-weight:600;letter-spacing:-.03em}.wordmark span{font-weight:400;color:#9c80b0}.view{flex:1;overflow:auto;min-height:0;padding:0 22px 16px}.hero{text-align:center;padding-top:9px}.sculpture{height:108px;width:140px;margin:0 auto 10px;position:relative;filter:drop-shadow(0 9px 8px #b298ce22)}.sculpture .piece{position:absolute;width:67px;height:84px;border-radius:48% 50% 44% 52%;top:11px;left:31px;transform:rotate(-24deg);background:radial-gradient(ellipse at 22% 13%,#fff 0%,#fff9 14%,transparent 39%),conic-gradient(from 130deg,#cee9f6,#eed9f7,#e6a7d8,#fee0ca,#d9eaf5,#c7b1f0,#cee9f6);box-shadow:inset 2px 1px 2px #fff,inset -3px -2px 5px #baa2d455;border:1px solid #fff9}.sculpture .piece:nth-child(2){left:65px;top:12px;transform:rotate(24deg);width:51px;height:77px;background:radial-gradient(ellipse at 75% 17%,#fff 0%,#fff8 17%,transparent 44%),conic-gradient(from 30deg,#cceafb,#d5c0f5,#f3d2e8,#fee5dd,#d3eaf9)}.sculpture:after{content:'';position:absolute;bottom:2px;left:27px;width:90px;height:8px;background:#bb9dda35;filter:blur(8px);border-radius:50%}.hero h2{font-size:29px;line-height:1.14;font-weight:450;letter-spacing:-.03em}.hero h2 em{font-family:Georgia,serif;color:#9251ad;font-weight:400}.hero p{font-size:13px;color:#74627f;line-height:1.5;margin-top:10px}.topic{display:flex;align-items:center;justify-content:space-between;margin:24px 0 18px;font-size:12px;color:#766a7d}.topic span:first-child{padding:7px 11px;border:1px solid #e8dfed;border-radius:20px;background:#fff}.messages{display:flex;flex-direction:column;gap:20px}.message{font-size:15px;line-height:1.6}.message.user{padding:11px 14px;border-radius:14px;background:#f2eaf7;margin-left:28px}.message .who{font-size:11px;font-weight:600;color:#7c6688;margin-bottom:5px}.message p{white-space:pre-wrap;overflow-wrap:anywhere}.reply-title{font-size:20px;letter-spacing:-.02em;font-weight:500;margin:8px 0}.idea{margin-top:16px;display:flex;gap:12px;align-items:center}.idea-art{width:70px;height:76px;flex-shrink:0;overflow:hidden;border-radius:12px;position:relative;background:linear-gradient(150deg,#e3c1e8,#e5e3ff,#c5d9f2)}.idea-art:before{content:'';position:absolute;width:72px;height:72px;border-radius:50%;left:20px;top:25px;background:linear-gradient(140deg,#e7dbff,#a8bfe2);box-shadow:inset 1px 1px 2px #fff8}.idea-art:after{content:'';position:absolute;width:30px;height:30px;left:13px;top:10px;border-radius:50%;background:radial-gradient(circle at 30% 25%,#fff9,#f5c7dc 35%,#d397c4);box-shadow:0 4px 5px #ae90b333}.idea-text{font-size:13px;line-height:1.6;color:#71607c}.idea-text strong{display:block;color:#45334e;font-size:14px;margin-bottom:3px}.actions{display:flex;gap:8px;margin-top:15px}.actions button{padding:0 12px;border-radius:24px;border:1px solid #e1d7e8;background:#fff;font-size:12px}.composer-shell{padding:10px 14px 12px;flex-shrink:0}.composer{border-radius:16px;background:#fff;padding:13px 14px 10px;box-shadow:0 4px 8px #8c76a313}.composer input{border:0;color:#45334e;background:transparent;wLine truncated
</style></head><body><svg width="0" height="0" style="position:absolute" aria-hidden="true"><defs><linearGradient id="gem" x1="0" x2="1" y1="0" y2="1"><stop stop-color="#fff5ef"/><stop offset=".35" stop-color="#def3fb"/><stop offset=".65" stop-color="#e9c9f0"/><stop offset="1" stop-color="#f4afcf"/></linearGradient><linearGradient id="gem2"><stop stop-color="#dfc2f1"/><stop offset=".5" stop-color="#f8e2e5"/><stop offset="1" stop-color="#e1f2ff"/></linearGradient><symbol id="prism-icon" viewBox="0 0 100 100"><path d="M26 16C10 28 11 57 28 73C36 80 45 77 48 66L57 36C62 18 42 4 26 16Z" fill="url(#gem)" stroke="#fff7" stroke-width="1"/><path d="M69 21C54 11 42 29 47 46L58 77C63 91 85 78 85 59C85 39 81 29 69 21Z" fill="url(#gem2)" stroke="#fff8" stroke-width="1"/><path d="M29 19C18 26 17 42 20 50M68 24C77 31 79 39 80 48" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round"/></symbol><symbol id="mic-symbol" viewBox="0 0 24 24"><rect x="9" y="3" width="6" height="12" rx="3"/><path d="M5 10v2a7 7 0 0 0 14 0v-2M12 19v3M8 22h8"/></symbol></defs></svg><main class="stage"><section class="intro"><a class="back" href="new-index.html">← Compare the new directions</a><div class="name">Prism / a conversation that unfolds</div><h1>From a thought<br>to <em>something<br>you can use.</em></h1><p class="lede">A softer place to talk things through. Pearlescent details, quiet lavender, and useful answers with room to breathe.</p><div class="features"><div class="feature"><strong>Your answer is the main event.</strong>A compact sculptural identity leaves space for readable replies and the next step.</div><div class="feature"><strong>Write or speak from one place.</strong>A floating composer makes switching between voice and text effortless.</div><div class="feature"><strong>A little color, a lighter touch.</strong>Translucent pastel forms carry the personality. Controls stay simple.</div></div></section><section class="phone-wrap" aria-label="Interactive Prism demonstration"><div class="phone"><div class="statusbar"><span>9:41</span><div class="island" aria-hidden="true"></div><span aria-hidden="true">▮▮▮ ▰</span></div><header class="header"><button id="history" aria-label="Conversation history">☰</button><div class="wordmark">hope <span>/ prism</span></div><button id="settings" aria-label="Settings">···</button></header><section class="view" id="chat-view"><div class="hero"><div class="sculpture" aria-hidden="true"><div class="piece"></div><div class="piece"></div></div><h2>A little possibility,<br><em>Shane.</em></h2><p>Let’s see where your thoughts take us.</p></div><div class="topic"><span>A slower weekend</span><span>Sample conversation</span></div><div class="messages" id="messages" role="log" aria-label="Conversation" aria-live="polite"><article class="message user"><div class="who">You</div><p>I’d like a weekend that feels less busy.</p></article><article class="message"><div class="who">Hope</div><h2 class="reply-title">Leave a little room.</h2><p>Choose one thing you’ll look forward to, and leave the rest of the morning open. A walk with no destination is a good place to start.</p><div class="idea"><div class="idea-art" aria-hidden="true"></div><div class="idea-text"><strong>A morning, unplanned.</strong>Take a short walk. Stop somewhere new. Let the day find its own pace.</div></div><div class="actions"><button id="continue">Plan a quiet morning ↗</button><button id="copy">Copy reply</button></div><p class="toast" id="copy-status" role="status"></p></article></div><p class="light-status" id="chat-status" role="status"></p></section><section class="view" id="history-view" hidden><h2 class="nav-title">Your conversations</h2><p class="sub">Pick up a thought where you left it.</p><div class="list"><button id="open-thread"><strong>A slower weekend</strong><small>Today · Sample conversation</small></button><button id="open-idea"><strong>An idea taking shape</strong><small>Yesterday · Sample conversation</small></button></div><button class="voice-back" id="history-back">← Back to conversation</button><p class="notice">Example history only. Nothing is saved or loaded from your account.</p></section><section class="view" id="settings-view" hidden><h2 class="nav-title">Make it yours.</h2><p class="sub">The voice that meets you here.</p><div class="list"><label class="setting"><span>Hope’s voice</span><select id="voice-choice"><option>Ava</option><option>Andrew</option><option>Emma</option></select></label><label class="setting"><span>Read replies aloud</span><input id="spoken" type="checkbox" checked style="width:24px;height:24px;accent-color:#a36cba"></label><div class="setting"><span>Account</span><span>Shane · demo</span></div></div><p class="notice">Preferences apply to this sample only. No audio is played and no real account is connected.</p><button class="voice-back" id="settings-back">← Back to conversation</button><button class="voice-back" id="signout" style="display:block">SiLine truncated
const $=id=>document.getElementById(id);let timeouts=[],clock=null,seconds=0,active=false,muted=false,busy=false;function clear(){timeouts.forEach(clearTimeout);timeouts=[];clearInterval(clock);clock=null;busy=false}function view(name){document.querySelectorAll('.view').forEach(v=>v.hidden=v.id!==name+'-view');$('composer-shell').hidden=name!=='chat';$('history').textContent=name==='chat'?'☰':'‹'}function add(role,text){const article=document.createElement('article');article.className='message'+(role==='You'?' user':'');const who=document.createElement('div');who.className='who';who.textContent=role;const p=document.createElement('p');p.textContent=text;article.append(who,p);$('messages').append(article);$('chat-view').scrollTop=$('chat-view').scrollHeight}function reply(text){if(busy)return;busy=true;add('You',text);$('chat-status').textContent='Hope is finding a starting point… · demo';$('voice-state').textContent='Putting a thought together · demo';$('voice-heading').textContent='One moment.';timeouts.push(setTimeout(()=>{add('Hope','Leave the first hour open. A slow breakfast, a nearby walk, and one small thing you’re looking forward to. You can decide what comes next when you get there. (Sample reply.)');$('chat-status').textContent='Sample reply ready';$('voice-state').textContent=muted?'Microphone muted · demo':'Hope’s reply is ready · demo';$('voice-heading').textContent='A little room to breathe.';busy=false},1600))}function start(){clear();active=true;muted=false;seconds=0;$('timer').textContent='00:00';$('pause').textContent='Mute';$('pause').setAttribute('aria-pressed','false');$('voice-state').textContent='Listening · demo';$('voice-heading').innerHTML='Take your time.<br>I’m here.';view('voice');clock=setInterval(()=>{$('timer').textContent=String(Math.floor(++seconds/60)).padStart(2,'0')+':'+String(seconds%60).padStart(2,'0')},1000);timeouts.push(setTimeout(()=>{if(active&&!muted)reply('Help me plan a quiet morning.')},2400))}$('start-voice').onclick=start;$('demo-turn').onclick=()=>{if(!muted)reply('Help me plan a quiet morning.')};$('pause').onclick=()=>{muted=!muted;$('pause').textContent=muted?'Unmute':'Mute';$('pause').setAttribute('aria-pressed',String(muted));$('voice-state').textContent=muted?'Microphone muted · demo':'Listening · demo'};$('end').onclick=()=>{clear();active=false;view('chat');$('chat-status').textContent='Voice demo ended. Your conversation stays here.'};$('transcript').onclick=()=>view('chat');$('history').onclick=()=>{if(!$('chat-view').hidden)view('history');else view('chat')};$('settings').onclick=()=>view('settings');$('history-back').onclick=$('settings-back').onclick=()=>view('chat');$('open-thread').onclick=()=>view('chat');$('open-idea').onclick=()=>{add('Hope','Tell me the idea in its simplest form. We can work out the next step together. (Sample history.)');view('chat')};$('composer').onsubmit=e=>{e.preventDefault();const text=$('text-input').value.trim();if(text&&!busy){$('text-input').value='';reply(text)}};$('continue').onclick=()=>reply('Help me plan a quiet morning.');$('copy').onclick=async()=>{try{await navigator.clipboard.writeText('Choose one thing you’ll look forward to, and leave the rest of the morning open.');$('copy-status').textContent='Reply copied.'}catch{$('copy-status').textContent='Copy isn’t available here. Select the reply text to copy it.'}};$('voice-choice').onchange=e=>$('settings-status').textContent=e.target.value+' selected for this demo.';$('spoken').onchange=e=>$('settings-status').textContent='Spoken replies '+(e.target.checked?'enabled':'disabled')+' as a demo preference. No audio plays.';$('signout').onclick=()=>{clear();active=false;$('settings-status').textContent='Simulated sign out complete. Your real account was not accessed.'};
</script></body></html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><defs><linearGradient id="a" x2="1" y2="1"><stop stop-color="#f5b6d2"/><stop offset="1" stop-color="#a79aef"/></linearGradient><linearGradient id="b" x2="1" y2="1"><stop stop-color="#d2baf5"/><stop offset="1" stop-color="#b8d8f4"/></linearGradient></defs><rect width="100" height="100" rx="23" fill="#302438"/><path d="M24 76V31c0-12 9-17 22-17h9c15 0 22 8 22 18 0 17-16 20-31 26l-9 5v13H24Zm13-28 18-7c6-2 9-4 9-9 0-4-3-6-9-6H44c-5 0-7 2-7 7v15Z" fill="url(#a)"/><path d="m43 53 13-6 24 29H63L43 53Z" fill="url(#b)"/><path d="m43 53 13-6 7 8-13 6Z" fill="#776593" opacity=".45"/></svg>

After

Width:  |  Height:  |  Size: 648 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

+28
View File
@@ -0,0 +1,28 @@
<!doctype html>
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover"><meta name="color-scheme" content="light"><title>Hope · Ribbon</title><link rel="icon" href="ribbon-icon.svg"><style>
:root{--white:#fff;--ink:#302438;--muted:#73677d;--pink:#edb1ce;--lavender:#b8a6e8;--blue:#adcef3;--surface:#f6f4f9;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;color:var(--ink);background:#faf9fc;font-synthesis:none}*{box-sizing:border-box}body{margin:0}button,input,select{font:inherit}button,a,input,select{touch-action:manipulation}button{color:inherit;cursor:pointer;min-width:44px;min-height:44px;border:0;background:none}button:hover{background-color:#f1edf6}button:disabled{opacity:.38;cursor:default}button:focus-visible,a:focus-visible,input:focus-visible,select:focus-visible{outline:3px solid #8060a6;outline-offset:4px}a{color:inherit}svg{display:block}[hidden]{display:none!important}.showcase{max-width:1150px;margin:auto;min-height:100vh;display:grid;grid-template-columns:1fr 430px;gap:120px;align-items:center;padding:45px 60px}.intro{max-width:450px}.back{display:inline-flex;align-items:center;min-height:44px;font-size:14px;text-decoration:none;color:var(--muted)}.direction{font-size:14px;margin-top:50px}.intro h1{font-size:76px;font-weight:450;letter-spacing:-.035em;line-height:1;margin:20px 0 25px}.intro .lead{font-size:23px;line-height:1.5;letter-spacing:-.02em;margin:0;max-width:26ch}.description{font-size:15px;line-height:1.7;color:var(--muted);max-width:38ch;margin:25px 0 0}.identity{display:flex;align-items:center;gap:28px;margin:40px 0}.large-icon{width:104px;height:104px;filter:drop-shadow(0 8px 12px #30243816)}.small-icon{width:32px;height:32px;margin-bottom:12px}.identity span{font-size:12px;color:var(--muted)}.note{font-size:12px;line-height:1.7;color:var(--muted);max-width:42ch}.phone{width:410px;padding:9px;background:linear-gradient(120deg,#fefefe,#e5e3e8 45%,#fff 75%);border-radius:55px;box-shadow:0 25px 70px #43335016,0 2px 3px #fff inset}.screen{width:390px;height:800px;position:relative;overflow:hidden;background:white;border-radius:46px;display:flex;flex-direction:column}.statusbar{height:56px;flex:none;display:flex;align-items:center;justify-content:space-between;padding:0 29px;font-size:14px;font-weight:650}.island{position:absolute;left:50%;top:14px;transform:translateX(-50%);width:108px;height:29px;background:#211e25;border-radius:24px}.signals{font-size:11px;letter-spacing:2px}.topbar{display:flex;align-items:center;justify-content:space-between;padding:9px 25px 0;height:67px}.wordmark{font-size:25px;font-weight:550;letter-spacing:-.04em}.top-actions{display:flex;gap:3px}.icon{width:21px;height:21px;fill:none;stroke:currentColor;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round}.icon-button{display:grid;place-items:center;border-radius:50%}.voice-home{position:relative;flex:1;min-height:0;display:flex;flex-direction:column}.welcome{padding:27px 29px 0}.welcome h2{font-size:45px;line-height:1.09;font-weight:450;letter-spacing:-.035em;margin:0}.welcome p{font-size:14px;line-height:1.6;color:var(--muted);margin:14px 0 0}.sculpture{position:relative;height:180px;flex:none;margin-top:0;display:grid;place-items:center}.mesh{width:460px;height:190px;position:absolute;left:50%;transform:translateX(-50%)}.mesh path{fill:none;stroke:url(#ribbon-gradient);stroke-width:.7}.sculpture:before{content:"";position:absolute;width:310px;height:100px;background:radial-gradient(ellipse,#e8dcf54a,transparent 70%);filter:blur(15px)}.voice-status{text-align:center;min-height:56px;margin-top:-6px}.voice-status strong{font-weight:500;font-size:15px;display:block}.timer{font-variant-numeric:tabular-nums;font-size:13px;color:var(--muted);display:block;margin-top:7px;letter-spacing:.08em}.controls{display:flex;align-items:center;justify-content:center;gap:31px;height:143px;flex:none}.minor{width:46px;height:46px;border-radius:50%;background:#f7f5fa;display:grid;place-items:center}.mic{width:83px;height:83px;border-radius:50%;position:relative;background:linear-gradient(130deg,#fff 25%,#f1e9f8 85%);box-shadow:0 6px 18px #ad91bf20,inset 0 0 0 1px #fff;display:grid;place-items:center;isolation:isolate}.mic:before,.mic:after{content:"";position:absolute;z-index:-1;border-radius:50%;inset:-14px;background:conic-gradient(from 50deg,#d9e6fa77,#eee2fb55,#f6d8e977,#d9e6fa77)}.mic:after{inset:-27px;background:conic-gradient(from 220deg,#f7e4ed55,#e8e4f944,#e0edfa55,#f7e4ed55)}.mic .icon{width:30px;height:30px;stroke-width:1.45}.state-listening .mic:before{animation:breathe 2.8s ease-in-out infinite}.state-working .mic:before{animation:breathe 1.6s ease-in-out infinite}.transcript-toggle{align-self:center;font-size:12px;color:var(--muted);margin-top:-5px}.composer{margin:9px 23px 0;padding:6px 7px 6px 18px;display:flex;align-items:center;background:#fbfafd;box-shadow:0 5px 24px #6d4c9010;border-radius:50px;gap:7px}.composer input{width:100%;min-width:0;border:0;background:none;font-size:13px;color:var(--ink);height:40px;outline-offset:2px}.composer input::placeholder{color:var(--muted)}.composer button{border-radius:50%;display:grid;place-items:center;background:#f1ecf7}.demo-note{tLine truncated
@media(max-width:850px){.showcase{gap:45px;padding:35px;grid-template-columns:1fr 410px}.intro h1{font-size:60px}.intro .lead{font-size:19px}}
@media(max-width:700px){body{background:white}.showcase{display:block;padding:0;min-height:100dvh}.intro,.caption{display:none}.device-wrap{width:100%;display:flex;justify-content:center}.phone{width:100%;padding:0;border-radius:0;background:white;box-shadow:none}.screen{width:100%;max-width:430px;height:max(800px,100dvh);border-radius:0;margin:auto}.mobile-back{display:inline-flex!important;position:absolute;top:7px;left:16px;z-index:3;font-size:12px;min-height:44px;align-items:center;text-decoration:none}.statusbar{visibility:hidden}.island{display:none}.welcome{padding-top:26px}.sculpture{margin-top:20px}.voice-home{justify-content:flex-start}.demo-note{margin-top:auto;padding-top:13px}.home-indicator{margin-bottom:max(9px,env(safe-area-inset-bottom))}}
.welcome{padding-top:17px}.welcome h2{font-size:42px;line-height:1.05}.welcome p{margin-top:11px;font-size:13px}.sculpture{height:137px;margin-top:0}.voice-status{min-height:49px}.controls{height:111px}.transcript-toggle{min-height:44px;margin-top:0}.composer{margin-top:2px}.demo-note{font-size:9px;margin-top:12px}.text-mode .sculpture{height:150px}.text-mode .voice-status{margin-bottom:15px}@media(max-width:700px){.statusbar{height:44px}.topbar{height:60px}.welcome{padding-top:16px}.sculpture{height:142px;margin-top:0}.controls{height:108px}.demo-note{margin-top:auto;padding-top:8px}.transcript-toggle{min-height:44px}.home-indicator{margin-top:12px}}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation:none!important;transition:none!important}}
</style></head><body>
<svg width="0" height="0" aria-hidden="true" style="position:absolute"><defs><symbol id="mic-icon" viewBox="0 0 24 24"><rect x="9" y="2" width="6" height="13" rx="3"/><path d="M5 10v3a7 7 0 0 0 14 0v-3M12 20v2M8 22h8"/></symbol><symbol id="activity-icon" viewBox="0 0 24 24"><path d="M4 5h16M4 12h16M4 19h10"/></symbol><symbol id="settings-icon" viewBox="0 0 24 24"><path d="M4 6h16M4 18h16"/><circle cx="9" cy="6" r="3" fill="white"/><circle cx="16" cy="18" r="3" fill="white"/></symbol><symbol id="send-icon" viewBox="0 0 24 24"><path d="M12 19V5m-6 6 6-6 6 6"/></symbol></defs></svg>
<main class="showcase"><aside class="intro"><a class="back" href="new-index.html">← Explore the new directions</a><p class="direction">Hope / Ribbon</p><h1>A voice,<br>given shape.</h1><p class="lead">Room for your thoughts.<br>A little less interface.</p><p class="description">A diaphanous ribbon follows the conversation. Pink folds into lavender, then blue. Your voice is the centre; the transcript is a quiet companion.</p><div class="identity"><img class="large-icon" src="ribbon-icon.svg" alt="Ribbon R app icon"><div><img class="small-icon" src="ribbon-icon.svg" alt="Ribbon icon at 32 pixels"><span>A folded R. Two strands, one voice.</span></div></div><p class="note">Interactive design study. All conversations are simulated sample data. No network requests, microphone permissions, audio playback, or account connection.</p></aside><section class="device-wrap" aria-label="Interactive Ribbon phone"><div><div class="phone"><div class="screen" id="screen"><a class="mobile-back" href="new-index.html" hidden>← New directions</a><div class="statusbar" aria-hidden="true"><span>9:41</span><span class="island"></span><span class="signals">▮▮▮ ◒ ▰</span></div><header class="topbar"><span class="wordmark">hope</span><div class="top-actions"><button class="icon-button" id="activity" aria-label="Open Activity"><svg class="icon"><use href="#activity-icon"/></svg></button><button class="icon-button" id="settings" aria-label="Open Settings"><svg class="icon"><use href="#settings-icon"/></svg></button></div></header>
<section class="voice-home" id="home"><div class="welcome"><h2 id="headline">Say it<br>your way.</h2><p id="subline">A thought, a question, a little of everything.<br>Start wherever you are.</p></div><div class="sculpture" aria-hidden="true"><svg class="mesh" viewBox="0 0 440 230"><defs><linearGradient id="ribbon-gradient" x1="0" x2="1"><stop stop-color="#eeb5cf"/><stop offset=".35" stop-color="#e8b4db"/><stop offset=".62" stop-color="#bfa7e4"/><stop offset="1" stop-color="#a6c9ec"/></linearGradient></defs><g id="mesh-lines"></g></svg></div><div class="voice-status" role="status" aria-live="polite"><strong id="status">A little space to speak</strong><span class="timer" id="timer" aria-label="Elapsed recording time">00:00</span></div><div class="controls"><button class="minor" id="pause" aria-label="Pause simulated recording" disabled><svg class="icon" viewBox="0 0 24 24"><path d="M9 6v12M15 6v12"/></svg></button><button class="mic" id="mic" aria-label="Start simulated listening"><svg class="icon"><use href="#mic-icon"/></svg></button><button class="minor" id="end" aria-label="End simulated recording" disabled><svg class="icon" viewBox="0 0 24 24"><rect x="7" y="7" width="10" height="10" rx="1"/></svg></button></div><button id="transcript-toggle" class="transcript-toggle" aria-expanded="false" aria-controls="transcript-sheet">Show transcript ↗</button><form class="composer" id="composer"><label class="sr-only" for="message">Type a message to Hope</label><input id="message" placeholder="Or let a few words out…" maxlength="1000" autocomplete="off"><button id="text-button" type="button" aria-label="Switch to text mode"><svg class="icon" viewBox="0 0 24 24"><path d="M5 7h14M12 7v11M8 18h8"/></svg></button><button id="send" type="submit" aria-label="Send sample text message" hidden><svg class="icon"><use href="#send-icon"/></svg></button></form><p class="mode-label" id="mode-label" hidden>Text mode · <button id="voice-button" type="button">Back to voice</button></p><p class="demo-note">SIMULATED DEMO · Your microphone stays off<br>Sample replies only. Nothing leaves this page.</p></section>
<section class="panel" id="activity-panel" hidden><button class="back" id="activity-back">← Back to voice</button><h2>Activity</h2><p>A few thoughts you’ve shared.<br>Local sample data, not a real history.</p><div id="events"></div><button class="row" id="sample">A little room in the day<small>Today · Sample conversation · View transcript ↗</small></button><div class="row">A train to the coast<small>Yesterday · Sample conversation</small></div></section><section class="panel" id="settings-panel" hidden><button class="back" id="settings-back">← Back to voice</button><h2>Make it yours.</h2><p>Preferences for this prototype only.<br>No audio is played.</p><label class="setting">Sample voice<select id="voice"><option>Ava</option><option>Emma</option><option>Andrew</option></select></label><label class="setting">Spoken replies<input id="spoken" type="checkbox" checked></label><p id="preference-note" role="status">Your preferences stay here until you reload.</p><h3>Private by design</h3><p>This is a local, simulated design study. It does not request your microphone, contact a server, or connect to an account.</p></section><section class="sheet" id="transcript-sheet" aria-label="Sample transcript" hidden><div class="sheet-head"><h3>A few words, kept here.</h3><button class="close" id="close-sheet" aria-label="Close transcript">×</button></div><p id="empty-transcript">Your transcript will appear here after a simulated voice turn or text message.</p><div id="transcript" role="log" aria-live="polite"></div><small>Sample transcript · No audio was recorded</small></section><div class="home-indicator" aria-hidden="true"></div></div></div><p class="caption">RIBBON · Voice-first, sculptural, quietly alive.</p></div></section></main>
<script>
(()=>{'use strict';const $=id=>document.getElementById(id),reduced=matchMedia('(prefers-reduced-motion: reduce)');let state='idle',elapsed=0,last=0,phase=0,mode='voice',tick=null,replyTimer=null,focusReturn=null;const sampleQuestion='Help me find a little room in my day.',sampleReply='Let one thing wait. Take ten minutes for a walk, a slow cup of tea, or simply nothing. You don’t have to fill every little space.';const paths=[];for(let i=0;i<72;i++){const p=document.createElementNS('http://www.w3.org/2000/svg','path');p.setAttribute('opacity',String(.2+.35*Math.sin(Math.PI*i/71)));$('mesh-lines').append(p);paths.push(p)}
function draw(t=0){paths.forEach((p,i)=>{const v=(i/71-.5)*2;let d='';for(let x=0;x<=440;x+=4){const u=x/440,envelope=Math.pow(Math.sin(Math.PI*u),.75);const center=115+32*Math.sin(u*Math.PI*2-1.15+t*.13)*envelope;const spread=(48+27*Math.cos(u*Math.PI*3+.3))*envelope;const twist=Math.sin(u*Math.PI*2.4+v*1.3+t*.25)*25*envelope;const y=center+v*spread*Math.cos(u*Math.PI*1.7+t*.08)+twist;d+=(x?'L':'M')+x.toFixed(1)+','+y.toFixed(2)}p.setAttribute('d',d)})}draw();function frame(time){if(!reduced.matches&&['listening','working','reply'].includes(state)&&time-last>65){phase+=.035;draw(phase);last=time}requestAnimationFrame(frame)}requestAnimationFrame(frame);
function update(next){state=next;$('home').classList.remove('state-listening','state-working');if(['listening','working'].includes(next))$('home').classList.add('state-'+next);const labels={idle:'A little space to speak',listening:'Listening to you…',paused:'Take your time. Paused.',working:'Finding the words…',reply:'A little room, just for you.'};$('status').textContent=labels[next];$('mic').disabled=next==='working';$('mic').setAttribute('aria-label',next==='listening'?'Finish simulated listening':'Start simulated listening');$('pause').disabled=!['listening','paused'].includes(next);$('pause').setAttribute('aria-label',next==='paused'?'Resume simulated recording':'Pause simulated recording');$('pause').setAttribute('aria-pressed',String(next==='paused'));$('end').disabled=!['listening','paused','working'].includes(next)}
function clock(){const s=Math.floor(elapsed);$('timer').textContent=String(Math.floor(s/60)).padStart(2,'0')+':'+String(s%60).padStart(2,'0')}
function clear(){clearInterval(tick);clearTimeout(replyTimer);tick=null;replyTimer=null}
function add(role,text){$('empty-transcript').hidden=true;const section=document.createElement('div'),label=document.createElement('small'),p=document.createElement('p');label.textContent=role;p.textContent=text;section.append(label,p);$('transcript').append(section)}
function event(text){const row=document.createElement('div');row.className='row';row.textContent=text;const small=document.createElement('small');small.textContent='Just now · Local demo';row.append(small);$('events').prepend(row)}
function finish(text=sampleQuestion){clear();add('You',text);update('working');replyTimer=setTimeout(()=>{add('Hope',sampleReply);update('reply');$('headline').textContent='A little room.\nJust for you.';$('headline').style.whiteSpace='pre-line';$('subline').textContent='A sample reply, ready when you are.';event(mode==='text'?'A written thought':'A little room in the day');},1500)}
function start(){clear();elapsed=0;clock();$('headline').textContent='Say it\nyour way.';$('headline').style.whiteSpace='pre-line';$('subline').textContent='This is simulated listening. Your mic is off.';update('listening');tick=setInterval(()=>{if(state==='listening'){elapsed+=.25;clock();if(elapsed>=5)finish()}},250)}
function page(which){clear();update('idle');closeSheet();$('home').hidden=which!=='home';$('activity-panel').hidden=which!=='activity';$('settings-panel').hidden=which!=='settings';if(which!=='home')$(which+'-back').focus()}
function openSheet(){focusReturn=document.activeElement;$('transcript-sheet').hidden=false;$('transcript-toggle').setAttribute('aria-expanded','true');$('close-sheet').focus()}
function closeSheet(){if($('transcript-sheet').hidden)return;$('transcript-sheet').hidden=true;$('transcript-toggle').setAttribute('aria-expanded','false');if(focusReturn&&focusReturn.isConnected)focusReturn.focus()}
function setMode(next){clear();update('idle');mode=next;$('home').classList.toggle('text-mode',next==='text');$('text-button').hidden=next==='text';$('send').hidden=next!=='text';$('mode-label').hidden=next!=='text';$('status').textContent=next==='text'?'Some things are easier to write.':'A little space to speak';$('message').placeholder=next==='text'?'Write what’s on your mind…':'Or let a few words out…';if(next==='text')$('message').focus()}
$('mic').onclick=()=>state==='listening'?finish():start();$('pause').onclick=()=>update(state==='paused'?'listening':'paused');$('end').onclick=()=>{clear();update('idle');$('subline').textContent='The simulated recording has ended. Start again anytime.'};$('activity').onclick=()=>page('activity');$('settings').onclick=()=>page('settings');$('activity-back').onclick=$('settings-back').onclick=()=>page('home');$('transcript-toggle').onclick=openSheet;$('close-sheet').onclick=closeSheet;document.addEventListener('keydown',e=>{if(e.key==='Escape')closeSheet()});$('text-button').onclick=()=>setMode('text');$('voice-button').onclick=()=>setMode('voice');$('message').addEventListener('focus',()=>{if(mode==='voice')setMode('text')});$('composer').onsubmit=e=>{e.preventDefault();const text=$('message').value.trim();if(!text){$('message').focus();return}if(mode!=='text')setMode('text');$('message').value='';finish(text)};$('sample').onclick=()=>{if(!$('transcript').children.length){add('You',sampleQuestion);add('Hope',sampleReply)}openSheet()};$('voice').onchange=()=>{$('preference-note').textContent=$('voice').value+' selected for the simulated voice. No audio plays.'};$('spoken').onchange=()=>{$('preference-note').textContent='Spoken replies '+($('spoken').checked?'enabled':'disabled')+' as a demo preference. No audio plays.'};
})();
</script></body></html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" role="img" aria-labelledby="title"><title id="title">Hope SIGNAL — three audio bars forming an h</title><rect width="256" height="256" rx="56" fill="#10272d"/><g fill="#9ee3e9"><rect x="66" y="54" width="28" height="148" rx="3"/><rect x="114" y="108" width="28" height="94" rx="3"/><rect x="162" y="88" width="28" height="114" rx="3"/><rect x="80" y="108" width="96" height="26"/></g></svg>

After

Width:  |  Height:  |  Size: 454 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

+39
View File
@@ -0,0 +1,39 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="color-scheme" content="dark"><title>Hope — SIGNAL design study</title>
<style>
:root{--petroleum:#10272d;--cyan:#9ee3e9;--ink:#eff7f7;--muted:#b3c7ca;--line:#345057;--panel:#173239;--page:#0c1c21;--mono:ui-monospace,"SFMono-Regular",Menlo,monospace;color-scheme:dark}*{box-sizing:border-box}body{margin:0;background:var(--page);color:var(--ink);font-family:-apple-system,BlinkMacSystemFont,"SF Pro Text",system-ui,sans-serif;-webkit-font-smoothing:antialiased}button,input,select{font:inherit}button{cursor:pointer;color:inherit;background:none;border:0;min-height:44px}button:focus-visible,input:focus-visible,select:focus-visible{outline:2px solid var(--cyan);outline-offset:4px}button:disabled{cursor:default;opacity:.5}button:hover:not(:disabled){background-color:#25464d}a{color:var(--cyan)}[hidden]{display:none!important}.presentation{max-width:1120px;margin:auto;min-height:100vh;display:grid;grid-template-columns:1fr 390px;gap:100px;align-items:center;padding:64px 72px}.intro{max-width:390px}.brand{display:flex;align-items:center;gap:12px;font-size:19px;font-weight:600}.brand svg{width:32px;height:32px}.direction{font-family:var(--mono);font-size:12px;color:var(--cyan);margin:52px 0 16px}.intro h1{font-size:64px;line-height:1.03;font-weight:450;letter-spacing:-.035em;margin:0 0 26px}.intro>p{font-size:17px;line-height:1.65;color:var(--muted);max-width:34ch}.principles{margin:32px 0 40px;padding:0;list-style:none}.principles li{padding:12px 0;border-top:1px solid var(--line);display:flex;justify-content:space-between;gap:20px;font-size:14px}.principles span:last-child{color:var(--muted);text-align:right}.icon-study{display:flex;align-items:flex-end;gap:24px}.icon-study svg:first-child{width:104px;height:104px}.icon-study svg.small{width:32px;height:32px}.icon-caption{font-size:12px;color:var(--muted);line-height:1.5;margin-top:12px}.demo-note{font-size:12px!important;margin-top:32px;color:var(--muted)}.phone{width:390px;height:800px;padding:9px;border:1px solid #456067;border-radius:49px;background:#08171c;position:relative}.screen{height:100%;background:var(--petroleum);border-radius:40px;overflow:hidden;display:flex;flex-direction:column;position:relative}.statusbar{height:45px;flex-shrink:0;padding:15px 25px 0;display:flex;justify-content:space-between;font-size:13px;font-weight:600}.island{position:absolute;top:11px;left:50%;transform:translateX(-50%);height:25px;width:104px;background:#08171c;border-radius:20px}.status-icons{display:flex;align-items:center;gap:5px}.status-icons svg{width:17px;height:12px}.app-header{padding:17px 24px 10px;display:flex;align-items:center;justify-content:space-between}.wordmark{font-size:25px;font-weight:550;letter-spacing:-.03em}.sim-label{font-family:var(--mono);font-size:10px;color:var(--muted);border:1px solid var(--line);padding:5px 7px;border-radius:4px}.view{flex:1;min-height:0;overflow-y:auto}.talk{display:flex;flex-direction:column;height:100%;padding:0 24px}.state-line{display:flex;justify-content:space-between;align-items:center;color:var(--cyan);font:11px var(--mono);margin-top:23px}.voice-zone{padding:40px 0 12px;text-align:center}.voice-zone h2{margin:0;font-size:39px;letter-spacing:-.035em;line-height:1.13;font-weight:450;min-height:89px}.voice-zone h2 span{display:block}.wave{width:100%;height:85px;margin:12px 0 2px;display:block;color:var(--cyan)}.wave line{stroke:var(--line);stroke-width:1}.wave path{fill:none;stroke:currentColor;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}.voice-hint{margin:0 0 16px;color:var(--muted);font-size:12px}.primary{background:var(--cyan);color:var(--petroleum);border:1px solid var(--cyan);border-radius:12px;font-weight:600;width:100%;height:57px;display:flex;align-items:center;justify-content:center;gap:10px;font-size:15px}.primary:hover:not(:disabled){background:#b8eff2!important}.primary svg,.secondary svg{width:20px;height:20px;fill:none;stroke:currentColor;stroke-width:1.7}.session-controls{display:flex;gap:10px}.session-controls .primary{flex:1}.secondary{border:1px solid var(--line);border-radius:12px;display:flex;gap:7px;align-items:center;justify-content:center;min-width:92px;font-size:13px}.transcript-area{margin-top:25px;padding-top:8px;border-top:1px solid var(--line);flex:1;min-height:115px;display:flex;flex-direction:column}.transcript-header{display:flex;align-items:center;justify-content:space-between}.transcript-header p{font:10px var(--mono);color:var(--muted);margin:0}.mode-toggle{display:flex;gap:2px}.mode-toggle button{min-width:48px;font-size:12px;color:var(--muted);padding:0 8px}.mode-toggle button[aria-pressed=true]{color:var(--cyan)}.messages{overflow:auto;max-height:142px;scroll-behavior:smooth;padding-bottom:12px}.message{margin:9px 0 16px}.message .who{color:var(--muted);font:10px var(--mono);display:flex;gap:10px;margin-bottom:6px}.message p{font-size:14px;line-height:1.5;margin:0}.message.answer p{color:var(--cyan)}.composer{display:flex;gap:8px;margin:8px 0 15px}.composer input{width:100%;min-width:0;height:48px;background:var(--panel);border:1px solid var(--linLine truncated
@media(max-width:980px){.presentation{gap:40px;padding:40px;grid-template-columns:1fr 390px}.intro h1{font-size:52px}}@media(max-width:740px){.presentation{display:flex;flex-direction:column;padding:30px 16px;gap:30px}.intro{max-width:390px;width:100%}.brand{font-size:17px}.direction{margin-top:26px}.intro h1{font-size:44px}.intro>p{font-size:15px;max-width:40ch}.principles{margin:22px 0}.icon-study{display:none}.icon-caption{display:none}.demo-note{margin-top:18px}.phone{max-width:100%;width:390px}.presentation{padding-bottom:30px}}@media(max-width:410px){.presentation{padding-left:8px;padding-right:8px}.phone{border-radius:37px;padding:5px;height:800px}.screen{border-radius:32px}.intro{padding:0 12px}.talk{padding:0 20px}.voice-zone h2{font-size:36px}}@media(prefers-reduced-motion:reduce){*{scroll-behavior:auto!important;transition:none!important;animation:none!important}}
</style></head>
<body>
<svg width="0" height="0" style="position:absolute" aria-hidden="true"><defs><symbol id="hope-icon" viewBox="0 0 256 256"><rect width="256" height="256" rx="56" fill="#10272d"/><g fill="#9ee3e9"><rect x="66" y="54" width="28" height="148" rx="3"/><rect x="114" y="108" width="28" height="94" rx="3"/><rect x="162" y="88" width="28" height="114" rx="3"/><rect x="80" y="108" width="96" height="26"/></g></symbol><symbol id="mic" viewBox="0 0 24 24"><rect x="9" y="3" width="6" height="12" rx="3"/><path d="M5 10v2a7 7 0 0 0 14 0v-2M12 19v3m-4 0h8"/></symbol></defs></svg>
<main class="presentation">
<aside class="intro"><a href="index.html" style="display:inline-flex;align-items:center;min-height:44px;font-size:14px;text-decoration:none;margin-bottom:18px">← All three directions</a><div class="brand"><svg aria-hidden="true"><use href="#hope-icon"/></svg>hope</div><div class="direction">Design direction / SIGNAL</div><h1>A little space<br>to think<br>out loud.</h1><p>A voice-first companion with the calm precision of an audio instrument. Less to look at. More room to be heard.</p><ul class="principles"><li><span>Petroleum + soft cyan</span><span>Low-light, clear contrast</span></li><li><span>A line with a purpose</span><span>Voice state, not decoration</span></li><li><span>Your words stay close</span><span>A readable conversation</span></li></ul><div class="icon-study"><svg role="img" aria-label="Hope audio bar h icon, large"><use href="#hope-icon"/></svg><svg class="small" role="img" aria-label="Hope icon at 32 pixels"><use href="#hope-icon"/></svg></div><div class="icon-caption">Three audio bars. One unmistakable h.<br>104 px / 32 px · solid, never glowing.</div><p class="demo-note">Interactive design study · Sample data only.<br>No microphone, network, or account access.</p></aside>
<section class="phone" aria-label="Interactive Hope iOS design demo"><div class="screen"><div class="island" aria-hidden="true"></div><div class="statusbar" aria-hidden="true"><span>9:41</span><span class="status-icons"><svg viewBox="0 0 20 14" fill="currentColor"><path d="M1 10h3v4H1zm5-3h3v7H6zm5-3h3v10h-3zm5-3h3v13h-3z"/></svg><svg viewBox="0 0 22 12" fill="none" stroke="currentColor"><rect x="1" y="1" width="17" height="10" rx="2"/><path d="M20 4v4"/><path fill="currentColor" d="M3 3h13v6H3z"/></svg></span></div><header class="app-header"><span class="wordmark">hope</span><span class="sim-label">LOCAL SIMULATION</span></header>
<div class="view" id="talk-view"><div class="talk"><div class="state-line"><span id="state-label" role="status">READY WHEN YOU ARE</span><span id="timer">00:00</span></div><div class="voice-zone"><h2 id="voice-title"><span>Go ahead.</span><span>I’m listening.</span></h2><svg class="wave" viewBox="0 0 320 85" role="img" aria-label="Voice signal: ready"><line x1="0" x2="320" y1="43" y2="43"/><path id="wave-path" d="M0 43 L320 43"/></svg><p class="voice-hint" id="voice-hint">Tap to begin a simulated conversation</p></div><div class="session-controls"><button class="primary" id="start"><svg aria-hidden="true"><use href="#mic"/></svg><span>Start talking</span></button><button class="secondary" id="mute" hidden aria-pressed="false">Mute</button><button class="primary" id="end" hidden>End conversation</button></div><div class="transcript-area"><div class="transcript-header"><p>SAMPLE CONVERSATION</p><div class="mode-toggle" aria-label="Conversation input"><button id="voice-mode" aria-pressed="true">Voice</button><button id="text-mode" aria-pressed="false">Text</button></div></div><div class="messages" id="messages" role="log" aria-label="Conversation transcript" aria-live="polite"><article class="message"><div class="who">YOU <span>09:40</span></div><p>Help me make a little room in my day.</p></article><article class="message answer"><div class="who">HOPE <span>09:40</span></div><p>Let’s start with one thing. What can wait until tomorrow?</p></article></div><form class="composer" id="composer" hidden><input id="text-input" aria-label="Message Hope" placeholder="Think out loud, in text…" maxlength="1200" autocomplete="off"><button type="submit" aria-label="Send message">↑</button></form></div></div></div>
<div class="view inner-view" id="activity-view" hidden><h2>Activity</h2><p class="view-description">A quiet place for the things you’ve asked Hope to work on.</p><article class="task"><div class="task-top"><span>A little room in your day</span><span class="task-tag" id="task-status">READY</span></div><p id="task-description">A sample task. Start a conversation to watch its progress.</p><progress id="task-progress" max="100" value="0" aria-label="Sample task progress"></progress><button id="task-toggle" aria-expanded="false">View steps</button><div class="task-detail" id="task-detail" hidden><p>1. Listen to what needs your attention<br>2. Find one thing that can wait<br>3. Write a simple next step</p></div></article><article class="task"><div class="task-top"><span>Weekend walking ideas</span><span class="task-tag">DONE</span></div><p>Three easy ways to get outside.<br>Yesterday · 4:12 PM · Sample data</p><button id="sample-result" aria-expanded="false">Read result</button><div id="sample-detail" class="task-detail" hidden><p>Take a short park loop, walk to a nearby café, or try a new neighborhood. Pick the easiest one and leave the rest for another day.</p></div></article><p class="sample-caption">Demo tasks only. Nothing is scheduled or saved.</p></div>
<div class="view inner-view" id="settings-view" hidden><h2>Settings</h2><p class="view-description">Make the conversation feel like yours.</p><div class="setting"><label for="voice-choice">Hope’s voice</label><select id="voice-choice"><option>Ava · warm & clear</option><option>Andrew · calm & grounded</option><option>Emma · bright & natural</option></select><button id="preview" class="secondary" style="margin-top:12px;width:100%">Preview voice · simulation</button><p class="feedback" id="voice-feedback" role="status"></p></div><div class="setting"><label for="speed">Speaking pace <span id="speed-label" style="float:right;font-family:var(--mono)">1.0×</span></label><input type="range" id="speed" min="0.8" max="1.2" step="0.1" value="1"><small>Give each thought a little breathing room.</small></div><div class="setting setting-row"><span class="setting-name">Keep transcript visible</span><button id="transcript-switch" class="switch" role="switch" aria-checked="true" aria-label="Keep transcript visible"></button></div><div class="setting"><span class="setting-name">Demo account</span><small>[email protected] · Sample data<br>Settings apply only to this open demo.</small><button class="signout" id="signout">Sign out · simulated</button><div class="account-confirm" id="account-confirm" hidden>Simulate signing out? Your real account is never accessed.<br><button id="confirm-signout">Simulate sign out</button> <button id="cancel-signout">Cancel</button></div><p id="account-feedback" class="feedback" role="status"></p></div></div>
<nav class="nav" aria-label="Main sections"><button data-view="talk" aria-current="page"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M3 12h2l2-5 3 10 3-13 3 15 2-7h3"/></svg>Talk</button><button data-view="activity"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 5h14M5 12h14M5 19h9"/><circle cx="19" cy="19" r="2"/></svg>Activity</button><button data-view="settings"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 6h16M4 12h16M4 18h16"/><path d="M8 3v6m8 0v6M10 15v6"/></svg>Settings</button></nav><div class="home-indicator" aria-hidden="true"></div></div></section></main>
<script>
'use strict';
const $=id=>document.getElementById(id);let state='idle',muted=false,seconds=0,timers=[],clock=null,phase=0;const reduced=matchMedia('(prefers-reduced-motion: reduce)').matches;
function clearTimers(){timers.forEach(clearTimeout);timers=[];clearInterval(clock);clock=null;}
function later(fn,delay){timers.push(setTimeout(fn,delay));}
function message(role,text){const article=document.createElement('article');article.className='message'+(role==='HOPE'?' answer':'');const who=document.createElement('div');who.className='who';who.textContent=role+' · DEMO';const p=document.createElement('p');p.textContent=text;article.append(who,p);$('messages').append(article);$('messages').scrollTop=$('messages').scrollHeight;}
function title(a,b){$('voice-title').replaceChildren();[a,b].forEach(text=>{if(text){const span=document.createElement('span');span.textContent=text;$('voice-title').append(span);}});}
function task(value,status,description){$('task-progress').value=value;$('task-status').textContent=status;$('task-description').textContent=description;}
function render(){const active=state!=='idle';$('start').hidden=active;$('mute').hidden=!active;$('end').hidden=!active;$('mute').textContent=muted?'Unmute':'Mute';$('mute').setAttribute('aria-pressed',String(muted));const descriptions={idle:'ready',listening:'listening',working:'working',answer:'answering'};document.querySelector('.wave').setAttribute('aria-label','Voice signal: '+(muted?'muted':descriptions[state]));if(muted){$('state-label').textContent='MICROPHONE MUTED · DEMO';title('Take your time.','I’m here.');$('voice-hint').textContent='Unmute to continue the simulation';}else if(state==='idle'){$('state-label').textContent='READY WHEN YOU ARE';title('Go ahead.','I’m listening.');$('voice-hint').textContent='Tap to begin a simulated conversation';}else if(state==='listening'){$('state-label').textContent='LISTENING · DEMO';title('Go ahead.','I’m listening.');$('voice-hint').textContent='Sample voice input · no microphone access';}else if(state==='working'){$('state-label').textContent='WORKING · DEMO';title('One thought','at a time.');$('voice-hint').textContent='Finding a little room in your day';}else{$('state-label').textContent='HOPE IS SPEAKING · DEMO';title('Make room','for what matters.');$('voice-hint').textContent='Simulated answer · no audio is played';}draw();}
function draw(){let d='';for(let x=0;x<=320;x+=2){const envelope=Math.pow(Math.sin(Math.PI*x/320),4);let y=43;if(state!=='idle'&&!muted){const amp=state==='listening'?23:state==='working'?6:17;y+=Math.sin(x*.18+phase)*Math.sin(x*.035+phase*.4)*envelope*amp;}d+=(x?' L':'M')+x+' '+y.toFixed(2);}$('wave-path').setAttribute('d',d);}
function stages(){later(()=>{if(state!=='listening'||muted)return;message('YOU','Help me make a little room in my day.');state='working';task(45,'WORKING','Finding one thing you can move to tomorrow.');render();later(()=>{if(state!=='working'||muted)return;state='answer';task(100,'DONE','One next step, ready to read in your transcript.');message('HOPE','You don’t have to do it all today. Move one non-urgent task to tomorrow, and keep ten minutes just for yourself.');render();later(()=>{if(state==='answer'&&!muted){state='listening';render();$('voice-hint').textContent='Try text, or end when you’re ready';}},4500);},2300);},3000);}
function start(){clearTimers();muted=false;state='listening';seconds=0;$('timer').textContent='00:00';task(15,'LISTENING','Listening to the sample request.');clock=setInterval(()=>{seconds++;$('timer').textContent=String(Math.floor(seconds/60)).padStart(2,'0')+':'+String(seconds%60).padStart(2,'0');},1000);render();stages();}
$('start').onclick=start;$('end').onclick=()=>{clearTimers();state='idle';muted=false;render();$('state-label').textContent='CONVERSATION ENDED · DEMO';$('voice-hint').textContent='Your sample transcript is still here';};
$('mute').onclick=()=>{muted=!muted;timers.forEach(clearTimeout);timers=[];render();if(!muted){state='listening';render();stages();}};
document.querySelectorAll('[data-view]').forEach(button=>button.onclick=()=>{document.querySelectorAll('[data-view]').forEach(b=>b.removeAttribute('aria-current'));button.setAttribute('aria-current','page');['talk','activity','settings'].forEach(v=>$(v+'-view').hidden=v!==button.dataset.view);});
function mode(text){$('composer').hidden=!text;$('voice-mode').setAttribute('aria-pressed',String(!text));$('text-mode').setAttribute('aria-pressed',String(text));$('messages').hidden=false;if(text)$('text-input').focus();}
$('voice-mode').onclick=()=>mode(false);$('text-mode').onclick=()=>mode(true);
$('composer').onsubmit=event=>{event.preventDefault();const input=$('text-input').value.trim();if(!input)return;message('YOU',input);$('text-input').value='';timers.forEach(clearTimeout);timers=[];state='working';muted=false;task(50,'WORKING','Preparing a local sample reply to your text.');render();later(()=>{state='answer';task(100,'DONE','Sample text reply added to the transcript.');message('HOPE','This is a local sample reply. Take one small next step, and let the rest wait for a moment.');render();later(()=>{clearInterval(clock);clock=null;state='idle';render();},3500);},1500);};
$('task-toggle').onclick=()=>{const show=$('task-detail').hidden;$('task-detail').hidden=!show;$('task-toggle').setAttribute('aria-expanded',String(show));$('task-toggle').textContent=show?'Hide steps':'View steps';};$('sample-result').onclick=()=>{const show=$('sample-detail').hidden;$('sample-detail').hidden=!show;$('sample-result').setAttribute('aria-expanded',String(show));$('sample-result').textContent=show?'Hide result':'Read result';};
$('voice-choice').onchange=()=>{$('voice-feedback').textContent='Demo voice changed to '+$('voice-choice').value.split(' · ')[0]+'.';};$('preview').onclick=()=>{$('voice-feedback').textContent='“Take your time. I’m here.” — '+$('voice-choice').value.split(' · ')[0]+'. Text preview only; no audio is played.';};$('speed').oninput=()=>{$('speed-label').textContent=Number($('speed').value).toFixed(1)+'×';};$('transcript-switch').onclick=()=>{const on=$('transcript-switch').getAttribute('aria-checked')!=='true';$('transcript-switch').setAttribute('aria-checked',String(on));$('messages').hidden=!on;};$('signout').onclick=()=>{$('account-confirm').hidden=false;};$('cancel-signout').onclick=()=>{$('account-confirm').hidden=true;};$('confirm-signout').onclick=()=>{clearTimers();state='idle';muted=false;render();$('account-confirm').hidden=true;$('account-feedback').textContent='Simulated sign out complete. No real account was changed.';};
if(!reduced){setInterval(()=>{if(state!=='idle'&&!muted){phase+=.3;draw();}},90);}render();
</script></body></html>