diff --git a/public/neu/huelle.css b/public/neu/huelle.css index 9ced136..adc92f4 100644 --- a/public/neu/huelle.css +++ b/public/neu/huelle.css @@ -21,7 +21,7 @@ @media (max-width: 880px), (pointer: coarse) and (max-height: 500px) { .kn { --kn-unten: calc(var(--kn-zeile-h) + env(safe-area-inset-bottom)); } .kn-blatt { - position: fixed; inset: calc(var(--kn-kopf-h) + env(safe-area-inset-top)) 0 var(--kn-unten, var(--kn-zeile-h)); z-index: 20; + position: fixed; inset: calc(var(--kn-banner-h) + var(--kn-kopf-h) + env(safe-area-inset-top)) 0 var(--kn-unten, var(--kn-zeile-h)); z-index: 20; overflow-y: auto; overscroll-behavior: contain; border-radius: 12px 12px 0 0; box-shadow: 0 0 0 1px rgba(26,31,54,.06), 0 -8px 24px rgba(26,31,54,.1); transform: translateY(100%); transition: transform 550ms var(--kn-bremse); @@ -55,7 +55,7 @@ .kn-konto-wurzel { position: fixed; inset: 0; z-index: 60; } .kn-konto-wurzel:focus { outline: none; } /* tabindex -1: ein Tipp ins Leere behält die Tasten (Esc, Tab) im Sheet */ .kn-konto-scrim { position: absolute; inset: 0; background: transparent; } -.kn-konto { position: absolute; top: 56px; right: 24px; width: 280px; max-height: calc(100vh - 72px); padding: 8px 20px; overflow-y: auto; overscroll-behavior: contain; background: var(--kn-bg); border-radius: var(--kn-radius-lg); box-shadow: var(--kn-shadow-pop); animation: kn-aufpoppen .14s ease-out; } +.kn-konto { position: absolute; top: calc(var(--kn-banner-h) + 56px); right: 24px; width: 280px; max-height: calc(100vh - 72px); padding: 8px 20px; overflow-y: auto; overscroll-behavior: contain; background: var(--kn-bg); border-radius: var(--kn-radius-lg); box-shadow: var(--kn-shadow-pop); animation: kn-aufpoppen .14s ease-out; } .kn-konto-kopf { display: grid; grid-template-columns: 1fr auto; align-items: center; column-gap: 12px; padding: 8px 0 12px; border-bottom: 1px solid var(--kn-line); } .kn-konto-kopf > div { display: contents; } /* Name neben „Schließen“, die Mail darunter über die volle Breite */ .kn-konto-name { grid-column: 1; grid-row: 1; display: block; font-size: 17px; line-height: 24px; font-weight: 600; overflow-wrap: anywhere; } @@ -88,18 +88,17 @@ /* ---------- Gerüst: Spalte, Inhalt, Menü (Desktop) und Kopf ---------- */ -.kn { --kn-kopf-h: 52px; } +.kn { --kn-kopf-h: 52px; --kn-banner-h: 0px; } /* --kn-banner-h setzt huelle.js auf die Höhe des Mitarbeiter-Banners (E-Fix M4): Kopf, Menü, Blatt und Konto beginnen darunter */ .kn-skip { position: absolute; top: -48px; left: 8px; z-index: 100; padding: 8px 12px; border-radius: var(--kn-radius); background: var(--kn-accent); color: #fff; font-weight: 600; } .kn-skip:focus { top: 8px; } .kn-nur-leser { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; } -.kn-banner { position: relative; z-index: 30; display: flex; align-items: center; justify-content: center; gap: 12px; min-height: 36px; padding: 6px max(16px, env(safe-area-inset-right)) 6px max(16px, env(safe-area-inset-left)); background: var(--kn-accent); color: #fff; font-size: 13px; line-height: 20px; } +.kn-banner { position: sticky; top: 0; z-index: 50; display: flex; align-items: center; justify-content: center; gap: 12px; min-height: 36px; padding: 6px max(16px, env(safe-area-inset-right)) 6px max(16px, env(safe-area-inset-left)); background: var(--kn-accent); color: #fff; font-size: 13px; line-height: 20px; } .kn-banner > span { min-width: 0; overflow-wrap: anywhere; } .kn-banner button { flex: none; min-height: 28px; padding: 0 4px; color: #fff; font-weight: 600; text-decoration: underline; text-underline-offset: 3px; } -.kn-banner:not([hidden]) ~ .kn-huelle .kn-menue { top: 36px; } -.kn-menue { position: fixed; inset: 0 auto 0 0; z-index: 20; display: flex; flex-direction: column; gap: 2px; width: var(--kn-sidebar-w); padding: 20px 12px; overflow-y: auto; border-right: 1px solid var(--kn-line); background: var(--kn-bg); } +.kn-menue { position: fixed; inset: var(--kn-banner-h) auto 0 0; z-index: 20; display: flex; flex-direction: column; gap: 2px; width: var(--kn-sidebar-w); padding: 20px 12px; overflow-y: auto; border-right: 1px solid var(--kn-line); background: var(--kn-bg); } .kn-marke { padding: 0 10px 16px; font-size: 15px; line-height: 24px; font-weight: 600; } .kn-nav-item { display: flex; align-items: center; justify-content: space-between; gap: 8px; width: 100%; padding: 6px 10px; border-radius: var(--kn-radius); font-size: 14px; line-height: 20px; font-weight: 500; color: var(--kn-text-2); text-align: left; } .kn-nav-item:hover { background: var(--kn-bg-hover); color: var(--kn-text); } @@ -108,7 +107,7 @@ .kn-nav-zahl--heiss { color: var(--kn-rot-fg); font-weight: 600; } .kn-spalte { position: relative; min-height: 100vh; margin-left: var(--kn-sidebar-w); } -.kn-kopf { position: sticky; top: 0; z-index: 10; display: flex; align-items: center; justify-content: flex-end; height: var(--kn-kopf-h); margin-bottom: calc(0px - var(--kn-kopf-h)); padding: 0 24px; pointer-events: none; } /* Desktop: nur das Profilbild, bleibt beim Scrollen oben rechts und schiebt den Inhalt nicht */ +.kn-kopf { position: sticky; top: var(--kn-banner-h); z-index: 10; display: flex; align-items: center; justify-content: flex-end; height: var(--kn-kopf-h); margin-bottom: calc(0px - var(--kn-kopf-h)); padding: 0 24px; pointer-events: none; } /* Desktop: nur das Profilbild, bleibt beim Scrollen oben rechts und schiebt den Inhalt nicht */ .kn-kopf > * { pointer-events: auto; } .kn-kopf-titel { display: none; } .kn-haupt, .kn-blatt { max-width: 1160px; padding: 36px 48px 80px; } diff --git a/public/neu/huelle.js b/public/neu/huelle.js index d52bc11..22deffb 100644 --- a/public/neu/huelle.js +++ b/public/neu/huelle.js @@ -144,6 +144,11 @@ export async function starteHuelle({ win = window, doc = document, api = apiStan } leeren(banner).append(h('span', null, 'Kundenansicht: ', h('strong', null, kunde.name || 'Kunde'), ` · geöffnet von ${admin?.name || 'Mitarbeiter'}`), h('button', { type: 'button', on: { click: beenden } }, 'Beenden')) banner.hidden = false + // Höhe des Banners für Kopf, Menü, Blatt und Konto (E-Fix M4: --kn-banner-h). Der Banner bleibt oben stehen (sticky) und wird am Handy zweizeilig. + const setzeHoehe = () => doc.body.style?.setProperty?.('--kn-banner-h', `${banner.offsetHeight || 0}px`) + setzeHoehe() + if (typeof win.ResizeObserver === 'function') new win.ResizeObserver(setzeHoehe).observe(banner) + else win.addEventListener('resize', setzeHoehe) } // 3. Scroll: Stand je Route merken, Kopf (Rand, kleiner Titel) nachführen diff --git a/test/knEfixCss.test.js b/test/knEfixCss.test.js index 09bdd5f..b7fc09d 100644 --- a/test/knEfixCss.test.js +++ b/test/knEfixCss.test.js @@ -75,3 +75,15 @@ test('M3: die Fehlertexte der öffentlichen Seiten (Login, Kündigen, Widerrufen assert.match(zeile, /role="alert"/, `${datei}: ${zeile}`) } }) + +test('M4: der Mitarbeiter-Banner steht oben (sticky), Kopf, Menü, Blatt und Konto beginnen um seine Höhe (--kn-banner-h) darunter', () => { + assert.match(HUELLE, /\.kn \{[^}]*--kn-banner-h:\s*0px/) + assert.match(HUELLE, /\.kn-banner \{[^}]*position:\s*sticky;[^}]*top:\s*0/) + assert.match(HUELLE, /\.kn-menue \{[^}]*inset:\s*var\(--kn-banner-h\) auto 0 0/) + assert.match(HUELLE, /\.kn-kopf \{[^}]*position:\s*sticky;\s*top:\s*var\(--kn-banner-h\)/) + assert.match(HUELLE, /\.kn-blatt \{[^}]*inset:\s*calc\(var\(--kn-banner-h\) \+ var\(--kn-kopf-h\) \+ env\(safe-area-inset-top\)\)/) + assert.match(HUELLE, /\.kn-konto \{[^}]*top:\s*calc\(var\(--kn-banner-h\) \+ 56px\)/) + assert.doesNotMatch(HUELLE, /\.kn-banner:not\(\[hidden\]\) ~ \.kn-huelle \.kn-menue/, 'die feste Höhe 36 px ist weg') + const js = quelle('huelle.js') + assert.match(js, /setProperty\?\.\('--kn-banner-h'/) +})