v0.319.0: the app page in panels, the login in one place, a password the box never had is said in words
gates / gates (push) Successful in 52s

- style A (operator 2026-10-16): hero, tab bar and every section are panels on --bg-1, one width, 16px apart;
  the install page's form groups use the same rule; the settings tab's 700px inner wrapper is gone
- „Belépés az alkalmazásba": name + password side by side, fetched on demand (R-254, R-709); pairing in app_login.go
- the empty-value rule: no stored value -> a sentence, never an eye; page and reveal endpoint share storedValuePresent
- „Cím és kulcsok" is rows (no Domain input, no disabled storage select, no install form); hint under the title
- tests red-proved: app_page_tuning_test.go (4); 36 app-page parity fixtures re-captured, 4 new; install fixtures unchanged

Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb
This commit is contained in:
2026-10-16 12:12:06 +02:00
parent 8d44416610
commit d170a2aecf
58 changed files with 6046 additions and 1776 deletions
+63 -35
View File
@@ -1300,13 +1300,17 @@ a.stat-card:hover {
.login-footer a:hover { color: var(--blue); }
/* --- App Info Page --- */
/* ── THE APP PAGE (v0.316.0) — one column, hairlines, boxes only where they mean something ───────
Operator-approved mockup, 2026-10-15. The rules, and why each one:
ONE COLUMN of ONE WIDTH. Boxes of different widths read as a page assembled by accident.
SECTIONS ARE SEPARATED BY HAIRLINES, not drawn as cards. A card says "this is a thing you act
on"; most of an app page is a thing you READ, so a card there is a promise it cannot keep.
A BOX MEANS SOMETHING. Exactly two exist: blue when the app is waiting for the household, amber
when something is risky. The exception-colour principle, applied to shape as well as colour.
/* ── THE APP PAGE (v0.319.0) — one column, the header, the tab bar and every section a panel ─────
Operator-approved mockup „Felhom app oldal — egy oszlop", 2026-10-16, section style A. The rules:
ONE COLUMN of ONE WIDTH. Every panel is the column's full width; panels of different widths
read as a page assembled by accident.
PANELS ON --bg-1. v0.316.0's hairline sections sat on the page background with the header and
the tab bar, and the operator found the page flat: nothing told one section from the next.
Now the hero, the tab bar and each section are their own panel, 16px apart.
ONE SECTION STYLE ON EVERY SURFACE — the four tabs and the install page. Never mixed. Pinned by
TestAppPage_OneSectionStyleEverywhere.
COLOUR STILL MEANS SOMETHING. A panel is neutral; blue is the app waiting for the household,
amber is a risk. The callouts keep their colours inside or as a panel.
Tokens only — no raw hexes, 2px radius, no shadows. */
.app-page {
@@ -1330,18 +1334,23 @@ a.stat-card:hover {
}
.app-back:hover { color: var(--text-1); }
/* HERO — no box, no border. The app's identity is a heading, not a card. */
/* HERO — its own panel. */
.app-hero {
display: flex;
align-items: flex-start;
gap: 20px;
flex-wrap: wrap;
background: var(--bg-1);
border: 1px solid var(--line);
border-radius: var(--radius);
padding: 20px 24px;
margin-top: 16px;
}
.app-hero-logo {
width: 64px; height: 64px;
min-width: 64px;
border: 1px solid var(--line);
background: var(--bg-1);
background: var(--bg-2);
border-radius: var(--radius);
object-fit: contain;
padding: 8px;
@@ -1364,40 +1373,62 @@ a.stat-card:hover {
worked. A success that needed no decision is not news; it is a date. */
.app-meta { font-size: 12px; color: var(--text-3); }
/* TABS — links with a line under the open one. No pills, no fills. */
/* TABS — a panel; the open tab is filled and underlined. */
.app-tabs {
display: flex;
gap: 28px;
gap: 4px;
flex-wrap: wrap;
margin: 28px 0 8px;
border-bottom: 1px solid var(--line);
background: var(--bg-1);
border: 1px solid var(--line);
border-radius: var(--radius);
padding: 4px;
margin: 16px 0 20px;
}
.app-tab {
font-size: 15px; font-weight: 600;
padding: 12px 0;
padding: 10px 18px;
color: var(--text-2);
text-decoration: none;
border-radius: var(--radius);
border-bottom: 2px solid transparent;
margin-bottom: -1px;
white-space: nowrap;
}
.app-tab:hover { color: var(--text-1); }
.app-tab-active { color: var(--text-1); border-bottom-color: var(--blue-bright); }
.app-tab-active { color: var(--text-1); background: var(--bg-2); border-bottom-color: var(--blue-bright); }
/* SECTIONS — a hairline between, nothing around. */
.app-section {
padding: 28px 0;
border-bottom: 1px solid var(--line-soft);
background: none;
border-left: 0; border-right: 0; border-top: 0;
border-radius: 0;
margin: 0;
/* SECTIONS — style A: each its own panel, the column's width, 16px apart, the title 18px from the
top edge with a soft rule under it. The install page's form groups (.form-section inside the
wizard's form) and its progress panel are the same panel: one style on every surface. */
.app-section,
.app-page .deploy-form .form-section,
.app-page .deploy-progress {
padding: 18px 24px 22px;
background: var(--bg-1);
border: 1px solid var(--line);
border-radius: var(--radius);
margin: 0 0 16px;
}
.app-section:last-child { border-bottom: 0; }
.app-section > h3, .app-section > h4 {
font-size: 17px; font-weight: 700; color: var(--text-1); margin: 0 0 6px;
.app-section > h3:first-child, .app-section > h4:first-child,
.app-page .deploy-form .form-section > h4:first-child,
.app-page .deploy-progress > h3:first-child {
font-size: 17px; font-weight: 700; color: var(--text-1);
margin: 0 0 12px;
padding-bottom: 10px;
border-bottom: 1px solid var(--line-soft);
}
/* A heading further down a panel is a sub-heading, not a second title. */
.app-section > h3:not(:first-child), .app-section > h4:not(:first-child) {
font-size: 14px; font-weight: 600; color: var(--text-1); margin: 16px 0 6px;
}
.app-section > p { font-size: 14px; color: var(--text-2); line-height: 1.55; margin: 0 0 16px; }
.app-section > :last-child { margin-bottom: 0; }
/* The install wizard's form was one box around all its groups; the groups are the panels now. */
.app-page .deploy-form { background: none; border: 0; padding: 0; }
/* THE LOGIN PAIR — the name and the password side by side, stacked on a phone. */
.app-login-pair { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; }
.app-login-field { min-width: 0; }
.app-login-label { display: block; font-size: 13px; color: var(--text-2); margin-bottom: 6px; }
/* ROWS — label and value, one grid so every value on the page starts at the same x. */
.app-field-row {
@@ -1418,17 +1449,13 @@ a.stat-card:hover {
font-size: 14px;
border: 1px solid var(--line);
}
.app-callout > h3, .app-callout > h4 { font-size: 15px; font-weight: 700; margin: 0 0 6px; color: var(--text-1); }
.app-callout > h3, .app-callout > h4 { font-size: 15px; font-weight: 700; margin: 0 0 6px; color: var(--text-1); padding-bottom: 0; border-bottom: 0; }
/* „The app is waiting for you" — a request, never a fault, so blue and never amber. */
.app-callout-ask { border-color: var(--blue); background: var(--blue-dim); }
/* „Something here is risky" — the exception colour, and only on a deviation. */
.app-callout-warn { border-color: var(--warn); background: var(--warn-dim); }
/* The settings tab reuses the install wizard's field markup, which carries that page's boxes: a
card around the whole form and one around every generated value. On a TAB those are sections, so
the boxes come off — the input itself is still a field, which is what tells the household it is a
value. Scoped to .app-section, so the install page (same column, its own form) is untouched. */
.app-section .deploy-form,
/* A box inside a panel would be a narrower inner card; the panel is the box. */
.app-section .form-group-auto,
.app-section .app-optional-config,
.app-section .deploy-storage-info,
@@ -1450,8 +1477,9 @@ a.stat-card:hover {
.app-page { padding: 0 0 24px; }
.app-field-row { grid-template-columns: 1fr; gap: 4px; }
.app-hero-actions { margin-left: 0; flex-basis: 100%; }
.app-tabs { gap: 18px; }
.app-tab { font-size: 14px; }
.app-tab { font-size: 14px; padding: 8px 12px; }
.app-hero, .app-section, .app-page .deploy-form .form-section, .app-page .deploy-progress { padding-left: 16px; padding-right: 16px; }
.app-login-pair { grid-template-columns: 1fr; }
}
.app-info-hero {