German page, and a section for the image module

/ and /de/ are now two pages from one shared component and one copy file, with
hreflang between them and a language button in the header. Separate URLs rather
than a runtime switch: each language is linkable and indexable, and the page
still works without JavaScript. The sheet playground takes its labels from the
page, so its readout says "29,7 cm" in German and "29.7 cm" in English.

New section for the `ai` module, because the page so far read as if Klarbild
were print-only. It says plainly what the module costs and that the endpoint is
configurable, and it carries a preset builder: pick tasks and a target size,
see the exact pixels and the recipe that gets saved. It composes; it does not
generate. A generator here would need a key on a public page and would show a
picture from a model rather than anything about Klarbild — the part worth
showing is the recipe.

The target pixels come from engine/format.ts, copied verbatim from the
application like the layout files.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nh4A79bbqT9dcd2inzYUdg
This commit is contained in:
Claude committed 2026-09-15 15:40:07 +00:00
1 parent 5ef5dd53a3
commit 880644e026
10 files changed
+1126 -372

No files matched your search

+43
View File
@@ -202,3 +202,46 @@ footer a { color: var(--ink-soft); text-decoration: none; font-size: 0.88rem; }
footer a:hover { color: var(--accent); }
footer .fine { font-size: 0.8rem; color: var(--ink-soft); margin-left: auto; }
@media (max-width: 620px) { footer .fine { margin-left: 0; width: 100%; } }
/* ------------------------------------------------- language switch & nav bits */
.top nav a.langswitch { font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: .08em;
border: 1px solid var(--line); padding: 6px 9px; border-radius: 999px; line-height: 1; }
.top nav a.langswitch:hover { color: var(--accent); border-color: var(--accent); background: transparent; }
@media (max-width: 980px) { .top nav a.hide-m { display: none; } }
/* ------------------------------------------------------------ preset builder */
.recipe { margin-top: clamp(28px, 4vw, 48px); }
.recipe-body { display: grid; grid-template-columns: minmax(0, 1fr); }
@media (min-width: 900px) { .recipe-body { grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr); } }
.recipe-controls { padding: 20px 18px; display: grid; gap: 18px; align-content: start; }
@media (min-width: 900px) { .recipe-controls { border-right: 1px solid var(--line); } }
.recipe-out { padding: 20px 18px; display: grid; gap: 14px; align-content: start;
background: repeating-linear-gradient(45deg, transparent 0 11px, oklch(21% 0.01 95 / 0.015) 11px 22px); }
.chips { display: flex; flex-wrap: wrap; gap: 6px; }
.chips button { font-family: inherit; font-size: 0.82rem; padding: 7px 11px; cursor: pointer;
border: 1px solid var(--line); border-radius: 999px; background: var(--paper); color: var(--ink-soft);
transition: border-color .15s, color .15s, background .15s; }
.chips button:hover { color: var(--ink); border-color: var(--ink-soft); }
.chips button[aria-pressed=true] { background: var(--accent-bg); border-color: var(--accent);
color: var(--accent); font-weight: 600; }
.tasklist { display: grid; gap: 6px; }
@media (min-width: 560px) { .tasklist { grid-template-columns: 1fr 1fr; } }
.tasklist button { display: grid; gap: 2px; text-align: left; font-family: inherit; cursor: pointer;
border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--paper);
padding: 10px 12px; transition: border-color .15s, background .15s; }
.tasklist button b { font-size: 0.92rem; color: var(--ink); font-weight: 600; }
.tasklist button em { font-style: normal; font-size: 0.78rem; color: var(--ink-soft); line-height: 1.4; }
.tasklist button[aria-pressed=true] { background: var(--accent-bg); border-color: var(--accent); }
.tasklist button[aria-pressed=true] b { color: var(--accent); }
.tasklist button[aria-pressed=true] b::after { content: ' ✓'; }
.tasklist button:disabled { opacity: .45; cursor: not-allowed; }
.readout.single { grid-template-columns: minmax(0, 1fr); }
.recipe-out pre { font-size: 0.78rem; line-height: 1.65; max-height: 280px; }
.mod-after { display: grid; gap: 22px; margin-top: 26px; align-items: start; }
@media (min-width: 880px) { .mod-after { grid-template-columns: minmax(0, 1fr) minmax(0, 0.8fr); gap: 40px; } }
.stackline { font-size: .84rem; color: var(--ink-soft); margin-top: 14px; }