44 lines
35 KiB
HTML
44 lines
35 KiB
HTML
<!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-shadow:0 0 0 2px #b59bcf,0 5px 22px #69587814}.composer .mic-button{border-radius:50%;background:#f1e9f8;width:44px;color:#725199}.composer .send-button{border-radius:50%;background:#76579d;color:#fff;width:44px}.simulation{font-size:10px;text-align:center;color:#796e84;margin:12px 0 0}.home-indicator{position:absolute;bottom:9px;left:50%;transform:translateX(-50%);width:125px;height:4px;background:#292331;border-radius:4px}.device-caption{text-align:center;font-size:11px;color:#756982;margin:20px 0 0}.page-heading{font-size:29px;letter-spacing:-.035em;font-weight:450;margin:22px 0 10px}.page-description{color:var(--muted);font-size:13px;line-height:1.7;margin:0 0 25px}.back{display:flex;gap:7px;align-items:center;padding:0;color:#77608d;font-size:12px}.back svg{width:17px}.history-label{font-size:12px;color:#7d7188;margin:25px 0 8px}.history-row{display:flex;align-items:center;width:100%;text-align:left;padding:16px 0;gap:15px;border-bottom:1px solid #f0edf4;border-radius:0}.history-row .history-symbol{width:39px;height:39px;background:#f4effa;border-radius:50%;display:grid;place-items:center;color:#9779b1}.history-symbol svg{width:20px}.history-row strong{font-size:14px;font-weight:500;display:block}.history-row small{font-size:11px;color:var(--muted);display:block;margin-top:7px}.history-row .chevron{margin-left:auto;width:17px;color:#94869e}.thread-title{font-size:23px;font-weight:450;letter-spacing:-.025em;margin:15px 0 20px}.transcript{display:flex;flex-direction:column;gap:20px;padding-bottom:24px}.message{font-size:14px;line-height:1.65;max-width:94%}.message small{display:block;font-size:10px;font-weight:500;color:#786a88;margin-bottom:6px}.message p{margin:0}.message.you{background:#f5f0fa;padding:13px 17px;border-radius:16px 16px 4px 16px;align-self:flex-end}.message.hope{padding:0 5px;align-self:flex-start}.settings-group{margin-top:26px}.settings-group h3{font-size:12px;font-weight:500;color:#786a88;margin-bottom:10px}.setting{min-height:72px;display:flex;align-items:center;justify-content:space-between;gap:15px;border-bottom:1px solid #eeebf2}.setting span{font-size:14px}.setting small{display:block;color:var(--muted);font-size:11px;margin-top:6px;line-height:1.5}.setting select{height:44px;border:0;border-radius:10px;background:#f3eef9;color:#685079;padding:0 9px;font-size:12px}.setting input{accent-color:#8764af;width:22px;height:22px;cursor:pointer}.settings-footer{font-size:12px;line-height:1.8;color:var(--muted);margin-top:26px}.settings-save{width:100%;border-radius:30px;background:#f1e9f8;color:#705088;margin-top:20px;font-size:13px}.saved-note{font-size:12px;text-align:center;color:#705088;margin-top:12px;min-height:20px}.live{position:absolute;inset:52px 0 21px;z-index:3;background:#fff;display:flex;flex-direction:column;align-items:center;padding:20px 26px 14px}.live-top{width:100%;display:flex;align-items:center;justify-content:space-between;font-size:13px}.live-top span{color:#786b86;font-size:11px}.live-pearl{width:142px;height:150px;margin-top:30px}.live h2{font-size:27px;letter-spacing:-.025em;font-weight:400;margin:10px 0}.live-state{font-size:12px;color:#796489;display:flex;gap:6px;align-items:center}.state-dot{width:5px;height:5px;border-radius:50%;background:#a78cc3}.elapsed{font-variant-numeric:tabular-nums;color:#8c7f95;font-size:11px;margin-top:10px}.ribbon{width:310px;height:67px;margin-top:13px;overflow:visible}.live-log{width:100%;overflow:auto;flex:1;min-height:0;padding:14px 4px 0;scrollbar-width:thin}.live-log .message{margin-bottom:18px;font-size:13px}.live-controls{display:flex;align-items:center;justify-content:center;gap:28px;padding-top:20px}.control-group{text-align:center;font-size:10px;color:#796c86}.control-group button{display:grid;place-items:center;width:54px;height:54px;border-radius:50%;background:#f4eff9;margin-bottom:9px}.control-group .listen{width:65px;height:65px;background:#eee2f5;box-shadow:0 0 0 7px #faf5fc}.control-group .end{background:#fbedf1;color:#a66b7d}.live-note{font-size:10px;color:#7b6e85;margin:18px 0 0}.listening .ribbon{animation:breathe 3s ease-in-out infinite}.listening .live-pearl{animation:pearl-breathe 4s ease-in-out infinite}@keyframes breathe{50%{transform:scaleY(.65);opacity:.65}}@keyframes pearl-breathe{50%{transform:translateY(-4px)}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap}
|
||
@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?'Hope is replying · simulated':'Sample reply ready','One small thing at a time.');},3200);schedule(()=>{state('Listening','What’s on your mind now?');$('voice-turn').disabled=false;},5200)}function startVoice(){cancel();muted=false;seconds=0;active={title:'A little room in my day',when:'Just now · Voice demo',messages:[]};live.hidden=false;$('composer').inert=true;content.inert=true;document.querySelector('.app-header').inert=true;$('live-log').replaceChildren();$('elapsed').textContent='00:00';$('mute-button').setAttribute('aria-pressed','false');$('mute-button').setAttribute('aria-label','Mute simulated microphone');$('mute-label').textContent='Mute';$('voice-turn').disabled=false;interval=setInterval(()=>{seconds++;$('elapsed').textContent=String(Math.floor(seconds/60)).padStart(2,'0')+':'+String(seconds%60).padStart(2,'0')},1000);$('mute-button').focus();turn()}function endVoice(){cancel();clearInterval(interval);interval=null;live.hidden=true;$('composer').inert=false;content.inert=false;document.querySelector('.app-header').inert=false;if(active.messages.length){history.unshift(active);renderThread(active);announce('Conversation ended. Demo transcript saved in history.')}else{home();announce('Conversation ended. Your microphone was never accessed.')} $('composer-mic').focus()}
|
||
$('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> |