banyaro/backend/static/css/layout.css
rene ed9dd08c14 Desktop: Einheitliche Seitenbreite 860px via pc-desktop Klasse
- app.js: _applyDesktopWidth() setzt nach Page-Init die Klasse pc-desktop
  auf dem ersten Kind-Div aller Standard-Seiten (excl. admin/map/chat/etc.)
- layout.css: .pc-desktop { max-width:860px !important; margin:0 auto }
- layout.css: .page-container ab 768px auf 860px (statt erst 1024px)
- main.py: /force-update Text "Service Worker wird entfernt" →
  "Wir besorgen neue Leckerlis 🦴"
- layout.css ?v=1013, components.css ?v=1010, SW by-v1014, APP_VER 1014
2026-05-16 09:57:00 +02:00

798 lines
22 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* ============================================================
BAN YARO — Layout
App Shell: Mobile Bottom-Nav + Desktop Sidebar
Mobile-first mit einer einzigen Media Query für Desktop
============================================================ */
/* ------------------------------------------------------------
1. APP SHELL
------------------------------------------------------------ */
#app {
display: flex;
flex-direction: column;
min-height: 100dvh;
}
/* Content-Bereich: füllt den Raum zwischen Header und Bottom-Nav */
#page-content {
flex: 1;
min-height: 0; /* iOS-Flex-Bug: ohne das scrollt body statt #page-content */
overflow-y: auto;
overflow-x: hidden;
padding-top: var(--safe-top);
padding-bottom: calc(var(--nav-bottom-height) + var(--safe-bottom) + 16px);
-webkit-overflow-scrolling: touch;
}
/* Mobile only: iOS-Bounce verhindert dass fixed-Nav driftet */
@media (max-width: 767px) {
#page-content {
overscroll-behavior-y: none;
}
}
/* Desktop: Sidebar-Layout — kein Bottom-Nav, natürliche Höhe */
@media (min-width: 768px) {
#app {
flex-direction: row;
}
#page-content {
min-height: unset;
overflow-y: visible; /* nicht als Scroll-Container — Window scrollt */
overflow-x: visible;
padding-bottom: 0;
padding-left: var(--nav-sidebar-width);
}
}
/* ------------------------------------------------------------
2. HEADER (Mobile)
------------------------------------------------------------ */
#app-header {
position: sticky;
top: 0;
z-index: 100;
min-height: calc(var(--header-height) + var(--safe-top));
padding-top: var(--safe-top);
padding-bottom: var(--space-2);
background: var(--c-surface);
border-bottom: 1px solid var(--c-border-light);
display: flex;
align-items: center;
padding-left: var(--space-4);
padding-right: var(--space-4);
gap: var(--space-3);
box-shadow: var(--shadow-xs);
}
.header-title {
font-size: var(--text-lg);
font-weight: var(--weight-bold);
color: var(--c-text);
flex: 1;
}
/* Dog Switcher Container im Header */
#header-dog-switcher {
flex: 1;
display: flex;
align-items: center;
gap: var(--space-2);
min-width: 0;
overflow: visible;
}
.header-back {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
border-radius: var(--radius-md);
color: var(--c-text-secondary);
cursor: pointer;
transition: background var(--transition-fast);
font-size: 20px;
flex-shrink: 0;
}
.header-back:hover { background: var(--c-surface-2); }
/* Hamburger-Button (nur Mobile) */
.header-menu-btn {
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
border: none;
background: transparent;
font-size: 1.3rem;
color: var(--c-text);
cursor: pointer;
border-radius: var(--radius-md);
flex-shrink: 0;
-webkit-tap-highlight-color: transparent;
}
.header-menu-btn:hover { background: var(--c-surface-2); }
/* Backdrop für mobile Sidebar */
.sidebar-backdrop {
display: none;
position: fixed;
inset: 0;
background: rgba(0,0,0,0.45);
z-index: 499;
}
.sidebar-backdrop.visible { display: block; }
/* Auf Desktop keinen mobilen Header zeigen */
@media (min-width: 768px) {
#app-header { display: none; }
.header-menu-btn { display: none; }
.sidebar-backdrop { display: none !important; }
}
/* Karte: volle Höhe, kein Scrollen, kein Padding */
#page-map {
height: 100%;
overflow: hidden;
}
#page-map > .page-body {
padding: 0 !important;
overflow: hidden;
height: 100%;
}
/* Gassi-Treffen + Sitting: volle Höhe, internes Scroll */
#page-walks,
#page-sitting,
#page-chat {
height: 100%;
overflow: hidden;
}
#page-walks > .page-body,
#page-sitting > .page-body,
#page-chat > .page-body {
padding: 0 !important;
gap: 0 !important;
overflow: hidden;
height: 100%;
position: relative;
}
/* Routen: volle Höhe damit .rk-layout height:100% auflöst und
das Grid intern scrollt (nicht die gesamte Seite via #page-content) */
#page-routes {
height: 100%;
overflow: hidden;
}
#page-routes > .page-body {
padding: 0 !important;
overflow: hidden;
height: 100%;
}
/* ------------------------------------------------------------
3. BOTTOM NAVIGATION (Mobile)
------------------------------------------------------------ */
#bottom-nav {
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 700; /* über Leaflet-Panes (~400) */
/* GPU-Layer erzwingen → iOS Safari fixed-position Stabilität */
transform: translateZ(0);
-webkit-transform: translateZ(0);
will-change: transform;
min-height: calc(var(--nav-bottom-height) + var(--safe-bottom));
padding-top: var(--space-1);
padding-bottom: calc(var(--safe-bottom) + var(--space-1));
background: var(--c-surface);
border-top: 1px solid var(--c-border-light);
display: flex;
align-items: stretch;
box-shadow: 0 -2px 12px rgba(42, 31, 20, 0.08);
transition: border-top-color 0.4s ease;
}
@keyframes nav-alert-pulse {
0%, 100% { box-shadow: 0 -2px 8px rgba(42,31,20,0.06); }
50% { box-shadow: 0 -6px 28px var(--nav-alert-color, rgba(220,38,38,0.65)); }
}
#bottom-nav.alert-poison {
border-top: 4px solid var(--c-danger);
--nav-alert-color: rgba(220, 38, 38, 0.65);
animation: nav-alert-pulse 1.6s ease-in-out infinite;
}
#bottom-nav.alert-lost {
border-top: 4px solid #f59e0b;
--nav-alert-color: rgba(245, 158, 11, 0.65);
animation: nav-alert-pulse 1.6s ease-in-out infinite;
}
.nav-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 3px;
cursor: pointer;
color: var(--c-icon, var(--c-text-secondary));
transition: color var(--transition-fast);
-webkit-tap-highlight-color: transparent;
touch-action: manipulation;
position: relative;
padding: var(--space-2) var(--space-1);
}
.nav-item:hover { color: var(--c-text-secondary); }
.nav-item.active { color: var(--c-primary); }
/* Aktiv-Indikator oben */
.nav-item.active::before {
content: '';
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
width: 32px;
height: 3px;
background: var(--c-primary);
border-radius: 0 0 var(--radius-full) var(--radius-full);
}
.nav-item-icon {
font-size: 22px;
line-height: 1;
position: relative;
filter: saturate(0.35) brightness(0.75);
transition: filter var(--transition-fast);
}
.nav-item.active .nav-item-icon {
filter: sepia(0.7) saturate(1.8) hue-rotate(-8deg) brightness(0.9);
}
/* Ungelesen-Badge auf Nav-Icon */
.nav-badge {
position: absolute;
top: -4px;
right: -6px;
background: var(--c-danger);
color: #fff;
font-size: 9px;
font-weight: var(--weight-bold);
min-width: 16px;
height: 16px;
border-radius: var(--radius-full);
display: flex;
align-items: center;
justify-content: center;
padding: 0 3px;
border: 2px solid var(--c-surface);
pointer-events: none;
}
.nav-item-label {
font-size: clamp(9px, 0.6rem, 11px);
font-weight: var(--weight-semibold);
line-height: 1;
white-space: nowrap;
}
/* Mittlerer + Button: kein Label, größer */
.nav-item-center .nav-item-icon {
width: 50px;
height: 50px;
background: var(--c-primary);
color: #fff;
border-radius: var(--radius-full);
font-size: 26px;
display: flex;
align-items: center;
justify-content: center;
box-shadow: var(--shadow-md);
transition: transform var(--transition-fast),
box-shadow var(--transition-fast);
margin-top: -12px; /* ragt über die Nav hinaus */
}
.nav-item-center:active .nav-item-icon {
transform: scale(0.93);
box-shadow: var(--shadow-sm);
}
.nav-item-center.active::before { display: none; }
.nav-item-center .nav-item-label { display: none; }
/* Desktop: Bottom Nav ausblenden */
@media (min-width: 768px) {
#bottom-nav { display: none; }
}
/* ------------------------------------------------------------
4. SIDEBAR NAVIGATION (Desktop)
------------------------------------------------------------ */
#sidebar {
display: none;
position: fixed;
top: 0;
left: 0;
bottom: 0;
width: var(--nav-sidebar-width);
z-index: 300;
background: var(--c-surface);
border-right: 1px solid var(--c-border-light);
flex-direction: column;
overflow: hidden; /* Sidebar selbst scrollt nicht */
box-shadow: var(--shadow-sm);
}
@media (min-width: 768px) {
#sidebar { display: flex; }
}
/* Mobile Sidebar als Drawer */
@media (max-width: 767px) {
#sidebar {
display: flex !important; /* überschreibt display:none aus Base */
position: fixed;
top: 0;
left: 0;
bottom: 0;
width: var(--nav-sidebar-width);
z-index: 1000; /* klar über Backdrop (999) */
transform: translateX(-100%);
transition: transform 0.28s ease;
background: var(--c-surface);
box-shadow: none;
}
#sidebar.open {
transform: translateX(0);
box-shadow: 4px 0 24px rgba(0,0,0,0.18);
}
.sidebar-backdrop {
z-index: 999; /* unter Sidebar, über Seiteninhalt */
}
}
.sidebar-logo {
padding: calc(var(--space-6) + var(--safe-top)) var(--space-5) var(--space-6);
display: flex;
align-items: center;
gap: var(--space-3);
border-bottom: 1px solid var(--c-border-light);
flex-shrink: 0;
}
.sidebar-logo-img {
width: 36px;
height: 36px;
border-radius: var(--radius-full);
object-fit: cover;
}
.sidebar-logo-text {
font-size: var(--text-lg);
font-weight: var(--weight-bold);
color: var(--c-text);
}
.sidebar-add {
padding: var(--space-4) var(--space-4) var(--space-2);
flex-shrink: 0;
}
.sidebar-nav {
flex: 1;
padding: var(--space-2) var(--space-2) var(--space-4);
display: flex;
flex-direction: column;
gap: var(--space-1);
overflow-y: auto;
min-height: 0; /* wichtig: flex-child darf kleiner werden als Inhalt */
/* Firefox */
scrollbar-width: thin;
scrollbar-color: var(--c-primary) var(--c-surface);
}
.sidebar-nav::-webkit-scrollbar { width: 6px; }
.sidebar-nav::-webkit-scrollbar-track { background: var(--c-surface); }
.sidebar-nav::-webkit-scrollbar-thumb {
background: var(--c-primary);
border-radius: 3px;
}
.sidebar-nav::-webkit-scrollbar-thumb:hover { background: var(--c-primary-dark); }
.sidebar-section-label {
font-size: var(--text-xs);
font-weight: var(--weight-semibold);
color: var(--c-text-muted);
text-transform: uppercase;
letter-spacing: 0.08em;
padding: var(--space-3) var(--space-3) var(--space-1);
margin-top: var(--space-2);
}
.sidebar-section-toggle {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
background: none;
border: none;
cursor: pointer;
font-size: var(--text-xs);
font-weight: var(--weight-semibold);
color: var(--c-text-muted);
text-transform: uppercase;
letter-spacing: 0.08em;
padding: var(--space-3) var(--space-3) var(--space-1);
margin-top: var(--space-2);
border-radius: var(--radius-sm);
transition: color var(--transition-fast);
-webkit-tap-highlight-color: transparent;
}
.sidebar-section-toggle:hover { color: var(--c-text); }
.sidebar-section-toggle .wissen-caret {
transition: transform 0.2s ease;
flex-shrink: 0;
}
.sidebar-section-toggle[aria-expanded="true"] .wissen-caret {
transform: rotate(90deg);
}
.sidebar-section-body {
display: flex;
flex-direction: column;
gap: var(--space-1);
overflow: hidden;
max-height: 0;
opacity: 0;
transition: max-height 0.25s ease, opacity 0.2s ease;
}
.sidebar-section-body.open {
max-height: 300px;
opacity: 1;
}
.sidebar-item {
display: flex;
align-items: center;
gap: var(--space-3);
padding: var(--space-3);
border-radius: var(--radius-md);
cursor: pointer;
color: var(--c-text-secondary);
font-size: var(--text-sm);
font-weight: var(--weight-medium);
transition: background var(--transition-fast),
color var(--transition-fast);
-webkit-tap-highlight-color: transparent;
}
.sidebar-item:hover {
background: var(--c-bg);
color: var(--c-text);
}
.sidebar-item.active {
background: var(--c-primary-subtle);
color: var(--c-primary-dark);
font-weight: var(--weight-semibold);
}
/* User-Eintrag bekommt nie den Active-Stil */
.sidebar-item--user.active {
background: transparent;
color: var(--c-text-secondary);
font-weight: var(--weight-medium);
}
.sidebar-item-icon {
font-size: 18px;
width: 24px;
text-align: center;
flex-shrink: 0;
filter: saturate(0.35) brightness(0.75);
transition: filter var(--transition-fast);
}
.sidebar-item.active .sidebar-item-icon {
filter: sepia(0.7) saturate(1.8) hue-rotate(-8deg) brightness(0.9);
}
.sidebar-item-badge {
margin-left: auto;
background: var(--c-danger);
color: #fff;
font-size: var(--text-xs);
font-weight: var(--weight-bold);
min-width: 20px;
height: 20px;
border-radius: var(--radius-full);
display: flex;
align-items: center;
justify-content: center;
padding: 0 var(--space-1);
}
/* sidebar-footer entfernt — Einstellungen/Konto sind jetzt Teil der scrollbaren Nav */
/* ------------------------------------------------------------
5. PAGE WRAPPER (inneres Layout der Seiten)
------------------------------------------------------------ */
.page {
display: none;
flex-direction: column;
min-height: 100%;
}
.page.active { display: flex; }
/* Scrollbarer Seiteninhalt */
.page-body {
flex: 1;
padding: var(--space-4);
display: flex;
flex-direction: column;
gap: var(--space-4);
}
/* Volle Breite mit seitlichem Limit für Desktop */
.page-container {
width: 100%;
max-width: 680px;
margin: 0 auto;
}
/* Desktop: Standard-Container auf 860px erweitern (768px1023px) */
@media (min-width: 768px) {
.page-container { max-width: 860px; }
}
/* Desktop-Breite: von app.js nach Page-Init gesetzt */
@media (min-width: 768px) {
.pc-desktop {
max-width: 860px !important;
margin-left: auto !important;
margin-right: auto !important;
}
}
/* Wide-Layout für Karte und ähnliches */
.page-container-wide {
width: 100%;
max-width: 1040px;
margin: 0 auto;
}
/* Karte nimmt vollen Platz ein */
.page-fullscreen {
position: absolute;
inset: 0;
padding: 0;
}
/* ------------------------------------------------------------
6. PULL-TO-REFRESH INDIKATOR
------------------------------------------------------------ */
.ptr-indicator {
display: flex;
justify-content: center;
align-items: center;
height: 48px;
color: var(--c-text-muted);
font-size: var(--text-sm);
gap: var(--space-2);
overflow: hidden;
max-height: 0;
transition: max-height var(--transition-normal);
}
.ptr-indicator.visible { max-height: 48px; }
/* ------------------------------------------------------------
7. RESPONSIVE GRID
------------------------------------------------------------ */
.grid-2 {
display: grid;
grid-template-columns: 1fr 1fr;
gap: var(--space-3);
}
.grid-3 {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: var(--space-3);
}
@media (max-width: 400px) {
.grid-3 { grid-template-columns: 1fr 1fr; }
}
/* ============================================================
Desktop Multi-Column Layouts (min-width: 1024px)
============================================================ */
@media (min-width: 1024px) {
/* Admin: breit + Sidebar-Layout */
#page-admin .page-container { max-width: 1200px; }
#page-admin .adm-shell {
display: flex;
gap: var(--space-4);
align-items: flex-start;
}
#page-admin .adm-tabs {
display: flex !important;
flex-direction: column;
width: 190px;
flex-shrink: 0;
gap: var(--space-1);
padding-bottom: 0;
position: sticky;
top: var(--space-3);
}
#page-admin .adm-tabs .by-tab {
justify-content: flex-start !important;
text-align: left !important;
padding-left: var(--space-3);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
#page-admin #adm-content {
flex: 1;
min-width: 0;
}
/* ----------------------------------------------------------
WELCOME: 2-spaltige Feature-Sections, zentrierter Hero
---------------------------------------------------------- */
.welcome-layout { max-width: 920px; }
.welcome-sections {
display: grid;
grid-template-columns: 1fr 1fr;
gap: var(--space-4);
align-items: start;
}
.welcome-sections .card { margin-bottom: 0; }
/* ----------------------------------------------------------
WALKS: Liste (links) + Karte (rechts) nebeneinander
---------------------------------------------------------- */
#page-walks .page-container { max-width: 860px; }
.walks-layout {
flex-direction: row;
align-items: stretch;
}
/* View-Toggle auf Desktop nicht nötig */
.walks-view-toggle { display: none; }
/* Beide Panels immer sichtbar */
#walks-list-view,
#walks-map-view {
display: flex !important;
flex-direction: column;
}
#walks-list-view {
width: 340px;
flex-shrink: 0;
border-right: 1px solid var(--c-border-light);
}
#walks-map-view { flex: 1; }
/* Toolbar-Zeile kompakter da Toggle wegfällt */
#page-walks .by-toolbar { padding: var(--space-2) var(--space-4); }
/* ----------------------------------------------------------
CHAT: Split-Pane zentriert mit max-width
---------------------------------------------------------- */
#page-chat .page-body {
display: flex;
flex-direction: column;
align-items: stretch;
max-width: 860px;
margin: 0 auto;
width: 100%;
}
#chat-split { min-height: 600px; }
/* ----------------------------------------------------------
FORUM: Rubriken über volle Breite, Threads darunter
---------------------------------------------------------- */
#page-forum .page-container { max-width: 860px; }
/* Rubriken auf genau 2 Zeilen verteilen, zentriert
— #page-forum nötig für Spezifität > .by-tabs (components.css lädt später) */
#page-forum .forum-category-tabs {
display: grid;
grid-template-columns: repeat(var(--forum-tab-cols, 7), minmax(0, 1fr));
overflow: visible;
gap: var(--space-1);
padding-bottom: var(--space-2);
}
#page-forum .forum-category-tabs .by-tab {
justify-content: center;
text-align: center;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* Gesundheit: Tabs auf 2 Zeilen */
#page-health .by-tabs {
display: grid;
grid-template-columns: repeat(var(--health-tab-cols, 5), minmax(0, 1fr));
overflow: visible;
gap: var(--space-1);
padding-bottom: var(--space-2);
}
#page-health .by-tabs .by-tab {
justify-content: center;
text-align: center;
white-space: nowrap;
}
/* Admin: Tabs als 2-zeiliges Grid (Mobile/Tablet) */
#page-admin .adm-tabs {
display: grid;
grid-template-columns: repeat(var(--adm-tab-cols, 4), minmax(0, 1fr));
overflow: visible;
gap: var(--space-1);
padding-bottom: var(--space-2);
}
#page-admin .adm-tabs .by-tab {
justify-content: center;
text-align: center;
white-space: nowrap;
}
/* Übungen: Tabs auf 2 Zeilen */
#page-uebungen #ueb-tabs {
display: grid;
grid-template-columns: repeat(var(--ueb-tab-cols, 5), minmax(0, 1fr));
overflow: visible;
gap: var(--space-1);
padding-bottom: var(--space-2);
}
#page-uebungen #ueb-tabs .by-tab {
justify-content: center;
text-align: center;
white-space: nowrap;
}
/* Karte: Legende auf 2 Zeilen
— #page-map nötig für Spezifität > .map-legend (components.css lädt später) */
#page-map .map-legend {
display: grid;
grid-template-columns: repeat(var(--map-legend-cols, 8), minmax(0, 1fr));
overflow: visible;
gap: var(--space-1);
}
#page-map .map-legend-btn {
justify-content: center;
}
/* Suche + Threads volle Breite */
.forum-main-col {
display: flex;
flex-direction: column;
gap: var(--space-3);
}
}
/* ============================================================
Phosphor Icons — SVG Sprite
============================================================ */
.ph-icon {
width: 20px;
height: 20px;
display: inline-block;
vertical-align: middle;
fill: currentColor;
flex-shrink: 0;
}
.nav-item .ph-icon { width: 24px; height: 24px; }
.nav-item-center .ph-icon { width: 22px; height: 22px; }
.header-menu-btn .ph-icon { width: 22px; height: 22px; }