diff --git a/public/neu/ansichten.css b/public/neu/ansichten.css index 675d9b1..7467b6a 100644 --- a/public/neu/ansichten.css +++ b/public/neu/ansichten.css @@ -86,6 +86,7 @@ /* Auftrag, Änderungen, Arbeiten, Aktivität */ .kn-aktivitaet { margin: 0; } +[data-abschnitt="aktivitaet"] { scroll-margin-top: 16px; } /* #fortschritt: scrollIntoView lässt den Abschnitt nicht hinter dem haftenden Kopf beginnen (am Handy unten) */ .kn-auftrag-karte { padding: 16px 0; border-top: 1px solid var(--kn-line); } .kn-auftrag-karte > .kn-auftrag + * { margin-top: 12px; } .kn-auftrag-kopf { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; } @@ -362,6 +363,7 @@ .kn-pw { max-width: none; } .kn-tk-feld input:not([type="checkbox"]):not([type="file"]) { height: 44px; font-size: 16px; } .kn-stepper .kn-knopf { min-width: 44px; } + [data-abschnitt="aktivitaet"] { scroll-margin-top: calc(var(--kn-banner-h) + var(--kn-kopf-h) + env(safe-area-inset-top) + 8px); } /* Bestellseiten (F1): Kerninfo und Knopf müssen im nutzbaren Bereich zwischen Kopf und Leiste zusammen stehen (375 x 667: gut 550 px). Darum läuft die Beschriftung in der Zeile mit (Label: Text) statt eine eigene Zeile zu brauchen, und der Abstand ist knapp. */ .kn-bestellen > h2 { margin: 0 0 6px; font-size: 17px; line-height: 24px; font-weight: 600; } diff --git a/public/neu/huelle.css b/public/neu/huelle.css index adc92f4..074706d 100644 --- a/public/neu/huelle.css +++ b/public/neu/huelle.css @@ -186,6 +186,9 @@ @media (prefers-reduced-motion: reduce) { .kn-gleiter, .kn-overlay, .kn-rw, .kn-t { transition: none; } + /* E-Fix M7: die Regel der beiden Fahrstuhl-Zeilen hat Spezifität 1-2-0 und schlug das .kn-rw oben; sie fuhr trotz „Bewegung reduziert“ noch 550 ms. + Gleiche Selektoren, später im Blatt: die Zeilen tauschen sofort (kein Verzug der Sichtbarkeit), nichts gleitet durch die andere Zeile. */ + .kn-leiste-reel[data-etage="offen"] #kn-zeile-haupt, .kn-leiste-reel:not([data-etage="offen"]) #kn-zeile-etage { transition: none; } .kn-blatt { transform: none; opacity: 0; transition: opacity 150ms; } .kn-blatt--auf { opacity: 1; } .kn-konto-scrim, .kn-konto { animation: kn-einblenden 150ms ease-out; } diff --git a/test/knAnsichtStil.test.js b/test/knAnsichtStil.test.js index 126068e..6ebcd90 100644 --- a/test/knAnsichtStil.test.js +++ b/test/knAnsichtStil.test.js @@ -13,7 +13,7 @@ const VERBOTEN = /linear-gradient|radial-gradient|conic-gradient|backdrop-filter test('Stil: keine verbotenen Mittel (Verläufe, Glas, Dunkelmodus, Lila, Gewicht 800), auch nicht in der Kopie des Composer-CSS', () => { for (const [n, c] of [['ansichten.css', A], ['oeffentlich.css', O], ['chat-composer.css', C]]) assert.doesNotMatch(c, VERBOTEN, n) }) test('Stil: Farbliterale nur in Custom-Property-Deklarationen, jedes benutzte Token ist definiert', () => { for (const [n, c] of [['ansichten.css', A], ['oeffentlich.css', O]]) for (const z of c.split('\n')) if (!/^\s*--kn-[\w-]+:/.test(z)) assert.doesNotMatch(z, /#[0-9a-f]{3,8}\b|rgba?\(/i, `${n}: ${z.trim()}`) - const definiert = new Set([...(TOKENS + A + O).matchAll(/(--kn-[\w-]+)\s*:/g)].map((m) => m[1])) + const definiert = new Set([...(TOKENS + A + O + css('huelle.css')).matchAll(/(--kn-[\w-]+)\s*:/g)].map((m) => m[1])) // die Maße der Hülle (--kn-kopf-h, --kn-banner-h) stehen in huelle.css for (const m of (A + O).matchAll(/var\((--kn-[\w-]+)/g)) assert.ok(definiert.has(m[1]), m[1]) }) test('Stil: jede kn-Klasse der P2-Module hat eine Regel', () => { diff --git a/test/knEfixCss.test.js b/test/knEfixCss.test.js index b7fc09d..37e157e 100644 --- a/test/knEfixCss.test.js +++ b/test/knEfixCss.test.js @@ -87,3 +87,11 @@ test('M4: der Mitarbeiter-Banner steht oben (sticky), Kopf, Menü, Blatt und Kon const js = quelle('huelle.js') assert.match(js, /setProperty\?\.\('--kn-banner-h'/) }) + +test('M7: Bewegung reduziert nimmt auch die Fahrt der Fahrstuhl-Zeilen (Spezifität gleich, später im Blatt); #fortschritt hat scroll-margin-top für den haftenden Kopf', () => { + const reduziert = HUELLE.slice(HUELLE.indexOf('@media (prefers-reduced-motion: reduce)')) + assert.match(reduziert, /\.kn-leiste-reel\[data-etage="offen"\] #kn-zeile-haupt,\s*\.kn-leiste-reel:not\(\[data-etage="offen"\]\) #kn-zeile-etage\s*\{\s*transition:\s*none/) + const A = lies('ansichten.css') + assert.match(A, /\n\[data-abschnitt="aktivitaet"\] \{ scroll-margin-top: 16px/) + assert.match(handyTeil(A), /\[data-abschnitt="aktivitaet"\] \{ scroll-margin-top: calc\(var\(--kn-banner-h\) \+ var\(--kn-kopf-h\) \+ env\(safe-area-inset-top\) \+ 8px\)/) +})