| 1 | <!doctype html> |
| 2 | <html lang="en"> |
| 3 | <head> |
| 4 | <meta charset="utf-8"> |
| 5 | <meta name="viewport" content="width=device-width, initial-scale=1"> |
| 6 | <meta name="theme-color" content="#f6f7fb" media="(prefers-color-scheme: light)"> |
| 7 | <meta name="theme-color" content="#15171c" media="(prefers-color-scheme: dark)"> |
| 8 | <title>Signing in</title> |
| 9 | <link rel="stylesheet" href="/static/home.css"> |
| 10 | </head> |
| 11 | <body> |
| 12 | <main class="card"> |
| 13 | <!-- The tile names which chat is being unlocked (restore payloads carry no |
| 14 | photo, so the chat glyph stands in). --> |
| 15 | <div class="entry" id="entry"> |
| 16 | <div class="entry-badge"> |
| 17 | <div class="entry-glyph" aria-hidden="true"> |
| 18 | <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M7.9 20A9 9 0 1 0 4 16.1L2 22Z"/></svg> |
| 19 | </div> |
| 20 | <div class="badge" id="badge" aria-hidden="true"> |
| 21 | <svg class="key" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m21 2-9.6 9.6"/><circle cx="7.5" cy="15.5" r="5.5"/><path d="m15.5 7.5 3 3L22 7l-3-3"/></svg> |
| 22 | <svg class="check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg> |
| 23 | </div> |
| 24 | </div> |
| 25 | <div class="name" id="entry-host"></div> |
| 26 | </div> |
| 27 | |
| 28 | <h1 id="headline">Signing in…</h1> |
| 29 | <p class="sub" id="sub">Your face or fingerprint is the key. Not even this |
| 30 | server can see inside your spaces.</p> |
| 31 | |
| 32 | <!-- The user already chose "Sign in" on their chat's page, so the ceremony |
| 33 | starts on load — this page is a loading screen, not a second decision. |
| 34 | The button is the fallback for a blocked/cancelled prompt (restore.js |
| 35 | reveals it), and there is deliberately NO create-a-passkey path here: |
| 36 | this flow is sign-IN only (keys are created during onboarding/enrol). --> |
| 37 | <div class="actions hidden" id="actions"> |
| 38 | <button id="restore">Sign in</button> |
| 39 | </div> |
| 40 | |
| 41 | <!-- Inline status only — never a floating toast (product-wide rule). --> |
| 42 | <p class="status" id="status"></p> |
| 43 | |
| 44 | <!-- CLI paste handoff: a terminal with no reachable loopback (SSH) gets the |
| 45 | sealed session as a code to copy back. It's ciphertext to everyone but |
| 46 | the terminal holding the ephemeral private key, so showing it is safe. --> |
| 47 | <div class="code-wrap hidden" id="code-wrap"> |
| 48 | <textarea id="code" class="code" readonly rows="4" spellcheck="false" aria-label="Sign-in code for your terminal"></textarea> |
| 49 | <button id="copy" class="secondary">Copy code</button> |
| 50 | </div> |
| 51 | </main> |
| 52 | <script type="module" src="/static/restore.js"></script> |
| 53 | </body> |
| 54 | </html> |
| 55 | |