mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-19 13:21:46 +00:00
9bec97fc19
* Start the Journey date picker week on Monday (#1078) The Journey entry date picker started the week on Sunday (firstDow = getDay(), headers Su-first) while every other picker (CustomDateTimePicker, VacayCalendar) starts on Monday. Align it: Monday-first leading offset ((getDay()+6)%7) and Mo-first weekday headers. * Fix Taiwan resolving to CN-TW in the Atlas country search (#1049) natural-earth gives Taiwan ISO_A2='CN-TW' (a subdivision-style value) with ADM0_A3='TWN'. The dynamic A2_TO_A3 augmentation added 'CN-TW'->'TWN', which then overwrote the legitimate TWN->TW entry in the reverse map, so Taiwan's country option resolved to 'CN-TW' — unresolvable by Intl.DisplayNames (no name, broken flag, not searchable). Only augment A2_TO_A3 with real 2-letter codes. * Drop empty leftover dateless days when a trip gets a shorter dated range (#1083) generateDays kept all unused dateless placeholder days after switching to an explicit (shorter) date range, so day_count (COUNT(*) FROM days) stayed inflated. Delete the empty leftovers (no assignments/notes/accommodations) like the dateless path already does, while preserving any that still hold content. Adds TRIP-SVC-017. * Render GPX and route overlays once the Mapbox style has loaded (#1036) The GPX and route geojson effects ran before the map 'load' event had attached their sources, so on the first paint they hit the early return and never re-ran. Add mapReady to their dependencies so they fire again the moment the sources exist. * Convert HEIC trip and journey covers to JPEG before upload (#1085) HEIC/HEIF covers coming straight off an iPhone could not be rendered in the preview or stored as a usable image. Route both cover pickers through normalizeImageFile, the same conversion the journal entry editor already uses, so the file becomes a JPEG before it leaves the browser. * Name GPX routes and tracks after their source file so multiple imports stick (#1054) Unnamed routes and tracks all fell back to the same generic 'GPX Route' / 'GPX Track' label, so the name-based import dedup dropped every one after the first - importing several files (or one file with several tracks) only kept a single place. Derive the default name from the source filename with an index suffix when a file holds more than one geometry, thread the filename down through the controller, and let the import modal take more than one file at a time. Adds PLACE-SVC-037/038. * Namespace the modal backdrop class so content blockers stop hiding it (#1027) Generic class names like .modal-backdrop sit on the cosmetic filter lists that content blockers (1Blocker, EasyList Annoyances) ship, and get hidden with display:none. The shared Modal - used by New Trip and Add Place - carried that class, so Safari users running such a blocker saw the modal silently fail to open with no error and no network request. Rename it to .trek-modal-backdrop. * Highlight GB regions by resolving England/Scotland/Wales/NI to finer admin-1 codes (#1067) A zoom-8 reverse geocode of a UK place only resolves to the constituent country (GB-ENG/SCT/WLS/NIR), but Natural Earth's admin-1 polygons for GB are counties and boroughs (GB-LND, GB-MAN, GB-CON, ...). Those four codes match no polygon, so places in England never highlighted in the Atlas while CH/IT/NL/etc. worked. When a GB lookup lands on a constituent country, re-resolve it at a finer zoom where Nominatim exposes the county/borough code the polygons actually carry. Other countries keep the exact zoom-8 behaviour. Adds ATLAS-UNIT-021. * Surface the real place-search error instead of a generic toast (#1092) When a place search or detail lookup fails, the backend already forwards the upstream reason - including descriptive Google Places API messages such as 'Places API (New) has not been used in project ... or it is disabled'. The planner discarded it and always showed 'Place search failed', so a key that is mis-enabled, unbilled, or pointed at the legacy API instead of Places API (New) looked like an unexplained silent failure. Show the server-provided message when present, and stop the Atlas bucket-list search from swallowing its error without a trace. * Await the async cover normalization in the TripFormModal paste test (#1085) handleCoverSelect now normalizes the pasted file before previewing it, so URL.createObjectURL is called a microtask later. The assertion moves into waitFor; a non-HEIC file still passes through unchanged.
833 lines
30 KiB
CSS
833 lines
30 KiB
CSS
@tailwind base;
|
|
@tailwind components;
|
|
@tailwind utilities;
|
|
|
|
html { height: 100%; overflow: hidden; background-color: var(--bg-primary); }
|
|
body { height: 100%; overflow: auto; overscroll-behavior: none; -webkit-overflow-scrolling: touch; }
|
|
|
|
|
|
/* Journey desktop feed: hide scrollbar (right column is a sticky map, a
|
|
visible scrollbar on the left breaks the polarsteps-style reading feel). */
|
|
.journey-feed-scroll { scrollbar-width: none; -ms-overflow-style: none; }
|
|
.journey-feed-scroll::-webkit-scrollbar { display: none; }
|
|
|
|
/* Leaflet Popups — Enter-Animation vom Anchor-Tip */
|
|
.leaflet-popup {
|
|
animation: trek-popover-enter 220ms cubic-bezier(0.23, 1, 0.32, 1);
|
|
transform-origin: bottom center;
|
|
will-change: transform, opacity;
|
|
}
|
|
.leaflet-popup-content-wrapper {
|
|
border-radius: 14px !important;
|
|
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.18) !important;
|
|
background: var(--bg-card) !important;
|
|
color: var(--text-primary) !important;
|
|
border: 1px solid var(--border-faint);
|
|
}
|
|
.leaflet-popup-tip {
|
|
background: var(--bg-card) !important;
|
|
}
|
|
.leaflet-popup-close-button {
|
|
transition: color 150ms cubic-bezier(0.23, 1, 0.32, 1), transform 150ms cubic-bezier(0.23, 1, 0.32, 1) !important;
|
|
}
|
|
.leaflet-popup-close-button:hover {
|
|
transform: scale(1.15);
|
|
color: var(--text-primary) !important;
|
|
}
|
|
|
|
.atlas-tooltip {
|
|
background: rgba(10, 10, 20, 0.6) !important;
|
|
backdrop-filter: blur(20px) saturate(180%) !important;
|
|
-webkit-backdrop-filter: blur(20px) saturate(180%) !important;
|
|
color: #f1f5f9 !important;
|
|
border: 1px solid rgba(255,255,255,0.1) !important;
|
|
border-radius: 14px !important;
|
|
padding: 10px 14px !important;
|
|
font-size: 12px !important;
|
|
font-family: inherit !important;
|
|
box-shadow: 0 8px 32px rgba(0,0,0,0.25) !important;
|
|
transition: none !important;
|
|
}
|
|
.atlas-tooltip::before { border-top-color: rgba(10, 10, 20, 0.6) !important; }
|
|
html:not(.dark) .atlas-tooltip {
|
|
background: rgba(255, 255, 255, 0.75) !important;
|
|
color: #0f172a !important;
|
|
border: 1px solid rgba(0,0,0,0.08) !important;
|
|
box-shadow: 0 8px 32px rgba(0,0,0,0.1) !important;
|
|
}
|
|
html:not(.dark) .atlas-tooltip::before { border-top-color: rgba(255, 255, 255, 0.75) !important; }
|
|
.leaflet-tooltip.atlas-tooltip { opacity: 1 !important; }
|
|
.leaflet-tooltip-pane { transition: none !important; }
|
|
.leaflet-fade-anim .leaflet-tooltip { transition: none !important; opacity: 1 !important; }
|
|
|
|
.dark .leaflet-control-zoom a {
|
|
background: rgba(10, 10, 20, 0.7) !important;
|
|
color: #e2e8f0 !important;
|
|
border-color: rgba(255, 255, 255, 0.1) !important;
|
|
backdrop-filter: blur(12px);
|
|
}
|
|
.dark .leaflet-control-zoom a:hover {
|
|
background: rgba(30, 30, 40, 0.8) !important;
|
|
}
|
|
@media (max-width: 767px) {
|
|
.leaflet-control-zoom { display: none !important; }
|
|
}
|
|
|
|
/* Dark mode overrides for pages using hardcoded slate-* Tailwind classes */
|
|
html.dark .bg-slate-50 { background-color: var(--bg-secondary) !important; }
|
|
html.dark .bg-white { background-color: var(--bg-card) !important; }
|
|
html.dark .bg-slate-100 { background-color: var(--bg-secondary) !important; }
|
|
html.dark .bg-slate-900.text-white { background-color: #e2e8f0 !important; color: #0f172a !important; }
|
|
html.dark .border-slate-200, html.dark .border-slate-300 { border-color: var(--border-primary) !important; }
|
|
html.dark .border-slate-100, html.dark .border-b-slate-100 { border-color: var(--border-secondary) !important; }
|
|
html.dark .text-slate-900 { color: var(--text-primary) !important; }
|
|
html.dark .text-slate-700 { color: var(--text-secondary) !important; }
|
|
html.dark .text-slate-600 { color: var(--text-muted) !important; }
|
|
html.dark .text-slate-500 { color: var(--text-muted) !important; }
|
|
html.dark .text-slate-400 { color: var(--text-faint) !important; }
|
|
html.dark .hover\:bg-slate-50:hover, html.dark .hover\:bg-slate-100:hover { background-color: var(--bg-hover) !important; }
|
|
html.dark .hover\:text-slate-900:hover { color: var(--text-primary) !important; }
|
|
html.dark .hover\:bg-slate-700:hover { background-color: var(--bg-hover) !important; }
|
|
html.dark .divide-slate-100 > :not([hidden]) ~ :not([hidden]) { border-color: var(--border-secondary) !important; }
|
|
html.dark .focus\:ring-slate-400:focus { --tw-ring-color: var(--text-faint) !important; }
|
|
html.dark input[class*="border-slate"], html.dark input[class*="text-slate"] { background: var(--bg-secondary) !important; color: var(--text-primary) !important; border-color: var(--border-primary) !important; }
|
|
html.dark .text-amber-900 { color: #fbbf24 !important; }
|
|
html.dark .text-amber-700 { color: #f59e0b !important; }
|
|
html.dark .bg-amber-50 { background-color: rgba(245,158,11,0.1) !important; }
|
|
html.dark .border-amber-200 { border-color: rgba(245,158,11,0.2) !important; }
|
|
html.dark .disabled\:bg-slate-400:disabled { background-color: var(--text-faint) !important; }
|
|
html.dark button.bg-slate-900 { background-color: #e2e8f0 !important; color: #0f172a !important; opacity: 1 !important; }
|
|
html.dark button.bg-slate-900:hover { background-color: #cbd5e1 !important; }
|
|
html.dark button.bg-slate-900:disabled { background-color: #ffffff !important; color: #000000 !important; opacity: 0.4 !important; }
|
|
html.dark span.bg-slate-900 { background-color: #e2e8f0 !important; color: #0f172a !important; }
|
|
html.dark span.bg-slate-100 { background-color: var(--bg-secondary) !important; color: var(--text-muted) !important; }
|
|
html.dark .border-b { border-bottom-color: var(--border-secondary) !important; }
|
|
/* Gray variants (CategoryManager, BackupPanel) */
|
|
html.dark .bg-gray-50 { background-color: var(--bg-secondary) !important; }
|
|
html.dark .bg-gray-100 { background-color: var(--bg-secondary) !important; }
|
|
html.dark .border-gray-200, html.dark .border-gray-300 { border-color: var(--border-primary) !important; }
|
|
html.dark .border-gray-100 { border-color: var(--border-secondary) !important; }
|
|
html.dark .text-gray-900 { color: var(--text-primary) !important; }
|
|
html.dark .text-gray-700 { color: var(--text-secondary) !important; }
|
|
html.dark .text-gray-600 { color: var(--text-muted) !important; }
|
|
html.dark .text-gray-500 { color: var(--text-muted) !important; }
|
|
html.dark .text-gray-400 { color: var(--text-faint) !important; }
|
|
html.dark .text-gray-300 { color: var(--text-faint) !important; }
|
|
html.dark .hover\:bg-gray-50:hover, html.dark .hover\:bg-gray-200:hover { background-color: var(--bg-hover) !important; }
|
|
html.dark .hover\:border-gray-200:hover, html.dark .hover\:border-gray-400:hover { border-color: var(--border-primary) !important; }
|
|
html.dark input.bg-white, html.dark input[class*="bg-white"] { background: var(--bg-secondary) !important; color: var(--text-primary) !important; }
|
|
html.dark .bg-gray-200 { background-color: var(--border-primary) !important; }
|
|
html.dark .border-gray-300.border-t-slate-600 { border-color: var(--border-primary) !important; border-top-color: var(--text-primary) !important; }
|
|
/* Modal buttons */
|
|
html.dark button[class*="text-slate-600"][class*="border-slate-200"] { color: var(--text-muted) !important; border-color: var(--border-primary) !important; }
|
|
html.dark button[class*="text-slate-600"][class*="border-slate-200"]:hover { background: var(--bg-hover) !important; }
|
|
/* Dashed borders */
|
|
html.dark .border-dashed.border-gray-300 { border-color: var(--border-primary) !important; }
|
|
html.dark .bg-slate-50\/60, html.dark [class*="bg-slate-50/"] { background-color: transparent !important; }
|
|
|
|
/* Reorder buttons: desktop = original style; mobile = always visible, larger touch targets */
|
|
.reorder-buttons {
|
|
flex-direction: column;
|
|
opacity: 0;
|
|
}
|
|
.reorder-buttons button {
|
|
background: none !important;
|
|
padding: 1px 2px;
|
|
}
|
|
@media (max-width: 767px) {
|
|
.reorder-buttons {
|
|
flex-direction: row !important;
|
|
opacity: 1 !important;
|
|
align-items: center;
|
|
margin-left: auto;
|
|
}
|
|
.reorder-buttons button {
|
|
background: var(--bg-tertiary) !important;
|
|
border-radius: 6px;
|
|
width: 32px;
|
|
height: 32px;
|
|
padding: 0 !important;
|
|
display: flex !important;
|
|
align-items: center !important;
|
|
justify-content: center !important;
|
|
}
|
|
.note-edit-buttons {
|
|
opacity: 1 !important;
|
|
}
|
|
}
|
|
|
|
/* Ort-Zeile Hover: Sortier-Buttons anzeigen */
|
|
.place-row:hover .reorder-btns {
|
|
opacity: 1 !important;
|
|
}
|
|
|
|
/* Ladeanimation */
|
|
@keyframes spin {
|
|
to { transform: rotate(360deg); }
|
|
}
|
|
|
|
/* ── Press-Feedback + bessere Easings (Emil Kowalski) ─────────── */
|
|
/* Buttons sollen antworten wenn sie gedrückt werden. */
|
|
button:not(:disabled):not([data-no-press]),
|
|
[role="button"]:not([aria-disabled="true"]):not([data-no-press]) {
|
|
transition-property: transform, color, background-color, border-color, box-shadow, opacity, filter !important;
|
|
transition-duration: 180ms;
|
|
transition-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
|
|
}
|
|
button:not(:disabled):not([data-no-press]):active,
|
|
[role="button"]:not([aria-disabled="true"]):not([data-no-press]):active {
|
|
transform: scale(0.97);
|
|
transition-duration: 80ms;
|
|
}
|
|
|
|
/* Tailwind-Default-Easing durch ease-out-quint ersetzen.
|
|
Eingebaute CSS-Easings sind kraftlos; ease-out-quint hat Punch. */
|
|
.transition,
|
|
.transition-all,
|
|
.transition-colors,
|
|
.transition-opacity,
|
|
.transition-transform,
|
|
.transition-shadow {
|
|
transition-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
|
|
}
|
|
|
|
/* Input-Focus transitions — border + ring faden weich ein */
|
|
input, textarea, select {
|
|
transition: border-color 150ms cubic-bezier(0.23, 1, 0.32, 1),
|
|
box-shadow 150ms cubic-bezier(0.23, 1, 0.32, 1),
|
|
background-color 150ms cubic-bezier(0.23, 1, 0.32, 1);
|
|
}
|
|
|
|
/* Back-Button Icon-Slide on hover */
|
|
.trek-back-btn .trek-back-icon {
|
|
transition: transform 200ms cubic-bezier(0.23, 1, 0.32, 1);
|
|
}
|
|
.trek-back-btn:hover .trek-back-icon {
|
|
transform: translateX(-2px);
|
|
}
|
|
|
|
/* Global focus-visible ring — konsistent überall */
|
|
:focus-visible {
|
|
outline: 2px solid var(--accent);
|
|
outline-offset: 2px;
|
|
border-radius: 4px;
|
|
}
|
|
button:focus-visible, [role="button"]:focus-visible, a:focus-visible {
|
|
outline-offset: 3px;
|
|
}
|
|
input:focus-visible, textarea:focus-visible, select:focus-visible {
|
|
outline: none;
|
|
}
|
|
|
|
/* Theme crossfade — beim Dark/Light switch, Hauptflächen + Text faden ihre Farben.
|
|
Sparingly: nur background-color und color bekommen eine Transition. */
|
|
html.trek-theme-transitioning,
|
|
html.trek-theme-transitioning body,
|
|
html.trek-theme-transitioning *:not(img):not(video):not(canvas):not([class*="trek-skeleton"]):not(.leaflet-layer) {
|
|
transition:
|
|
background-color 320ms cubic-bezier(0.23, 1, 0.32, 1),
|
|
color 320ms cubic-bezier(0.23, 1, 0.32, 1),
|
|
border-color 320ms cubic-bezier(0.23, 1, 0.32, 1),
|
|
fill 320ms cubic-bezier(0.23, 1, 0.32, 1) !important;
|
|
}
|
|
|
|
/* Touch-Geräte: iOS-Tap-Highlight weg (wir haben eigenes Press-Feedback) */
|
|
@media (hover: none) {
|
|
button, [role="button"], a {
|
|
-webkit-tap-highlight-color: transparent;
|
|
}
|
|
}
|
|
html, body {
|
|
-webkit-tap-highlight-color: transparent;
|
|
}
|
|
|
|
/* Tabular-nums global für Time/Date/Currency/Counter */
|
|
time, .tabular-nums, [data-tabular],
|
|
input[type="number"], input[type="time"], input[type="date"], input[type="datetime-local"] {
|
|
font-variant-numeric: tabular-nums;
|
|
}
|
|
/* Wenn Element explizit ease-in-out nutzt (z.B. Accordions), nicht überschreiben.
|
|
Tailwind setzt ease-in-out via eigener Klasse — die gewinnt durch letzte Deklaration. */
|
|
|
|
/* Press-Scale für clickbare Divs (Cards, Tiles) — sanfter als Buttons */
|
|
[data-press]:active {
|
|
transform: scale(0.985);
|
|
transition-duration: 80ms;
|
|
}
|
|
|
|
/* ── Popover/Dropdown Enter-Animationen ─────────────────────────
|
|
Emil: Popovers sollen von ihrem Trigger aus scalen, nicht vom Center.
|
|
Start bei scale(0.95) — nichts in der echten Welt poppt aus dem Nichts. */
|
|
@keyframes trek-menu-enter {
|
|
from { opacity: 0; transform: scale(0.95) translateY(-4px); }
|
|
to { opacity: 1; transform: scale(1) translateY(0); }
|
|
}
|
|
@keyframes trek-popover-enter {
|
|
from { opacity: 0; transform: scale(0.96); }
|
|
to { opacity: 1; transform: scale(1); }
|
|
}
|
|
@keyframes trek-modal-enter {
|
|
from { opacity: 0; transform: scale(0.97); }
|
|
to { opacity: 1; transform: scale(1); }
|
|
}
|
|
@keyframes trek-backdrop-enter {
|
|
from { opacity: 0; }
|
|
to { opacity: 1; }
|
|
}
|
|
@keyframes trek-toast-enter {
|
|
from { opacity: 0; transform: translateY(8px) scale(0.96); }
|
|
to { opacity: 1; transform: translateY(0) scale(1); }
|
|
}
|
|
@keyframes trek-progress-fill {
|
|
from { width: 0%; }
|
|
to { width: var(--trek-progress-to, 0%); }
|
|
}
|
|
|
|
/* Pie-Chart Reveal — rotate + fade-in, gibt dem Kreisdiagramm ein "Draw"-Gefühl */
|
|
@keyframes trek-pie-reveal {
|
|
from { opacity: 0; transform: rotate(-90deg) scale(0.85); }
|
|
to { opacity: 1; transform: rotate(0deg) scale(1); }
|
|
}
|
|
.trek-pie-reveal {
|
|
animation: trek-pie-reveal 900ms cubic-bezier(0.23, 1, 0.32, 1) both;
|
|
transform-origin: center;
|
|
will-change: transform, opacity;
|
|
}
|
|
|
|
/* Bar-Chart Reveal — horizontaler Fill von links */
|
|
@keyframes trek-bar-fill {
|
|
from { transform: scaleX(0); }
|
|
to { transform: scaleX(1); }
|
|
}
|
|
.trek-bar-fill {
|
|
animation: trek-bar-fill 700ms cubic-bezier(0.23, 1, 0.32, 1) both;
|
|
transform-origin: left center;
|
|
will-change: transform;
|
|
}
|
|
|
|
/* Page-Transition — subtiler Fade-Up beim Mount */
|
|
@keyframes trek-page-enter {
|
|
from { opacity: 0; transform: translateY(6px); }
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
.trek-page-enter {
|
|
animation: trek-page-enter 220ms cubic-bezier(0.23, 1, 0.32, 1) both;
|
|
}
|
|
|
|
/* Skeleton shimmer — ein fließender Gradient-Strip überquert den Platzhalter */
|
|
@keyframes trek-shimmer {
|
|
from { background-position: -200% 0; }
|
|
to { background-position: 200% 0; }
|
|
}
|
|
.trek-skeleton {
|
|
background: linear-gradient(
|
|
90deg,
|
|
var(--bg-tertiary) 0%,
|
|
var(--bg-hover) 50%,
|
|
var(--bg-tertiary) 100%
|
|
);
|
|
background-size: 200% 100%;
|
|
animation: trek-shimmer 1.6s linear infinite;
|
|
border-radius: 8px;
|
|
color: transparent;
|
|
user-select: none;
|
|
}
|
|
.dark .trek-skeleton {
|
|
background: linear-gradient(
|
|
90deg,
|
|
rgba(255,255,255,0.04) 0%,
|
|
rgba(255,255,255,0.08) 50%,
|
|
rgba(255,255,255,0.04) 100%
|
|
);
|
|
background-size: 200% 100%;
|
|
}
|
|
.trek-menu-enter {
|
|
animation: trek-menu-enter 200ms cubic-bezier(0.23, 1, 0.32, 1);
|
|
transform-origin: top right;
|
|
will-change: transform, opacity;
|
|
}
|
|
.trek-menu-enter-left {
|
|
animation: trek-menu-enter 200ms cubic-bezier(0.23, 1, 0.32, 1);
|
|
transform-origin: top left;
|
|
will-change: transform, opacity;
|
|
}
|
|
.trek-popover-enter {
|
|
animation: trek-popover-enter 180ms cubic-bezier(0.23, 1, 0.32, 1);
|
|
will-change: transform, opacity;
|
|
}
|
|
.trek-modal-enter {
|
|
animation: trek-modal-enter 220ms cubic-bezier(0.23, 1, 0.32, 1);
|
|
will-change: transform, opacity;
|
|
}
|
|
|
|
/* Mobile-Drawer-Feel — Modal slidet von unten rein, wird unten am Screen angedockt */
|
|
@keyframes trek-drawer-enter {
|
|
from { opacity: 0; transform: translateY(100%); }
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
@media (max-width: 639px) {
|
|
.trek-modal-enter {
|
|
animation: trek-drawer-enter 320ms cubic-bezier(0.32, 0.72, 0, 1);
|
|
border-bottom-left-radius: 0 !important;
|
|
border-bottom-right-radius: 0 !important;
|
|
margin-top: auto !important;
|
|
align-self: flex-end;
|
|
}
|
|
}
|
|
.trek-backdrop-enter {
|
|
animation: trek-backdrop-enter 180ms cubic-bezier(0.23, 1, 0.32, 1);
|
|
}
|
|
.trek-toast-enter {
|
|
animation: trek-toast-enter 260ms cubic-bezier(0.23, 1, 0.32, 1);
|
|
will-change: transform, opacity;
|
|
}
|
|
|
|
/* Stagger-Helpers für Listen — Enter-Animation mit Offset */
|
|
@keyframes trek-fade-up {
|
|
from { opacity: 0; transform: translateY(6px); }
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
.trek-stagger > * {
|
|
animation: trek-fade-up 280ms cubic-bezier(0.23, 1, 0.32, 1) both;
|
|
}
|
|
.trek-stagger > *:nth-child(1) { animation-delay: 0ms; }
|
|
.trek-stagger > *:nth-child(2) { animation-delay: 40ms; }
|
|
.trek-stagger > *:nth-child(3) { animation-delay: 80ms; }
|
|
.trek-stagger > *:nth-child(4) { animation-delay: 120ms; }
|
|
.trek-stagger > *:nth-child(5) { animation-delay: 160ms; }
|
|
.trek-stagger > *:nth-child(6) { animation-delay: 200ms; }
|
|
.trek-stagger > *:nth-child(7) { animation-delay: 240ms; }
|
|
.trek-stagger > *:nth-child(8) { animation-delay: 280ms; }
|
|
.trek-stagger > *:nth-child(n+9) { animation-delay: 320ms; }
|
|
|
|
/* Reduced motion — Emil's Accessibility-Regel: fewer and gentler, not zero */
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.trek-menu-enter, .trek-menu-enter-left, .trek-popover-enter,
|
|
.trek-modal-enter, .trek-toast-enter, .trek-stagger > * {
|
|
animation: trek-backdrop-enter 120ms ease-out;
|
|
}
|
|
.trek-skeleton {
|
|
animation: none;
|
|
background: var(--bg-tertiary);
|
|
}
|
|
button:not(:disabled):not([data-no-press]):active,
|
|
[role="button"]:not([aria-disabled="true"]):not([data-no-press]):active,
|
|
[data-press]:active {
|
|
transform: none;
|
|
}
|
|
/* Parallax & lift disablen */
|
|
.group:hover img,
|
|
.group:hover .cover-img { transform: none !important; }
|
|
*:hover { translate: none !important; }
|
|
}
|
|
|
|
/* ── Design tokens ─────────────────────────────── */
|
|
:root {
|
|
/* Easing curves — stärker als die CSS-Defaults, siehe easing.dev */
|
|
--ease-out-quint: cubic-bezier(0.23, 1, 0.32, 1);
|
|
--ease-in-out-quint: cubic-bezier(0.77, 0, 0.175, 1);
|
|
--ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);
|
|
|
|
--safe-top: env(safe-area-inset-top, 0px);
|
|
--nav-h: 0px;
|
|
--bottom-nav-h: 0px;
|
|
--font-system: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Segoe UI', system-ui, sans-serif;
|
|
--sp-1: 4px;
|
|
--sp-2: 8px;
|
|
--sp-3: 12px;
|
|
--sp-4: 16px;
|
|
--sp-6: 24px;
|
|
--radius-sm: 8px;
|
|
--radius-md: 12px;
|
|
--radius-lg: 16px;
|
|
--radius-xl: 20px;
|
|
--shadow-card: 0 1px 3px rgba(0,0,0,0.08), 0 1px 2px rgba(0,0,0,0.04);
|
|
--shadow-elevated: 0 4px 16px rgba(0,0,0,0.1);
|
|
|
|
/* Theme colors */
|
|
--bg-primary: #ffffff;
|
|
--bg-secondary: #f8fafc;
|
|
--bg-tertiary: #f1f5f9;
|
|
--bg-elevated: rgba(250,250,250,0.82);
|
|
--bg-card: #ffffff;
|
|
--bg-input: #ffffff;
|
|
--bg-hover: rgba(0,0,0,0.03);
|
|
--bg-selected: #e2e8f0;
|
|
--text-primary: #111827;
|
|
--text-secondary: #374151;
|
|
--text-muted: #6b7280;
|
|
--text-faint: #9ca3af;
|
|
--border-primary: #e5e7eb;
|
|
--border-secondary: #f3f4f6;
|
|
--border-faint: rgba(0,0,0,0.06);
|
|
--accent: #111827;
|
|
--accent-text: #ffffff;
|
|
--sidebar-bg: rgba(250,250,250,0.82);
|
|
--sidebar-shadow: 0 4px 32px rgba(0,0,0,0.10), 0 0 0 1px rgba(0,0,0,0.06);
|
|
--tooltip-bg: rgba(255,255,255,0.96);
|
|
--scrollbar-track: #f1f5f9;
|
|
--scrollbar-thumb: #d1d5db;
|
|
--scrollbar-hover: #9ca3af;
|
|
|
|
/* Journey design tokens */
|
|
--journal-bg: #FAFAFA;
|
|
--journal-card: #FFFFFF;
|
|
--journal-border: #E4E4E7;
|
|
--journal-accent: #6366F1;
|
|
--journal-text: #09090B;
|
|
--journal-muted: #71717A;
|
|
--journal-faint: #A1A1AA;
|
|
--mood-amazing: #E8654A;
|
|
--mood-good: #EF9F27;
|
|
--mood-neutral: #94928C;
|
|
--mood-tired: #6B9BD2;
|
|
--mood-rough: #9B8EC4;
|
|
}
|
|
|
|
@media (max-width: 767px) {
|
|
:root { --bottom-nav-h: calc(84px + env(safe-area-inset-bottom, 0px)); }
|
|
}
|
|
|
|
@media (min-width: 768px) {
|
|
:root { --nav-h: calc(64px + env(safe-area-inset-top, 0px)); }
|
|
}
|
|
|
|
.dark {
|
|
--bg-primary: #121215;
|
|
--bg-secondary: #1a1a1e;
|
|
--bg-tertiary: #1c1c21;
|
|
--bg-elevated: rgba(19,19,22,0.82);
|
|
--bg-card: #131316;
|
|
--bg-input: #1c1c21;
|
|
--bg-hover: rgba(255,255,255,0.06);
|
|
--bg-selected: rgba(255,255,255,0.1);
|
|
--text-primary: #f4f4f5;
|
|
--text-secondary: #d4d4d8;
|
|
--text-muted: #a1a1aa;
|
|
--text-faint: #71717a;
|
|
--border-primary: #27272a;
|
|
--border-secondary: #1c1c21;
|
|
--border-faint: rgba(255,255,255,0.07);
|
|
--accent: #e4e4e7;
|
|
--accent-text: #09090b;
|
|
--sidebar-bg: rgba(19,19,22,0.82);
|
|
--sidebar-shadow: 0 4px 32px rgba(0,0,0,0.4), 0 0 0 1px rgba(255,255,255,0.05);
|
|
--tooltip-bg: rgba(19,19,22,0.96);
|
|
--scrollbar-track: #131316;
|
|
--scrollbar-thumb: #3f3f46;
|
|
--scrollbar-hover: #52525b;
|
|
|
|
/* Journey design tokens (dark) */
|
|
--journal-bg: #09090B;
|
|
--journal-card: #18181B;
|
|
--journal-border: #27272A;
|
|
--journal-accent: #818CF8;
|
|
--journal-text: #FAFAFA;
|
|
--journal-muted: #A1A1AA;
|
|
--journal-faint: #52525B;
|
|
--mood-amazing: #f28a6e;
|
|
--mood-good: #f5b84d;
|
|
--mood-neutral: #9a9a94;
|
|
--mood-tired: #6db3f0;
|
|
--mood-rough: #a9a3f0;
|
|
}
|
|
|
|
body {
|
|
font-family: var(--font-system);
|
|
background-color: var(--bg-primary);
|
|
color: var(--text-primary);
|
|
transition: background-color 0.2s, color 0.2s;
|
|
}
|
|
|
|
/* ── Marker cluster custom styling ────────────── */
|
|
.marker-cluster-wrapper {
|
|
background: transparent !important;
|
|
border: none !important;
|
|
}
|
|
|
|
.marker-cluster-custom {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
border-radius: 50%;
|
|
background: #111827;
|
|
border: 2.5px solid rgba(255, 255, 255, 0.9);
|
|
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.25), 0 0 0 2px rgba(17, 24, 39, 0.15);
|
|
cursor: pointer;
|
|
transition: transform 0.15s ease, box-shadow 0.15s ease;
|
|
}
|
|
|
|
.marker-cluster-custom:hover {
|
|
transform: scale(1.1);
|
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.35), 0 0 0 3px rgba(17, 24, 39, 0.2);
|
|
}
|
|
|
|
.marker-cluster-custom span {
|
|
font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', system-ui, sans-serif;
|
|
font-size: 12px;
|
|
font-weight: 700;
|
|
color: #ffffff;
|
|
line-height: 1;
|
|
}
|
|
|
|
/* Hide default markercluster styles we don't need */
|
|
.marker-cluster-small,
|
|
.marker-cluster-medium,
|
|
.marker-cluster-large {
|
|
background: transparent !important;
|
|
}
|
|
.marker-cluster-small div,
|
|
.marker-cluster-medium div,
|
|
.marker-cluster-large div {
|
|
background: transparent !important;
|
|
}
|
|
|
|
/* ── Leaflet z-index ───────────────────────────── */
|
|
.leaflet-container {
|
|
z-index: 0;
|
|
}
|
|
.leaflet-pane {
|
|
z-index: 0 !important;
|
|
}
|
|
.leaflet-top, .leaflet-bottom {
|
|
z-index: 1 !important;
|
|
}
|
|
|
|
/* ── iOS-style map tooltip ─────────────────────── */
|
|
.leaflet-tooltip.map-tooltip {
|
|
background: var(--tooltip-bg);
|
|
backdrop-filter: blur(8px);
|
|
-webkit-backdrop-filter: blur(8px);
|
|
border: none;
|
|
border-radius: 8px;
|
|
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
|
|
padding: 5px 10px;
|
|
font-family: var(--font-system);
|
|
font-size: 11px;
|
|
font-weight: 500;
|
|
pointer-events: none;
|
|
color: var(--text-primary);
|
|
}
|
|
.leaflet-tooltip.map-tooltip::before,
|
|
.leaflet-tooltip-left.map-tooltip::before,
|
|
.leaflet-tooltip-top.map-tooltip::before {
|
|
display: none;
|
|
}
|
|
|
|
/* Scrollbars — styled on desktop, hidden on mobile */
|
|
::-webkit-scrollbar {
|
|
width: 6px;
|
|
height: 6px;
|
|
}
|
|
::-webkit-scrollbar-button {
|
|
display: none;
|
|
height: 0;
|
|
width: 0;
|
|
}
|
|
::-webkit-scrollbar-track {
|
|
background: var(--scrollbar-track);
|
|
border-radius: 3px;
|
|
}
|
|
::-webkit-scrollbar-thumb {
|
|
background: var(--scrollbar-thumb);
|
|
border-radius: 3px;
|
|
}
|
|
::-webkit-scrollbar-thumb:hover {
|
|
background: var(--scrollbar-hover);
|
|
}
|
|
|
|
@media (max-width: 767px) {
|
|
* { scrollbar-width: none; }
|
|
::-webkit-scrollbar { width: 0; height: 0; }
|
|
}
|
|
|
|
.route-info-pill { background: none !important; border: none !important; box-shadow: none !important; width: auto !important; height: auto !important; margin: 0 !important; }
|
|
.chat-scroll { overflow-y: auto !important; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
|
|
.chat-scroll::-webkit-scrollbar { width: 0; background: transparent; }
|
|
|
|
|
|
/* Einheitliche Formular-Inputs */
|
|
.form-input {
|
|
width: 100%;
|
|
border: 1px solid var(--border-primary);
|
|
border-radius: 10px;
|
|
padding: 8px 14px;
|
|
font-size: 13px;
|
|
font-family: inherit;
|
|
outline: none;
|
|
box-sizing: border-box;
|
|
color: var(--text-primary);
|
|
background: var(--bg-input);
|
|
transition: border-color 0.15s;
|
|
}
|
|
.form-input:focus {
|
|
border-color: var(--text-faint);
|
|
}
|
|
.form-input::placeholder {
|
|
color: var(--text-faint);
|
|
}
|
|
|
|
/* Brand images: no save/copy/drag */
|
|
img[alt="TREK"] {
|
|
pointer-events: none;
|
|
user-select: none;
|
|
-webkit-user-select: none;
|
|
-webkit-user-drag: none;
|
|
-webkit-touch-callout: none;
|
|
}
|
|
|
|
/* Weiche Übergänge */
|
|
.transition-smooth {
|
|
transition: all 0.2s ease;
|
|
}
|
|
|
|
|
|
|
|
/* Tagesliste */
|
|
.day-list-item {
|
|
transition: background-color 0.15s ease;
|
|
}
|
|
|
|
.day-list-item:hover {
|
|
background-color: var(--bg-secondary);
|
|
}
|
|
|
|
.day-list-item.active {
|
|
background-color: #4f46e5;
|
|
color: white;
|
|
}
|
|
|
|
.scroll-container {
|
|
scrollbar-width: thin;
|
|
scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track);
|
|
}
|
|
|
|
/* ── Dark-Mode: Tailwind-Klassen ─────────────── */
|
|
.dark .bg-slate-50 { background-color: #131316 !important; }
|
|
.dark .bg-slate-100 { background-color: #1c1c21 !important; }
|
|
.dark .bg-white { background-color: #09090b !important; }
|
|
.dark .bg-gray-50 { background-color: #131316 !important; }
|
|
.dark .bg-gray-100 { background-color: #1c1c21 !important; }
|
|
.dark .text-slate-900, .dark .text-gray-900, .dark .text-slate-800 { color: #f4f4f5 !important; }
|
|
.dark .text-slate-700, .dark .text-gray-700 { color: #d4d4d8 !important; }
|
|
.dark .text-slate-600, .dark .text-gray-600 { color: #a1a1aa !important; }
|
|
.dark .text-slate-500, .dark .text-gray-500 { color: #a1a1aa !important; }
|
|
.dark .text-slate-400, .dark .text-gray-400 { color: #71717a !important; }
|
|
.dark .border-slate-200, .dark .border-gray-200, .dark .border-slate-300 { border-color: #27272a !important; }
|
|
.dark .border-gray-100, .dark .border-slate-100 { border-color: #1c1c21 !important; }
|
|
.dark .hover\:bg-slate-50:hover, .dark .hover\:bg-gray-50:hover { background-color: #1c1c21 !important; }
|
|
.dark .bg-slate-50\/60 { background-color: transparent !important; }
|
|
.dark .divide-slate-100 > :not([hidden]) ~ :not([hidden]) { border-color: #27272a !important; }
|
|
.dark .bg-slate-100 { background-color: #27272a !important; }
|
|
.dark .bg-slate-900 { background-color: #e4e4e7 !important; color: #09090b !important; }
|
|
.dark .hover\:bg-slate-700:hover { background-color: #d4d4d8 !important; color: #09090b !important; }
|
|
.dark input, .dark textarea, .dark select {
|
|
background-color: #1c1c21;
|
|
color: #f4f4f5;
|
|
border-color: #27272a;
|
|
}
|
|
.dark input::placeholder, .dark textarea::placeholder { color: #71717a; }
|
|
.dark .bg-emerald-50 { background-color: rgba(16,185,129,0.15) !important; }
|
|
.dark .bg-red-50 { background-color: rgba(239,68,68,0.15) !important; }
|
|
|
|
/* Ladebildschirm */
|
|
.dark .min-h-screen { background-color: var(--bg-primary) !important; }
|
|
|
|
/* Modal-Hintergrund */
|
|
.dark .trek-modal-backdrop { background: rgba(0,0,0,0.6); }
|
|
|
|
/* ── Dark: Fallback für Komponenten die noch nicht auf CSS-Variablen umgestellt sind ── */
|
|
.dark {
|
|
color-scheme: dark;
|
|
}
|
|
|
|
|
|
/* Toast-Animationen */
|
|
@keyframes slideUp {
|
|
from { transform: translateY(100%); }
|
|
to { transform: translateY(0); }
|
|
}
|
|
|
|
@keyframes slide-in-right {
|
|
from { transform: translateX(100%); opacity: 0; }
|
|
to { transform: translateX(0); opacity: 1; }
|
|
}
|
|
|
|
@keyframes slide-out-right {
|
|
from { transform: translateX(0); opacity: 1; }
|
|
to { transform: translateX(100%); opacity: 0; }
|
|
}
|
|
|
|
.toast-enter {
|
|
animation: slide-in-right 0.3s ease-out forwards;
|
|
}
|
|
|
|
.toast-exit {
|
|
animation: slide-out-right 0.3s ease-in forwards;
|
|
}
|
|
|
|
/* Modal-Hintergrund (eigener Namespace, sonst blenden Content-Blocker .modal-backdrop aus) */
|
|
.trek-modal-backdrop {
|
|
backdrop-filter: blur(4px);
|
|
}
|
|
|
|
/* Fortschrittsbalken */
|
|
@keyframes progress-fill {
|
|
from { width: 0; }
|
|
to { width: var(--progress); }
|
|
}
|
|
|
|
/* Anmeldeseiten-Gradient */
|
|
.auth-gradient {
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
}
|
|
|
|
/* Bildanzeige-Overlay */
|
|
.lightbox-overlay {
|
|
position: fixed;
|
|
inset: 0;
|
|
background: rgba(0, 0, 0, 0.95);
|
|
z-index: 1000;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
/* Markdown in Collab Notes */
|
|
.collab-note-md strong, .collab-note-md-full strong { font-weight: 700 !important; }
|
|
.collab-note-md em, .collab-note-md-full em { font-style: italic !important; }
|
|
.collab-note-md h1, .collab-note-md h2, .collab-note-md h3 { font-weight: 700 !important; margin: 0; }
|
|
.collab-note-md-full h1 { font-size: 1.3em !important; font-weight: 700 !important; margin: 0.8em 0 0.3em; }
|
|
.collab-note-md-full h2 { font-size: 1.15em !important; font-weight: 700 !important; margin: 0.8em 0 0.3em; }
|
|
.collab-note-md-full h3 { font-size: 1em !important; font-weight: 700 !important; margin: 0.8em 0 0.3em; }
|
|
.collab-note-md p, .collab-note-md-full p { margin: 0 0 0.3em; }
|
|
.collab-note-md ul, .collab-note-md-full ul { list-style-type: disc !important; padding-left: 1.4em !important; margin: 0.2em 0; }
|
|
.collab-note-md ol, .collab-note-md-full ol { list-style-type: decimal !important; padding-left: 1.4em !important; margin: 0.2em 0; }
|
|
.collab-note-md li, .collab-note-md-full li { display: list-item !important; margin: 0.1em 0; }
|
|
.collab-note-md code, .collab-note-md-full code { font-size: 0.9em; padding: 1px 5px; border-radius: 4px; background: var(--bg-secondary); }
|
|
.collab-note-md-full pre { padding: 10px 12px; border-radius: 8px; background: var(--bg-secondary); overflow-x: auto; margin: 0.5em 0; }
|
|
.collab-note-md-full pre code { padding: 0; background: none; }
|
|
.collab-note-md a, .collab-note-md-full a { color: #3b82f6; text-decoration: underline; word-break: break-all; }
|
|
.collab-note-md blockquote, .collab-note-md-full blockquote { border-left: 3px solid var(--border-primary); padding-left: 12px; margin: 0.5em 0; color: var(--text-muted); }
|
|
.collab-note-md-full table { border-collapse: collapse; width: 100%; margin: 0.5em 0; }
|
|
.collab-note-md-full th, .collab-note-md-full td { border: 1px solid var(--border-primary); padding: 4px 8px; font-size: 0.9em; }
|
|
.collab-note-md-full hr { border: none; border-top: 1px solid var(--border-primary); margin: 0.8em 0; }
|
|
|
|
/* Day-plan header action grid (edit / +transport / note / collapse) */
|
|
.dp-day-actions button {
|
|
color: var(--text-faint);
|
|
background: transparent;
|
|
transition: background-color 0.12s ease, color 0.12s ease;
|
|
}
|
|
.dp-day-actions button:hover {
|
|
background: var(--bg-hover);
|
|
color: var(--text-primary);
|
|
}
|
|
/* Reveal the action grid only when hovering the day row (pointer devices).
|
|
Touch devices (hover: none) keep it visible; the selected day stays visible too. */
|
|
@media (hover: hover) {
|
|
.dp-day-actions { opacity: 0; transition: opacity 0.12s ease; }
|
|
.dp-day-header:hover .dp-day-actions,
|
|
.dp-day-header[data-selected="true"] .dp-day-actions { opacity: 1; }
|
|
}
|