Add full-screen API-key gate

In user-key mode a browser with no stored Ollama key now gets a polished
gate instead of the app shell: one masked input with a show/hide toggle,
a single Continue button, inline validation errors, and a "?" help sheet
with the steps to a free key.

- Validates the draft key through /api/health (real 1-token probe) before
  saving; invalid-key and network failures read differently.
- Key still lives only in this browser's localStorage; nothing server-side.
- Gate wraps /, /create and deck study; server-key and local-daemon modes
  skip it; removing the key in Settings brings it back.
- Removes the now-redundant dashboard/create API-key banner.
- Monochrome corner glows (dark near-black / light near-white), 24px card,
  48px field and button, gentle fade/slide-in, reduced-motion aware.
- Help modal: centred dialog on desktop, bottom sheet on mobile, closes via
  X, Escape or backdrop.
- README and browser suites updated (34 gate checks, 15 key-flow checks,
  12 shipped-default checks; ui/folders/docs/pwa/security/contrast green).
This commit is contained in:
Martin Dvořák 2026-10-06 21:20:22 +00:00
commit dfa7b7502a
13 changed files with 505 additions and 94 deletions

View file

@ -102,6 +102,13 @@
--sidebar-top: #fbfbfc;
--sidebar-bottom: #f6f6f7;
--sidebar-edge: 0 1px 0 var(--hairline), 6px 0 16px -14px rgb(13 13 13 / 0.28);
/* API-key gate: near-white stage with soft blank glows, tinted input. */
--gate-base: #f7f7f8;
--gate-glow-a: rgb(64 74 90 / 0.1);
--gate-glow-b: rgb(96 108 124 / 0.07);
--field: #f3f3f4;
--field-border: #e2e2e4;
--shadow-gate: 0 28px 70px -36px rgb(13 13 13 / 0.35), 0 1px 2px rgb(13 13 13 / 0.05);
--shadow-card: 0 1px 2px rgb(13 13 13 / 0.06), 0 1px 3px rgb(13 13 13 / 0.04);
--shadow-card-hover: 0 10px 28px -14px rgb(13 13 13 / 0.22), 0 1px 2px rgb(13 13 13 / 0.06);
}
@ -123,6 +130,13 @@
--sidebar-top: #1a1a1a;
--sidebar-bottom: #151515;
--sidebar-edge: 0 1px 0 var(--hairline), 6px 0 16px -14px rgb(0 0 0 / 0.75);
/* API-key gate: near-black stage, monochrome glows, raised input. */
--gate-base: #0d0d0e;
--gate-glow-a: rgb(255 255 255 / 0.075);
--gate-glow-b: rgb(255 255 255 / 0.05);
--field: #383838;
--field-border: rgb(255 255 255 / 0.12);
--shadow-gate: 0 30px 80px -40px rgb(0 0 0 / 0.9), 0 1px 2px rgb(0 0 0 / 0.4);
--shadow-card: 0 1px 2px rgb(0 0 0 / 0.25);
--shadow-card-hover: 0 10px 28px -16px rgb(0 0 0 / 0.55), 0 1px 2px rgb(0 0 0 / 0.3);
}
@ -172,6 +186,16 @@ body {
background: transparent;
}
/* API-key gate stage: monochrome radial glows in opposite corners over a
near-black (dark) or near-white (light) base. Radial gradients are the
softest "blurred glow" available without extra layers. */
.gate-bg {
background:
radial-gradient(64rem 46rem at 112% -12%, var(--gate-glow-a), transparent 68%),
radial-gradient(58rem 42rem at -12% 112%, var(--gate-glow-b), transparent 70%),
var(--gate-base);
}
.app-backdrop {
position: fixed;
inset: 0;