diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 0ffff21..0000000 --- a/.gitignore +++ /dev/null @@ -1,41 +0,0 @@ -# Ignore docs files -_gh_pages -_site -.ruby-version - -# Numerous always-ignore extensions -*.diff -*.err -*.orig -*.log -*.rej -*.swo -*.swp -*.zip -*.vi -*~ - -# OS or Editor folders -.DS_Store -._* -Thumbs.db -.cache -.project -.settings -.tmproj -*.esproj -nbproject -*.sublime-project -*.sublime-workspace -.idea - -# Komodo -*.komodoproject -.komodotools - -# grunt-html-validation -validation-status.json -validation-report.json - -# Folders to ignore -node_modules \ No newline at end of file diff --git a/MICROBLOG_HOWTO.md b/MICROBLOG_HOWTO.md new file mode 100644 index 0000000..9d01ceb --- /dev/null +++ b/MICROBLOG_HOWTO.md @@ -0,0 +1,192 @@ +# Search Engine Experimentation - Micro.blog Anleitung + +Einfache Anleitung für strukturierte Daten in Micro.blog. + +## Was du brauchst + +Nur **Tags** in deinen Posts. Keine komplizierten Einstellungen. + +--- + +## 1. 🍳 Rezepte + +**Tag:** `#rezeptvomchef` + +**Beispiel:** +``` +Omas Gurkensalat + +Zutaten: +- 2 Gurken +- 200ml Sahne +- Essig, Salz, Pfeffer + +Zubereitung: +1. Gurken schneiden +2. Mit Sahne vermischen +3. Ziehen lassen + +#rezeptvomchef +``` + +→ Google kann es im Rezept-Karussell anzeigen + +--- + +## 2. ⭐ Bewertungen (Reviews) + +**Was du schreibst:** +- Sternchen: ★★★★★ oder ⭐⭐⭐⭐⭐ +- Tag: `#review` +- Typ-Tag: `#film`, `#serie`, `#buch` oder `#ort` + +**Sternchen zum Kopieren:** +- ★ (schwarzer Stern) +- ⭐ (gefüllter Stern) + +### Beispiel: Film + +``` +The Matrix + +★★★★★ + +Legendärer Film! + +#film #review +``` + +### Beispiel: Serie + +``` +The Mandalorian + +⭐⭐⭐⭐ + +Tolle Serie! + +#serie #review +``` + +### Beispiel: Buch + +``` +Der Hobbit + +★★★★★ + +Klassiker! + +#buch #review +``` + +### Beispiel: Restaurant/Laden/Ort + +``` +Pizza Luigi + +★★★★★ + +Beste Pizza in Berlin! + +#restaurant #ort #review +``` + +``` +Buchladen am Markt + +★★★★☆ + +Große Auswahl! + +#laden #ort #review +``` + +**Hinweis:** Bei Orten ist egal ob Restaurant, Laden, Park, etc. - nutze einfach `#ort` oder spezifischer `#restaurant` / `#laden`. + +--- + +## 3. 📷 CC-Lizenz für Fotos + +**Option A: Global für alle Fotos** + +In deiner Micro.blog Config: +```json +{ + "params": { + "license": { + "url": "https://creativecommons.org/licenses/by-sa/4.0/", + "name": "CC BY-SA 4.0" + } + } +} +``` + +**Option B: Pro Post** + +Füge den Tag `#cc` hinzu: +``` +Sonnenuntergang am Strand + +[Foto] + +#fotografie #cc +``` + +→ Google erkennt deine Bilder als CC-lizenziert + +--- + +## Tag-Übersicht + +| Was | Tag | Beispiel | +|-----|-----|----------| +| Rezept | `#rezeptvomchef` | Gurkensalat | +| Film-Review | `#film #review` + ★★★★★ | The Matrix | +| Serien-Review | `#serie #review` + ★★★★★ | The Mandalorian | +| Buch-Review | `#buch #review` + ★★★★★ | Der Hobbit | +| Ort-Review | `#ort #review` + ★★★★★ | Restaurant, Laden, Park | +| CC-Lizenz | `#cc` | Für einzelne Posts | + +**Alternative Ort-Tags:** +- `#restaurant` (für Restaurants/Cafés) +- `#laden` oder `#shop` (für Geschäfte) +- `#ort` (für alles andere) + +Alle funktionieren gleich, Google versteht es als "Ort" (Place). + +--- + +## Testen + +**Google Rich Results Test:** +https://search.google.com/test/rich-results + +1. Post erstellen mit Tags +2. URL in Test eingeben +3. Schauen ob Schema erkannt wird + +**In Google suchen:** +``` +site:deine-domain.de [suchbegriff] +``` + +Viele Rich Snippets erscheinen nur bei `site:` Suchen. + +--- + +## Tipps + +1. **Geduld:** Google braucht Tage/Wochen zum Indexieren +2. **Sternchen:** Nur gefüllte zählen (★ oder ⭐), nicht ☆ +3. **Einfach halten:** Tags am Ende, fertig! + +--- + +## Das war's! + +**Rezept:** `#rezeptvomchef` +**Review:** Sternchen ★★★★★ + `#review` + `#film` / `#serie` / `#buch` / `#ort` +**CC-Fotos:** `#cc` oder global einstellen + +Inspiriert von Felix Schwenzels [Search Engine Experimentation](https://wirres.net/articles/zwischenstand-search-engine-experimentation-see). diff --git a/README.md b/README.md index 6ce7985..6276003 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,2 @@ -# Tiny Theme for Micro.blog +Tiny Theme is created and maintained by Matt Langford. This is my custom version powering my [personal Micro.blog](https://fischr.org/). -![Tiny Theme for Micro.blog Logo](https://github.com/MattSLangford/Tiny-Theme-for-Micro.blog/blob/main/screenshot.jpg?raw=true) - -## Description -Tiny Theme is developed for use with the Micro.blog platform. It is designed to be as fast as possible while still supporting all features of the platform and popular plugins. It is the easiest theme to customize on the platform and the first to use Microhooks. - -**Demo and Docs:** [tiny.micro.blog](https://tiny.micro.blog). - -## Credits - -Tiny Theme is created and maintained by Matt Langford ([follow on Mastodon](https://mastodon.social/@mtt). If you have bug reports or feature requests, you can submit them [Github](https://github.com/MattSLangford/Tiny-Theme-for-Micro.blog) (make sure you star the repo) or [contact Matt directly](https://mattlangford.com/). - -## Support Themes by Matt Langford - -Help fund ongoing work on Tiny, Sumo, and Bayou — clean, fast themes for Micro.blog. Your support keeps them updated and free for everyone. - -- \ No newline at end of file diff --git a/SCHEMA_ORG_HOWTO.md b/SCHEMA_ORG_HOWTO.md new file mode 100644 index 0000000..c63d1fc --- /dev/null +++ b/SCHEMA_ORG_HOWTO.md @@ -0,0 +1,219 @@ +# Search Engine Experimentation (SEE) - Anleitung + +Diese Anleitung erklärt, wie du die erweiterten Schema.org Strukturierte Daten Features nutzen kannst, die von Felix' [Search Engine Experimentation Artikel](https://wirres.net/articles/zwischenstand-search-engine-experimentation-see) inspiriert sind. + +## Was ist das? + +Strukturierte Daten (JSON-LD) helfen Suchmaschinen, deinen Content besser zu verstehen. Das führt zu: +- **Rich Snippets** in Google (Sternchen, Bilder, zusätzliche Infos) +- **Besserer Auffindbarkeit** in spezialisierten Suchen (Rezepte, Videos, Bilder) +- **Maschinenlesbaren Lizenzinformationen** für deine Bilder + +## Verfügbare Schema-Typen + +### 1. 🍳 Rezepte (Recipe) + +Erscheint im **Google Rezept-Karussell** mit Bild, Bewertung und Zubereitungszeit. + +**Frontmatter-Beispiel:** + +```yaml +--- +title: "Gurkensalat nach Omas Rezept" +date: 2025-11-30 +photos: + - "https://example.com/gurkensalat.jpg" +recipe: + name: "Gurkensalat" + description: "Frischer Gurkensalat wie bei Oma" + prepTime: "PT10M" # 10 Minuten (ISO 8601 Duration) + cookTime: "PT0M" # keine Kochzeit + totalTime: "PT10M" + recipeYield: "4 Portionen" + recipeCategory: "Salat" + recipeCuisine: "Deutsch" + keywords: "Gurkensalat, Sommer, schnell" + recipeIngredient: + - "2 große Gurken" + - "200ml Sahne" + - "2 EL Essig" + - "1 TL Zucker" + - "Salz und Pfeffer" + recipeInstructions: + - "Gurken schälen und in dünne Scheiben schneiden" + - "Sahne, Essig, Zucker, Salz und Pfeffer vermischen" + - "Gurkenscheiben mit der Marinade vermengen" + - "Mindestens 30 Minuten ziehen lassen" +--- +``` + +**Zeit-Formate (ISO 8601 Duration):** +- `PT10M` = 10 Minuten +- `PT1H` = 1 Stunde +- `PT1H30M` = 1 Stunde 30 Minuten + +### 2. ⭐ Bewertungen (Review) + +Zeigt **Sternchen** in Google-Suchergebnissen an (funktioniert mit `site:` Suche). + +**Beispiel: TV-Serie bewerten** + +```yaml +--- +title: "Plur1bus - Staffel 1" +date: 2025-11-30 +rating: 4.5 # Einfache Variante: nur die Bewertung +# ODER ausführlich: +rating: + value: 4.5 + bestRating: 5 + worstRating: 1 +review: + itemType: "TVSeries" # Oder: Movie, Book, Product, Place, etc. + itemName: "Plur1bus" + itemImage: "https://example.com/pluribus.jpg" +--- + +Tolle Serie über... +``` + +**Beispiel: Restaurant/Ort bewerten** + +```yaml +--- +title: "Denis Pizza Place" +date: 2025-11-30 +rating: 5 +review: + itemType: "Place" # Wichtig für Orte! + itemName: "Denis Pizza Place" + address: + streetAddress: "Hauptstraße 123" + addressLocality: "Berlin" + postalCode: "10115" + addressCountry: "DE" +--- + +Beste Pizza in Berlin! +``` + +**Unterstützte itemType Werte:** +- `TVSeries`, `Movie`, `Book`, `Product` +- `Place`, `Restaurant`, `LocalBusiness` +- `CreativeWork`, `Thing` (Fallback) + +### 3. 🎬 Videos (VideoObject) + +Erscheint im **Google Video-Index** (nur wenn Video Hauptinhalt der Seite ist). + +**Beispiel:** + +```yaml +--- +title: "Mein cooles Video" +date: 2025-11-30 +photos: + - "https://example.com/thumbnail.jpg" # Wird als thumbnailUrl verwendet +video: + name: "Titel des Videos" + description: "Kurze Beschreibung" + contentUrl: "https://example.com/video.mp4" # Direkter Link zum Video + embedUrl: "https://youtube.com/embed/xyz123" # Embed-URL + duration: "PT2M30S" # 2 Minuten 30 Sekunden + uploadDate: "2025-11-30T10:00:00+01:00" # Optional, nutzt sonst .Date + thumbnailUrl: "https://example.com/thumb.jpg" # Optional, nutzt sonst .Params.photos +--- +``` + +**Hinweis:** Google ist streng! Videos erscheinen nur im Video-Tab wenn: +- Das Video der Hauptinhalt der Seite ist (nicht nur Beiwerk) +- Die Seite primär für das Video-Viewing optimiert ist + +### 4. 📷 Creative Commons Lizenzen (ImageObject) + +Markiert deine Bilder als **CC-lizenziert** im Google-Bilder-Index. + +**Beispiel:** + +```yaml +--- +title: "Meine Fotos vom Strand" +date: 2025-11-30 +photos: + - "https://example.com/strand1.jpg" + - "https://example.com/strand2.jpg" +license: + url: "https://creativecommons.org/licenses/by-sa/4.0/" + name: "CC BY-SA 4.0" + attribution: "Felix Schwenzel" + notice: "© Felix Schwenzel - CC BY-SA 4.0" +--- +``` + +**Standard-Lizenz** (wenn nur `license: true`):: +- URL: CC BY-SA 4.0 +- Attribution: Dein Name aus `.Site.Author.name` + +**Beliebte CC-Lizenzen:** +- `https://creativecommons.org/licenses/by/4.0/` (CC BY) +- `https://creativecommons.org/licenses/by-sa/4.0/` (CC BY-SA) +- `https://creativecommons.org/licenses/by-nc/4.0/` (CC BY-NC) +- `https://creativecommons.org/publicdomain/zero/1.0/` (CC0 Public Domain) + +## Testen & Validieren + +### Google Rich Results Test +https://search.google.com/test/rich-results + +Gib deine URL ein und prüfe, ob die strukturierten Daten korrekt sind. + +### Schema.org Validator +https://validator.schema.org/ + +Validiert dein JSON-LD gegen die Schema.org Spezifikation. + +### Google Search Console +- Überwache, wie Google deine strukturierten Daten verarbeitet +- Sieh Fehler und Warnungen +- Beobachte die "Erfolge" (Impressionen, Klicks) + +## Kombination mehrerer Schema-Typen + +Du kannst mehrere Schema-Typen auf einer Seite kombinieren: + +```yaml +--- +title: "Video-Rezept: Gurkensalat" +date: 2025-11-30 +photos: + - "https://example.com/thumbnail.jpg" +# Rezept Schema +recipe: + name: "Gurkensalat" + recipeIngredient: + - "2 Gurken" + recipeInstructions: + - "Gurken schneiden" +# Video Schema +video: + contentUrl: "https://example.com/rezept.mp4" + duration: "PT5M" +# CC-Lizenz für Bilder +license: + url: "https://creativecommons.org/licenses/by/4.0/" +--- +``` + +## Tipps von Felix + +1. **Geduld haben**: Google braucht Zeit (Tage bis Wochen), um strukturierte Daten zu erkennen +2. **Nicht für Klicks optimieren**: Es geht darum, mit den Maschinen zu sprechen, nicht um SEO-Hacks +3. **Mit `site:` suchen**: Viele Rich Snippets erscheinen nur bei `site:deine-domain.de` Suchen +4. **Experimentieren**: Nutze deine Seite als Spielwiese, nicht als Business-Optimierung +5. **Langzeit-Experiment**: Sieh es als Notiz für später, zum Vergleichen + +## Weitere Ressourcen + +- [Google Search Central: Strukturierte Daten](https://developers.google.com/search/docs/appearance/structured-data/intro-structured-data) +- [Schema.org](https://schema.org/) +- [Felix' Original-Artikel](https://wirres.net/articles/zwischenstand-search-engine-experimentation-see) diff --git a/assets/css/main.css b/assets/css/main.css index 7f83c01..200e604 100644 --- a/assets/css/main.css +++ b/assets/css/main.css @@ -32,7 +32,10 @@ /* Special */ --audio-link: #d32f2f; - + --success: #4caf50; + --shared-note-bg: #fff5f5; + --shared-note-text: #7a0000; + /* Spacing & Sizing */ --radius-default: 5px; --radius-round: 40px; @@ -75,6 +78,9 @@ /* Special */ --audio-link: #ff6e6e; + --success: #50fa7b; + --shared-note-bg: #3f2020; + --shared-note-text: #ff9999; } } @@ -87,6 +93,10 @@ box-sizing: border-box; } +html { + scroll-behavior: smooth; +} + body { max-width: 40em; margin: 2em auto; @@ -107,10 +117,25 @@ h1, h2, h3 { line-height: 1.2; } -h2 { +h1, h2 { margin-top: 0; } +.post-content h1 { + font-size: 1.5em; + margin-top: 0; + margin-bottom: 0.6em; +} + +.post-content h1 a { + color: inherit; + text-decoration: none; +} + +.post-content h1 a:hover { + text-decoration: underline; +} + .p-name { text-wrap: balance; } @@ -232,26 +257,19 @@ footer .custom_footer { color: var(--accent2); } -footer .attribution { - display: none; -} - -footer i { - font-size: 1.5em; - padding: 0 5px; -} - -footer a i:hover { - color: var(--text); -} - /* ========================================================================== CONTENT: ARTICLES & POSTS ========================================================================== */ .post-header { - margin-bottom: 0; + margin-bottom: 0; +} + +.post-header .p-name { + font-size: 1.5em; + margin-top: 0; + margin-bottom: 0.8em; } span.post-date { @@ -275,6 +293,11 @@ a.post-date:hover { text-decoration: none; } +.reading-time { + font-size: 0.8em; + color: var(--accent2); +} + .e-content { margin-bottom: 5em; overflow-wrap: anywhere; @@ -470,6 +493,44 @@ pre { padding: 1em; } +/* Code block copy button */ +.code-block-wrapper { + position: relative; + margin: 1em 0; +} + +.copy-code-button { + position: absolute; + top: 0.5em; + right: 0.5em; + padding: 0.4em 0.8em; + font-size: 0.75em; + font-family: var(--font_system_ui); + background-color: var(--accent2); + color: var(--background); + border: none; + border-radius: var(--radius-default); + cursor: pointer; + opacity: 0.7; + transition: opacity 0.2s ease, background-color 0.2s ease; + z-index: 10; +} + +.copy-code-button:hover { + opacity: 1; + background-color: var(--link); +} + +.copy-code-button:focus { + outline: 2px solid var(--link); + outline-offset: 2px; +} + +.copy-code-button.copied { + background-color: var(--success); + color: var(--button-text); +} + /* ========================================================================== FORMS & INPUTS @@ -550,6 +611,14 @@ article img, border-radius: var(--radius-default); } +.photos-grid .photo-tile { + border-radius: var(--radius-default); +} + +.photos-grid .photo-tile img { + border-radius: inherit; +} + /* Video */ video { width: 100%; @@ -559,8 +628,10 @@ video { } /* iFrame */ -iframe { - max-width: 100%; +article iframe, +.e-content iframe { + display: block; + border-radius: var(--radius-default); } @@ -623,12 +694,12 @@ iframe { } .microblog_shared_note { - background: red; - margin: 0 auto; - padding: 5px; - border-radius: var(--radius-default); - color: white; - width: fit-content; + background: var(--shared-note-bg); + margin: 0 auto; + padding: 5px; + border-radius: var(--radius-default); + color: var(--shared-note-text); + width: fit-content; } .microblog_reply_textarea textarea { @@ -645,13 +716,314 @@ iframe { /* ========================================================================== - UTILITY CLASSES + ACCESSIBILITY + ========================================================================== */ + +/* Skip to main content link */ +.skip-link { + position: absolute; + left: -9999px; + background: var(--link); + color: var(--button-text); + padding: 8px 16px; + text-decoration: none; + z-index: 1000; + border-radius: 0 0 var(--radius-default) 0; +} + +.skip-link:focus { + left: 0; + top: 0; +} + +/* Screen reader only content */ +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; +} + +/* Focus indicators for keyboard navigation */ +a:focus-visible, +button:focus-visible, +input:focus-visible, +textarea:focus-visible, +select:focus-visible { + outline: 3px solid var(--link); + outline-offset: 2px; +} + +/* Enhanced focus for navigation links */ +nav a:focus-visible { + outline: 3px solid var(--link); + outline-offset: 2px; + border-radius: 2px; +} + +/* Reduced motion support */ +@media (prefers-reduced-motion: reduce) { + * { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + scroll-behavior: auto !important; + } +} + + +/* ========================================================================== + KEYBOARD SHORTCUTS + ========================================================================== */ + +/* Keyboard-fokussierter Post (temporäres Highlight) */ +.post-preview.keyboard-focused { + outline: 3px solid var(--link); + outline-offset: 4px; + border-radius: var(--radius-default); + transition: outline 0.2s ease; +} + +/* Hilfe-Overlay für Keyboard Shortcuts */ +.keyboard-help-overlay { + display: none; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.7); + backdrop-filter: blur(4px); + z-index: 9999; + align-items: center; + justify-content: center; + padding: 1em; +} + +.keyboard-help-content { + background: var(--background); + color: var(--text); + border-radius: var(--radius-default); + padding: 2em; + max-width: 600px; + width: 100%; + max-height: 90vh; + overflow-y: auto; + position: relative; + box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3); +} + +.keyboard-help-content h2 { + margin-top: 0; + margin-bottom: 1em; + color: var(--text); +} + +.keyboard-help-content h3 { + margin-top: 1.5em; + margin-bottom: 0.5em; + color: var(--accent1); + font-size: 1.1em; +} + +.keyboard-help-close { + position: absolute; + top: 0.5em; + right: 0.5em; + background: none; + border: none; + font-size: 2em; + color: var(--accent2); + cursor: pointer; + padding: 0.2em 0.5em; + line-height: 1; + border-radius: var(--radius-default); +} + +.keyboard-help-close:hover { + background: var(--code); + color: var(--text); +} + +.shortcuts-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 1.5em; +} + +.shortcut-section dl { + margin: 0; +} + +.shortcut-section dt { + display: inline-block; + font-weight: normal; + margin-top: 0.5em; +} + +.shortcut-section dd { + display: inline; + margin-left: 0.5em; + color: var(--accent2); +} + +.shortcut-section dd::after { + content: ""; + display: block; +} + +/* Kbd-Element Styling */ +kbd { + display: inline-block; + padding: 0.2em 0.5em; + font-family: var(--font_monospace_code); + font-size: 0.85em; + background: var(--code); + color: var(--text); + border: 1px solid var(--accent2); + border-radius: 3px; + box-shadow: 0 2px 0 var(--accent2); +} + + +/* ========================================================================== + SCROLL TO TOP BUTTON ========================================================================== */ -.tiny-img { - max-width: 25em; +#myBtn { + --btn-bg: #f7f7f7; + --btn-color: #4a4a4a; + --ring-track-color: rgba(0, 0, 0, 0.08); + --ring-active-color: #4a4a4a; + --scroll-progress: 0%; + + display: none; + position: fixed; + bottom: 1.5rem; + right: 1.5rem; + z-index: 99; + border: none; + background: none; + color: var(--btn-color); + cursor: pointer; + width: 3rem; + height: 3rem; + border-radius: 999px; + font-size: 1rem; + opacity: 0.85; + transition: opacity 0.2s ease, transform 0.2s ease, box-shadow 0.2s ease, + color 0.2s ease; + align-items: center; + justify-content: center; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); + padding: 0; + touch-action: manipulation; + isolation: isolate; +} + +#myBtn::before, +#myBtn::after { + content: ""; + position: absolute; + inset: 0; + border-radius: inherit; + transition: background 0.3s ease, background-color 0.3s ease; + z-index: -1; + pointer-events: none; +} + +#myBtn::before { + background: conic-gradient(var(--ring-active-color) var(--scroll-progress), + var(--ring-track-color) 0); +} + +#myBtn::after { + inset: 0.35rem; + background-color: var(--btn-bg); + box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.05); +} + +#myBtn:focus-visible { + --btn-bg: #4a4a4a; + --btn-color: #f7f7f7; + opacity: 1; + transform: translateY(-2px); + box-shadow: 0 8px 20px rgba(0, 0, 0, 0.12); + outline: 2px solid currentColor; + outline-offset: 4px; +} + +#myBtn:focus-visible::before { + --ring-active-color: #f7f7f7; + --ring-track-color: rgba(255, 255, 255, 0.35); +} + +@media (hover: hover) { + #myBtn:hover { + --btn-bg: #4a4a4a; + --btn-color: #f7f7f7; + opacity: 1; + transform: translateY(-2px); + box-shadow: 0 8px 20px rgba(0, 0, 0, 0.12); + } + + #myBtn:hover::before { + --ring-active-color: #f7f7f7; + --ring-track-color: rgba(255, 255, 255, 0.35); + } +} + +#myBtn:active { + transform: translateY(0); +} + +.scroll-btn__icon { + font-size: 1.4rem; + line-height: 1; + position: relative; + z-index: 1; +} + +@media (prefers-color-scheme: dark) { + #myBtn { + --btn-bg: #1f1f1f; + --btn-color: #f8f8f2; + --ring-track-color: rgba(255, 255, 255, 0.16); + --ring-active-color: #f8f8f2; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.35); + } + + #myBtn::after { + box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.06); + } + + #myBtn:focus-visible { + --btn-bg: #f8f8f2; + --btn-color: #1f1f1f; + box-shadow: 0 8px 20px rgba(0, 0, 0, 0.45); + } + + #myBtn:focus-visible::before { + --ring-active-color: #1f1f1f; + --ring-track-color: rgba(31, 31, 31, 0.4); + } +} + +@media (prefers-color-scheme: dark) and (hover: hover) { + #myBtn:hover { + --btn-bg: #f8f8f2; + --btn-color: #1f1f1f; + box-shadow: 0 8px 20px rgba(0, 0, 0, 0.45); + } + + #myBtn:hover::before { + --ring-active-color: #1f1f1f; + --ring-track-color: rgba(31, 31, 31, 0.4); + } } -.tiny-text { - font-size: 0.6em; -} \ No newline at end of file diff --git a/config.json b/config.json index b265150..89b1dd7 100644 --- a/config.json +++ b/config.json @@ -24,5 +24,28 @@ "home": ["HTML", "RSS", "JSONFeed"] }, + "params": { + "include_conversation": true, + "social": [ + { + "name": "Micro.blog", + "url": "https://micro.blog/fischr", + "relme": "https://micro.blog/fischr?remote_follow=1" + }, + { + "name": "GitHub", + "url": "https://github.com/flschr" + }, + { + "name": "OpenStreetMap", + "url": "https://www.openstreetmap.org/user/fischr" + }, + { + "name": "Twitter", + "url": "https://twitter.com/flschr" + } + ] + }, + "taxonomies": { "tag": "tags" } -} \ No newline at end of file +} diff --git a/i18n-groundwork/de.json b/i18n-groundwork/de.json deleted file mode 100644 index e69de29..0000000 diff --git a/i18n-groundwork/en.json b/i18n-groundwork/en.json deleted file mode 100644 index e69de29..0000000 diff --git a/layouts/404.html b/layouts/404.html new file mode 100644 index 0000000..1b8d0d6 --- /dev/null +++ b/layouts/404.html @@ -0,0 +1,16 @@ +{{ define "title" }} +404 - Seite nicht gefunden | {{ .Site.Title }} +{{ end }} + +{{ define "main" }} +
+
+

Very oooopsi! Diese Seite gibt es leider nicht. Du wirst in zu einem zufälligen Qualitätsartikel weitergeleitet.

+ + Ein Einhorn erbricht einen Regenbogen, satter 404! +
+
+ +{{ $buildHash := .Site.Params.buildHash | default now.Unix }} + +{{ end }} diff --git a/layouts/_default/_markup/render-image.html b/layouts/_default/_markup/render-image.html index bd4cf02..6601042 100644 --- a/layouts/_default/_markup/render-image.html +++ b/layouts/_default/_markup/render-image.html @@ -27,16 +27,19 @@ {{- $decoding := "async" -}} {{- $fetchpriority := cond $isLCP "high" "" -}} +{{- $loading := cond $isLCP "eager" "lazy" -}} {{- if $res -}} {{/* Lokales Bild: responsive Derivate */}} - {{- $widths := slice 400 768 1024 1440 -}} + {{- $siteQuality := default 80 ($page.Site.Params.renderImageQuality) -}} + {{- $quality := (default $siteQuality ($page.Param "renderImageQuality")) | int -}} + {{- $widths := slice 200 400 768 1024 1440 -}} {{- $srcset := slice -}} {{- range $w := $widths -}} - {{- $v := $res.Fit (printf "%dx q85" $w) -}} + {{- $v := $res.Fit (printf "%dx q%d" $w $quality) -}} {{- $srcset = $srcset | append (printf "%s %dw" $v.RelPermalink $w) -}} {{- end -}} - {{- $default := $res.Fit "1024x q85" -}} + {{- $default := $res.Fit (printf "1024x q%d" $quality) -}} {{ $alt }} {{- else -}} @@ -74,6 +78,7 @@ sizes="(max-width: 640px) 100vw, (max-width: 1024px) 95vw, 720px" decoding="{{ $decoding }}" {{ if $fetchpriority }}fetchpriority="{{ $fetchpriority }}"{{ end }} + loading="{{ $loading }}" alt="{{ $alt }}" {{ with $title }}title="{{ . }}"{{ end }}> {{- end -}} \ No newline at end of file diff --git a/layouts/_default/baseof.html b/layouts/_default/baseof.html index 29608db..ef9cbfc 100644 --- a/layouts/_default/baseof.html +++ b/layouts/_default/baseof.html @@ -4,20 +4,22 @@ {{ partial "head.html" . }} + + {{ partial "header.html" . }} -
+
{{ block "main" . }}{{ end }}
{{ if templates.Exists "partials/microhook-below-wrapper.html" }} {{ partial "microhook-below-wrapper.html" . }} {{ end }} -
+ {{ partial "footer.html" . }} {{ range .Site.Params.plugins_js }} - + {{ end }} {{ if templates.Exists "partials/microhook-before-closing-body.html" }} diff --git a/layouts/_default/list.archivehtml.html b/layouts/_default/list.archivehtml.html deleted file mode 100644 index 7caea1a..0000000 --- a/layouts/_default/list.archivehtml.html +++ /dev/null @@ -1,586 +0,0 @@ -{{ define "main" }} -
-

In über {{ sub now.Year 2002 }} Jahren haben sich {{ len (where .Site.RegularPages "Type" "post") }} fabelhafte Artikel in diesem Blog angesammelt, die du hier ganz bequem durchsuchen und filtern kannst.

- - {{ if templates.Exists "partials/microhook-archive-lead.html" }} - {{ partial "microhook-archive-lead.html" . }} - {{ end }} - -
- - -
- - -
- - - - -
- - - - - - -
- - - - -{{ end }} \ No newline at end of file diff --git a/layouts/_default/list.html b/layouts/_default/list.html index 50ce95e..869e877 100644 --- a/layouts/_default/list.html +++ b/layouts/_default/list.html @@ -4,7 +4,7 @@ {{ else }}
-

{{ .Title }}

+

{{ .Title }}

{{ if templates.Exists "partials/microhook-category-header.html" }} {{ partial "microhook-category-header.html" . }} @@ -34,10 +34,33 @@

{{ end }} - -
- {{ .Content }} -
+ {{ if in .RawContent "" }} +
+ {{ $splitContents := split .RawContent "" }} + {{ $summary := index $splitContents 0 }} + {{ $summary := replaceRE "\\[\\^.*?\\]" "" $summary }} + {{ $summary := replaceRE "\\\n\\[\\^.*?\\]:.*" "" $summary }} + {{ $summary | markdownify }} +

+ {{ if templates.Exists "partials/microhook-read-more-text.html" }} + {{ partial "microhook-read-more-text.html" . }} + {{ else }} + Read More → + {{ end }} +

+
+ {{ else }} +
+ {{ .Summary | safeHTML }} +

+ {{ if templates.Exists "partials/microhook-read-more-text.html" }} + {{ partial "microhook-read-more-text.html" . }} + {{ else }} + Read More → + {{ end }} +

+
+ {{ end }} {{ if templates.Exists "partials/microhook-below-post-in-list.html" }} {{ partial "microhook-below-post-in-list.html" . }} diff --git a/layouts/_default/list.photoshtml.html b/layouts/_default/list.photoshtml.html index a92fad0..ea0810c 100644 --- a/layouts/_default/list.photoshtml.html +++ b/layouts/_default/list.photoshtml.html @@ -1,765 +1,102 @@ {{ define "main" }} -
- - -
- - - - - - -
- {{ $pages := sort (where .Site.RegularPages "Type" "in" (slice "post" "photo")) "Date" "desc" }} - {{ $imageIndex := 0 }} - - {{ range $p := $pages }} - {{ $dateFormatted := $p.Date.Format "2. January 2006" }} - {{ $year := $p.Date.Format "2006" }} - {{ $overlayCaption := "" }} - {{ with $p.Title }}{{ $overlayCaption = . | plainify | truncate 80 }}{{ end }} - - {{ with $p.Params.photos }} - {{ range $i, $url := . }} - {{ $caption := $overlayCaption }} - {{ $eager := lt $imageIndex 12 }} - {{ $isMBPhotos := or (hasPrefix $url "https://micro.blog/photos/") (hasPrefix $url "http://micro.blog/photos/") }} - {{ $src300 := "" }}{{ $src600 := "" }}{{ $srcFull := "" }} - {{ if $isMBPhotos }} - {{ $src300 = replaceRE `/photos/[^/]+/` "/photos/200x/" $url }} - {{ $src600 = replaceRE `/photos/[^/]+/` "/photos/400x/" $url }} - {{ $srcFull = $url }} - {{ else }} - {{ $encoded := $url | urlquery }} - {{ $src300 = printf "https://micro.blog/photos/200x/%s" $encoded }} - {{ $src600 = printf "https://micro.blog/photos/400x/%s" $encoded }} - {{ $srcFull = $url }} - {{ end }} - -
- {{ if $eager }} - {{ if $caption }}{{ $caption }}{{ else }}{{ $dateFormatted }}{{ end }} - {{ else }} - {{ $tiny := "" }} - {{ if $isMBPhotos }} - {{ $tiny = replaceRE `/photos/[^/]+/` "/photos/40x/" $url }} - {{ else }} - {{ $encoded2 := $url | urlquery }} - {{ $tiny = printf "https://micro.blog/photos/40x/%s" $encoded2 }} - {{ end }} - {{ if $caption }}{{ $caption }}{{ else }}{{ $dateFormatted }}{{ end }} - {{ end }} - - -
- {{ $imageIndex = add $imageIndex 1 }} - {{ end }} +{{ $buildHash := .Site.Params.buildHash | default now.Unix }} + + + +
+

Foto-Archiv

+ + {{/* Konstanten */}} + {{ $eagerLoadThreshold := 8 }} + + {{ $pages := sort (where .Site.RegularPages "Type" "in" (slice "post" "photo")) "Date" "desc" }} + {{ $.Scratch.Set "currentMonth" "" }} + {{ $.Scratch.Set "sectionOpen" false }} + {{ $imageIndex := 0 }} + + {{/* Deutsche Monatsnamen */}} + {{ $monthsDE := dict "January" "Januar" "February" "Februar" "March" "März" "April" "April" "May" "Mai" "June" "Juni" "July" "Juli" "August" "August" "September" "September" "October" "Oktober" "November" "November" "December" "Dezember" }} + + {{ range $p := $pages }} + {{ $monthEN := $p.Date.Format "January" }} + {{ $monthDE := index $monthsDE $monthEN }} + {{ $dateFormatted := printf "%d. %s %s" $p.Date.Day $monthDE ($p.Date.Format "2006") }} + {{ $dateISO := $p.Date.Format "2006-01-02" }} + {{ $year := $p.Date.Format "2006" }} + {{ $monthYear := printf "%s %s" $monthDE ($p.Date.Format "2006") }} + + {{/* Micro.blog Photos */}} + {{ with $p.Params.photos }} + {{ range $i, $url := . }} + {{ $eager := lt $imageIndex $eagerLoadThreshold }} + {{ $isMBPhotos := or (hasPrefix $url "https://micro.blog/photos/") (hasPrefix $url "http://micro.blog/photos/") }} + {{ $src200 := "" }}{{ $src400 := "" }} + + {{ if $isMBPhotos }} + {{ $src200 = replaceRE "/photos/[0-9]+/" "/photos/200/" $url }} + {{ $src400 = replaceRE "/photos/[0-9]+/" "/photos/400/" $url }} + {{ else }} + {{ $src200 = $url }} + {{ $src400 = $url }} {{ end }} - {{ $imgs := $p.Resources.ByType "image" }} - {{ range $img := $imgs }} - {{ $name := $img.Name | lower }} - {{ if not (or (hasPrefix $name "hero") (in $name "og-") (in $name "open-graph") (in $name "social") (in $name "thumb")) }} - {{ $w300 := $img.Fit "200x200 q85" }} - {{ $w600 := $img.Fit "400x400 q85" }} - {{ $caption := $overlayCaption }} - {{ $eager := lt $imageIndex 12 }} - -
- {{ if $eager }} - {{ if $caption }}{{ $caption }}{{ else }}{{ $dateFormatted }}{{ end }} - {{ else }} - {{ $w40 := $img.Fit "40x40 q50" }} - {{ if $caption }}{{ $caption }}{{ else }}{{ $dateFormatted }}{{ end }} - {{ end }} - - -
- {{ $imageIndex = add $imageIndex 1 }} - {{ end }} - {{ end }} + {{/* Open month section if needed */}} + {{ partial "open-month-section.html" (dict "page" $p "monthYear" $monthYear "context" $) }} + + + {{ if $p.Title }}{{ $p.Title }}{{ else }}Foto vom {{ $dateFormatted }}{{ end }} + {{ $dateFormatted }} + {{ if $p.Title }}{{ $p.Title }}{{ end }} + + + {{ $imageIndex = add $imageIndex 1 }} {{ end }} -
-
- - - - -
-{{ end }} \ No newline at end of file +
+{{ end }} diff --git a/layouts/index.html b/layouts/index.html index 4bd8041..a7661a6 100644 --- a/layouts/index.html +++ b/layouts/index.html @@ -7,14 +7,14 @@ {{ partial "microhook-before-post-list.html" . }} {{ end }}
-
+
{{ $paginator := .Paginate (where .Site.Pages.ByDate.Reverse "Type" "post") }} {{ range .Paginator.Pages }}
{{ if templates.Exists "partials/microhook-post-list-byline.html" }} {{ partial "microhook-post-list-byline.html" . }} {{ else }} - + {{ if .Title }} · Lesedauer {{ .ReadingTime }} Minuten{{ end }} {{ end }} {{ if .Title }}

{{ .Title }}

@@ -35,7 +35,7 @@

{{ .Title }}

{{ else if .Params.custom_summary }}
-

{{ .Summary | safeHTML }}

+ {{ .Summary | safeHTML }}

{{ else }}
diff --git a/layouts/partials/footer.html b/layouts/partials/footer.html index e0992a5..86039ce 100644 --- a/layouts/partials/footer.html +++ b/layouts/partials/footer.html @@ -3,11 +3,39 @@

Read a random post or wander to another blog.
- That’s all there is, there isn’t any more. + That's all there is, there isn't any more.

+ + + + + {{ $buildHash := .Site.Params.buildHash | default now.Unix }} + + + + + + + + {{ if or (findRE " + {{ end }} + + + + - - - \ No newline at end of file + + + diff --git a/layouts/partials/head.html b/layouts/partials/head.html index 3678b03..2d880da 100644 --- a/layouts/partials/head.html +++ b/layouts/partials/head.html @@ -2,33 +2,53 @@ - - - - - + + + {{ if .Params.photos }} + {{ end }} + + + + + {{ $buildHash := .Site.Params.buildHash | default now.Unix }} - + {{ if templates.Exists "partials/microhook-uncss.html" }} {{ partial "microhook-uncss.html" . }} {{ else }} {{ $mainCss := resources.Get "css/main.css" }} {{ if $mainCss }} - {{ $mainCss = $mainCss | minify | fingerprint }} - + {{ $mainCss = $mainCss | minify | fingerprint "sha256" }} + + {{ else }} + + {{ end }} {{ end }} + {{ $ogAlt := "" }} + {{ with .Title }} + {{ $ogAlt = . }} + {{ end }} + {{ if not $ogAlt }} + {{ with .Site.Params.opengraph.altFallback }} + {{ $ogAlt = . }} + {{ end }} + {{ end }} + {{ if not $ogAlt }} + {{ $ogAlt = .Site.Title }} + {{ end }} + {{ with .Site.Params.twitter_username }} @@ -48,6 +68,8 @@ + + {{ else }} {{ $description := .Summary | plainify | truncate 155 }} @@ -59,12 +81,15 @@ {{ range first 1 .Params.photos }} - + + {{ end }} {{ else }} {{ with .Params.opengraph.image }} + + {{ end }} {{ end }} @@ -99,15 +124,23 @@ {{ if or .Params.noindex (eq .Kind "404") }} {{ end }} + + {{ if eq .Kind "404" }} + + {{ end }} {{ partial "schema_org.html" . }} {{ partial "microblog_head.html" . }} + + + {{ partial "embed-consent-config.html" . }} + {{ if templates.Exists "partials/microhook-head.html" }} {{ partial "microhook-head.html" . }} {{ end }} - \ No newline at end of file + diff --git a/layouts/partials/header.html b/layouts/partials/header.html index 8a68d22..df30bc9 100644 --- a/layouts/partials/header.html +++ b/layouts/partials/header.html @@ -18,7 +18,7 @@ {{ partial "microhook-title.html" . }} {{ else }}

{{ .Site.Title }}

-

Tagebuch, Langzeitspeicher und Verdauungsorgan.

+

Spielplatz, Langzeitspeicher und Verdauungsorgan.

{{ end }} {{ if templates.Exists "partials/microhook-navigation.html" }} @@ -33,8 +33,8 @@

{{ .Site.Title }} {{ range .Site.Menus.main }}
  • {{ if .Page.Params.redirect_url }} - {{ .Site.Title }} {{ .Name }} {{ else }} - {{ .Name }} diff --git a/layouts/partials/microblog_head.html b/layouts/partials/microblog_head.html index 48a4c03..aad213b 100644 --- a/layouts/partials/microblog_head.html +++ b/layouts/partials/microblog_head.html @@ -1,7 +1,7 @@ - - - + + + {{ $title := site.Title }} @@ -16,10 +16,14 @@ {{- end }} - - - - +{{- with .Site.Params.social }} + {{- range . }} + {{- $rel := .relme | default .url }} + {{- with $rel }} + + {{- end }} + {{- end }} +{{- end }} @@ -27,5 +31,4 @@ - - \ No newline at end of file + \ No newline at end of file diff --git a/layouts/partials/open-month-section.html b/layouts/partials/open-month-section.html new file mode 100644 index 0000000..9de189d --- /dev/null +++ b/layouts/partials/open-month-section.html @@ -0,0 +1,31 @@ +{{/* + Partial: open-month-section.html + + Öffnet bei Bedarf eine neue Monats-Sektion für die Foto-Galerie. + Schließt die vorherige Sektion, falls eine offen ist. + + Verwendung: + {{ partial "open-month-section.html" (dict "page" $p "monthYear" $monthYear "context" $) }} + + Parameter: + - page: Die aktuelle Page ($p) + - monthYear: String im Format "Januar 2024" + - context: Der Root-Context ($) für Scratch-Zugriff +*/}} + +{{- $p := .page -}} +{{- $monthYear := .monthYear -}} +{{- $ctx := .context -}} +{{- $monthId := printf "%s-%s" ($p.Date.Format "2006") ($p.Date.Format "01") -}} + +{{- if ne $monthYear ($ctx.Scratch.Get "currentMonth") -}} + {{- if $ctx.Scratch.Get "sectionOpen" -}} +
  • {{/* Close previous grid */}} + + {{- end -}} +
    +

    {{ $monthYear }}

    +
    + {{- $ctx.Scratch.Set "currentMonth" $monthYear -}} + {{- $ctx.Scratch.Set "sectionOpen" true -}} +{{- end -}} diff --git a/layouts/partials/schema_org.html b/layouts/partials/schema_org.html index aa0e9d1..fc551f0 100644 --- a/layouts/partials/schema_org.html +++ b/layouts/partials/schema_org.html @@ -1,13 +1,15 @@ -{{/* +{{/* schema_org.html — JSON-LD für fischr.org - - Erzeugt je Seite genau EIN Snippet: + - Erzeugt strukturierte Daten für verschiedene Content-Typen: * Blog (nur Startseite) * BlogPosting (Posts) oder WebPage (statische Seiten) + * Recipe (Tag: rezeptvomchef) + * Review (Tag: review + Sternchen ★ oder ⭐) + * ImageObject mit Creative Commons (Tag: cc oder Site.Params.license) * BreadcrumbList (außer auf Home) - - Bildlogik (Fallback-Kaskade): - hero* Resource → erstes Page-Image → erstes .Params.photos → .Site.Params.default_image + - Review-Typen: Film (Movie), Serie (TVSeries), Buch (Book), Ort (Place) + - Bildlogik: hero* Resource → Page-Image → .Params.photos → default_image - Sprache: fallback "de" - - Einbinden im via: {{ partial "schema_org.html" . }} */}} {{- $iso := "2006-01-02T15:04:05-07:00" -}} @@ -15,6 +17,12 @@ {{- $authorName := .Site.Author.name | default .Site.Title -}} {{- $authorURL := .Site.Author.url | default .Site.BaseURL -}} {{- $authorURLAbs := $authorURL | absURL -}} +{{- $sameAs := slice -}} +{{- range .Site.Params.social }} + {{- with .url }} + {{- $sameAs = $sameAs | append (. | absURL) -}} + {{- end }} +{{- end -}} {{/* Bild finden (absolute URL sicherstellen) */}} {{- $img := "" -}} @@ -33,10 +41,22 @@ "url": {{ printf "%q" .Site.BaseURL }}, "inLanguage": {{ printf "%q" $lang }}, "description": {{ printf "%q" (.Site.Params.description | default .Site.Title) }}, + {{- with $sameAs }} + "sameAs": [ + {{- range $index, $url := . -}} + {{- if $index }}, {{ end -}}{{ printf "%q" $url }} + {{- end }} + ], + {{- end }} "publisher": { "@type": "Organization", "name": {{ printf "%q" .Site.Title }}, - "url": {{ printf "%q" .Site.BaseURL }} + "url": {{ printf "%q" .Site.BaseURL }}{{- with $sameAs }}, + "sameAs": [ + {{- range $index, $url := . -}} + {{- if $index }}, {{ end -}}{{ printf "%q" $url }} + {{- end }} + ]{{- end }} } } @@ -60,8 +80,33 @@ {{- with .Lastmod }} "dateModified": {{ printf "%q" (.Format $iso) }}, {{ end -}} "inLanguage": {{ printf "%q" $lang }}, "url": {{ printf "%q" .Permalink }}, - "author": { "@type": "Person", "name": {{ printf "%q" $authorName }}, "url": {{ printf "%q" $authorURLAbs }} }, - "publisher": { "@type": "Organization", "name": {{ printf "%q" .Site.Title }}, "url": {{ printf "%q" .Site.BaseURL }} } + {{- with $sameAs }} + "sameAs": [ + {{- range $index, $url := . -}} + {{- if $index }}, {{ end -}}{{ printf "%q" $url }} + {{- end }} + ], + {{- end }} + "author": { + "@type": "Person", + "name": {{ printf "%q" $authorName }}, + "url": {{ printf "%q" $authorURLAbs }}{{- with $sameAs }}, + "sameAs": [ + {{- range $index, $url := . -}} + {{- if $index }}, {{ end -}}{{ printf "%q" $url }} + {{- end }} + ]{{- end }} + }, + "publisher": { + "@type": "Organization", + "name": {{ printf "%q" .Site.Title }}, + "url": {{ printf "%q" .Site.BaseURL }}{{- with $sameAs }}, + "sameAs": [ + {{- range $index, $url := . -}} + {{- if $index }}, {{ end -}}{{ printf "%q" $url }} + {{- end }} + ]{{- end }} + } {{- with .GetTerms "categories" -}} , "articleSection": {{ printf "%q" (index . 0).LinkTitle }}, "keywords": [{{ range $i,$t := . }}{{ if $i }}, {{ end }}{{ printf "%q" $t.LinkTitle }}{{ end }}] @@ -71,6 +116,240 @@ {{- end -}} +{{/* Recipe Schema - aktiviert durch Tag/Category "rezeptvomchef" ODER .Params.recipe */}} +{{- $isRecipe := false -}} +{{- if .Params.recipe }}{{ $isRecipe = true }}{{ end -}} +{{- range $term := .GetTerms "tags" }} + {{- if in (slice "rezeptvomchef" "rezept" "recipe" "kochen") (lower $term.LinkTitle) }}{{ $isRecipe = true }}{{ end -}} +{{- end -}} +{{- range $term := .GetTerms "categories" }} + {{- if in (slice "rezeptvomchef" "rezept" "recipe" "kochen") (lower $term.LinkTitle) }}{{ $isRecipe = true }}{{ end -}} +{{- end -}} + +{{- if $isRecipe -}} + +{{- end -}} + +{{/* Review Schema - aktiviert durch Tag "review"/"rezension" ODER .Params.rating ODER Sternchen im Content */}} +{{- $isReview := false -}} +{{- $ratingValue := 0.0 -}} +{{- $reviewItemType := "Thing" -}} + +{{/* Prüfe auf explizites Rating in Params */}} +{{- if .Params.rating }} + {{- $isReview = true -}} + {{- if reflect.IsMap .Params.rating }} + {{- $ratingValue = .Params.rating.value -}} + {{- else }} + {{- $ratingValue = .Params.rating -}} + {{- end }} +{{- end -}} + +{{/* Prüfe auf review Tag/Category */}} +{{- range $term := .GetTerms "tags" }} + {{- if in (slice "review" "rezension" "bewertung" "kritik") (lower $term.LinkTitle) }}{{ $isReview = true }}{{ end -}} +{{- end -}} +{{- range $term := .GetTerms "categories" }} + {{- if in (slice "review" "rezension" "bewertung" "kritik") (lower $term.LinkTitle) }}{{ $isReview = true }}{{ end -}} +{{- end -}} + +{{/* Automatische Sternchen-Erkennung im Content (⭐⭐⭐⭐⭐ oder ★★★★★) */}} +{{- if not $ratingValue -}} + {{- $content := .Content | plainify -}} + {{/* Suche nach ⭐ (U+2B50) oder ★ (U+2605) */}} + {{- $stars := findRE "[⭐★]+" $content 1 -}} + {{- if $stars -}} + {{- $starCount := len (index $stars 0) -}} + {{- if gt $starCount 0 -}} + {{- $isReview = true -}} + {{- $ratingValue = $starCount -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{/* Bestimme Review-Typ aus Tags - vereinfacht auf Film, Serie, Buch, Ort */}} +{{- range $term := .GetTerms "tags" }} + {{- $tag := lower $term.LinkTitle -}} + {{- if in (slice "film" "movie" "kino") $tag }}{{ $reviewItemType = "Movie" }}{{ end -}} + {{- if in (slice "serie" "tv" "fernsehen") $tag }}{{ $reviewItemType = "TVSeries" }}{{ end -}} + {{- if in (slice "buch" "book" "lesen") $tag }}{{ $reviewItemType = "Book" }}{{ end -}} + {{- if in (slice "restaurant" "laden" "shop" "geschäft" "ort" "place" "cafe" "location") $tag }}{{ $reviewItemType = "Place" }}{{ end -}} +{{- end -}} + +{{- if and $isReview (gt $ratingValue 0) -}} + +{{- end -}} + +{{/* ImageObject with Creative Commons License - aktiviert durch .Site.Params.license ODER .Params.license ODER Tag "cc" */}} +{{- $hasLicense := false -}} +{{- $licenseURL := "" -}} +{{- $licenseName := "CC BY-SA 4.0" -}} + +{{/* Prüfe Site-weite Lizenz-Einstellung */}} +{{- if .Site.Params.license }} + {{- $hasLicense = true -}} + {{- if reflect.IsMap .Site.Params.license }} + {{- $licenseURL = .Site.Params.license.url | default "https://creativecommons.org/licenses/by-sa/4.0/" -}} + {{- $licenseName = .Site.Params.license.name | default "CC BY-SA 4.0" -}} + {{- else }} + {{- $licenseURL = .Site.Params.license -}} + {{- end }} +{{- end -}} + +{{/* Post-spezifische Lizenz überschreibt Site-Default */}} +{{- if .Params.license }} + {{- $hasLicense = true -}} + {{- if reflect.IsMap .Params.license }} + {{- $licenseURL = .Params.license.url | default "https://creativecommons.org/licenses/by-sa/4.0/" -}} + {{- $licenseName = .Params.license.name | default "CC BY-SA 4.0" -}} + {{- else }} + {{- $licenseURL = .Params.license -}} + {{- end }} +{{- end -}} + +{{/* Aktivierung durch "cc" Tag */}} +{{- range $term := .GetTerms "tags" }} + {{- if in (slice "cc" "creative-commons" "creativecommons") (lower $term.LinkTitle) }} + {{- $hasLicense = true -}} + {{- if not $licenseURL }}{{ $licenseURL = "https://creativecommons.org/licenses/by-sa/4.0/" }}{{ end -}} + {{- end -}} +{{- end -}} + +{{/* Generiere ImageObject für alle Fotos wenn Lizenz aktiv */}} +{{- if and $hasLicense .Params.photos -}} +{{- range $index, $photo := .Params.photos }} + +{{- end }} +{{- end -}} + {{/* 2) Breadcrumbs (nicht auf Home) */}} {{- if not .IsHome -}} {{- $home := "/" | absURL -}} diff --git a/layouts/post/single.html b/layouts/post/single.html index de1933a..5985ea5 100644 --- a/layouts/post/single.html +++ b/layouts/post/single.html @@ -10,23 +10,21 @@ {{ if templates.Exists "partials/microhook-post-byline.html" }} {{ partial "microhook-post-byline.html" . }} {{ else }} - + {{ if .Title }} · Lesedauer {{ .ReadingTime }} Minuten{{ end }} {{ with .Params.audio }} - + {{ end }} {{ end }} -{{- $hideTitle := .Params.hideTitle | default false -}} -{{- $forceTitle := .Params.forceTitle | default false -}} {{ if .Title }} -

    {{ .Title }}

    +

    {{ .Title }}

    {{ end }}
    - {{ .Content }} + {{ .Content }}
    - {{ if templates.Exists "partials/microhook-categories.html" }} +
    {{ if or (templates.Exists "partials/reply-by-email.html") (templates.Exists "partials/conversation-link.html") (templates.Exists "partials/plugin_tinylytics.html") (templates.Exists "partials/reply-on-mastodon.html") (templates.Exists "partials/microhook-share-button.html")}}
      - {{ if templates.Exists "partials/plugin_tinylytics.html" }} -
    • - {{ end }} {{ if templates.Exists "partials/reply-by-email.html" }}
    • {{ partial "reply-by-email.html" . }}
    • {{ end }} @@ -59,9 +54,6 @@

      {{ .Title }}

      {{ if templates.Exists "partials/reply-on-mastodon.html" }}
    • {{ partial "reply-on-mastodon.html" . }}
    • {{ end }} - {{ if templates.Exists "partials/microhook-share-button.html" }} - {{ partial "microhook-share-button.html" . }} - {{ end }}
    {{ end }} diff --git a/layouts/sitemap.xml b/layouts/sitemap.xml new file mode 100644 index 0000000..828772b --- /dev/null +++ b/layouts/sitemap.xml @@ -0,0 +1,22 @@ +{{ printf "" | safeHTML }} + + {{ range .Data.Pages }} + + {{ .Permalink }}{{ if not .Lastmod.IsZero }} + {{ .Lastmod.Format "2006-01-02T15:04:05-07:00" | safeHTML }}{{ end }}{{ with .Sitemap.ChangeFreq }} + {{ . }}{{ end }}{{ if ge .Sitemap.Priority 0.0 }} + {{ .Sitemap.Priority }}{{ end }}{{ if .IsTranslated }}{{ range .Translations }} + {{ end }} + {{ end }} + + {{ end }} + diff --git a/screenshot.jpg b/screenshot.jpg deleted file mode 100644 index fd97055..0000000 Binary files a/screenshot.jpg and /dev/null differ diff --git a/static/css/all.min.css b/static/css/all.min.css deleted file mode 100644 index 29542ac..0000000 --- a/static/css/all.min.css +++ /dev/null @@ -1,9 +0,0 @@ -/*! - * Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com - * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) - * Copyright 2024 Fonticons, Inc. - */ -.fa{font-family:var(--fa-style-family,"Font Awesome 6 Free");font-weight:var(--fa-style,900)}.fa,.fa-brands,.fa-regular,.fa-solid,.fab,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:var(--fa-display,inline-block);font-style:normal;font-variant:normal;line-height:1;text-rendering:auto}.fa-brands:before,.fa-regular:before,.fa-solid:before,.fa:before,.fab:before,.far:before,.fas:before{content:var(--fa)}.fa-classic,.fa-regular,.fa-solid,.far,.fas{font-family:"Font Awesome 6 Free"}.fa-brands,.fab{font-family:"Font Awesome 6 Brands"}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-2xs{font-size:.625em;line-height:.1em;vertical-align:.225em}.fa-xs{font-size:.75em;line-height:.08333em;vertical-align:.125em}.fa-sm{font-size:.875em;line-height:.07143em;vertical-align:.05357em}.fa-lg{font-size:1.25em;line-height:.05em;vertical-align:-.075em}.fa-xl{font-size:1.5em;line-height:.04167em;vertical-align:-.125em}.fa-2xl{font-size:2em;line-height:.03125em;vertical-align:-.1875em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:var(--fa-li-margin,2.5em);padding-left:0}.fa-ul>li{position:relative}.fa-li{left:calc(var(--fa-li-width, 2em)*-1);position:absolute;text-align:center;width:var(--fa-li-width,2em);line-height:inherit}.fa-border{border-radius:var(--fa-border-radius,.1em);border:var(--fa-border-width,.08em) var(--fa-border-style,solid) var(--fa-border-color,#eee);padding:var(--fa-border-padding,.2em .25em .15em)}.fa-pull-left{float:left;margin-right:var(--fa-pull-margin,.3em)}.fa-pull-right{float:right;margin-left:var(--fa-pull-margin,.3em)}.fa-beat{animation-name:fa-beat;animation-delay:var(--fa-animation-delay,0s);animation-direction:var(--fa-animation-direction,normal);animation-duration:var(--fa-animation-duration,1s);animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-timing-function:var(--fa-animation-timing,ease-in-out)}.fa-bounce{animation-name:fa-bounce;animation-delay:var(--fa-animation-delay,0s);animation-direction:var(--fa-animation-direction,normal);animation-duration:var(--fa-animation-duration,1s);animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-timing-function:var(--fa-animation-timing,cubic-bezier(.28,.84,.42,1))}.fa-fade{animation-name:fa-fade;animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1))}.fa-beat-fade,.fa-fade{animation-delay:var(--fa-animation-delay,0s);animation-direction:var(--fa-animation-direction,normal);animation-duration:var(--fa-animation-duration,1s)}.fa-beat-fade{animation-name:fa-beat-fade;animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1))}.fa-flip{animation-name:fa-flip;animation-delay:var(--fa-animation-delay,0s);animation-direction:var(--fa-animation-direction,normal);animation-duration:var(--fa-animation-duration,1s);animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-timing-function:var(--fa-animation-timing,ease-in-out)}.fa-shake{animation-name:fa-shake;animation-duration:var(--fa-animation-duration,1s);animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-timing-function:var(--fa-animation-timing,linear)}.fa-shake,.fa-spin{animation-delay:var(--fa-animation-delay,0s);animation-direction:var(--fa-animation-direction,normal)}.fa-spin{animation-name:fa-spin;animation-duration:var(--fa-animation-duration,2s);animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-timing-function:var(--fa-animation-timing,linear)}.fa-spin-reverse{--fa-animation-direction:reverse}.fa-pulse,.fa-spin-pulse{animation-name:fa-spin;animation-direction:var(--fa-animation-direction,normal);animation-duration:var(--fa-animation-duration,1s);animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-timing-function:var(--fa-animation-timing,steps(8))}@media (prefers-reduced-motion:reduce){.fa-beat,.fa-beat-fade,.fa-bounce,.fa-fade,.fa-flip,.fa-pulse,.fa-shake,.fa-spin,.fa-spin-pulse{animation-delay:-1ms;animation-duration:1ms;animation-iteration-count:1;transition-delay:0s;transition-duration:0s}}@keyframes fa-beat{0%,90%{transform:scale(1)}45%{transform:scale(var(--fa-beat-scale,1.25))}}@keyframes fa-bounce{0%{transform:scale(1) translateY(0)}10%{transform:scale(var(--fa-bounce-start-scale-x,1.1),var(--fa-bounce-start-scale-y,.9)) translateY(0)}30%{transform:scale(var(--fa-bounce-jump-scale-x,.9),var(--fa-bounce-jump-scale-y,1.1)) translateY(var(--fa-bounce-height,-.5em))}50%{transform:scale(var(--fa-bounce-land-scale-x,1.05),var(--fa-bounce-land-scale-y,.95)) translateY(0)}57%{transform:scale(1) translateY(var(--fa-bounce-rebound,-.125em))}64%{transform:scale(1) translateY(0)}to{transform:scale(1) translateY(0)}}@keyframes fa-fade{50%{opacity:var(--fa-fade-opacity,.4)}}@keyframes fa-beat-fade{0%,to{opacity:var(--fa-beat-fade-opacity,.4);transform:scale(1)}50%{opacity:1;transform:scale(var(--fa-beat-fade-scale,1.125))}}@keyframes fa-flip{50%{transform:rotate3d(var(--fa-flip-x,0),var(--fa-flip-y,1),var(--fa-flip-z,0),var(--fa-flip-angle,-180deg))}}@keyframes fa-shake{0%{transform:rotate(-15deg)}4%{transform:rotate(15deg)}8%,24%{transform:rotate(-18deg)}12%,28%{transform:rotate(18deg)}16%{transform:rotate(-22deg)}20%{transform:rotate(22deg)}32%{transform:rotate(-12deg)}36%{transform:rotate(12deg)}40%,to{transform:rotate(0deg)}}@keyframes fa-spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.fa-rotate-90{transform:rotate(90deg)}.fa-rotate-180{transform:rotate(180deg)}.fa-rotate-270{transform:rotate(270deg)}.fa-flip-horizontal{transform:scaleX(-1)}.fa-flip-vertical{transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{transform:scale(-1)}.fa-rotate-by{transform:rotate(var(--fa-rotate-angle,0))}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%;z-index:var(--fa-stack-z-index,auto)}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:var(--fa-inverse,#fff)} - -.fa-0{--fa:"\30"}.fa-1{--fa:"\31"}.fa-2{--fa:"\32"}.fa-3{--fa:"\33"}.fa-4{--fa:"\34"}.fa-5{--fa:"\35"}.fa-6{--fa:"\36"}.fa-7{--fa:"\37"}.fa-8{--fa:"\38"}.fa-9{--fa:"\39"}.fa-fill-drip{--fa:"\f576"}.fa-arrows-to-circle{--fa:"\e4bd"}.fa-chevron-circle-right,.fa-circle-chevron-right{--fa:"\f138"}.fa-at{--fa:"\40"}.fa-trash-alt,.fa-trash-can{--fa:"\f2ed"}.fa-text-height{--fa:"\f034"}.fa-user-times,.fa-user-xmark{--fa:"\f235"}.fa-stethoscope{--fa:"\f0f1"}.fa-comment-alt,.fa-message{--fa:"\f27a"}.fa-info{--fa:"\f129"}.fa-compress-alt,.fa-down-left-and-up-right-to-center{--fa:"\f422"}.fa-explosion{--fa:"\e4e9"}.fa-file-alt,.fa-file-lines,.fa-file-text{--fa:"\f15c"}.fa-wave-square{--fa:"\f83e"}.fa-ring{--fa:"\f70b"}.fa-building-un{--fa:"\e4d9"}.fa-dice-three{--fa:"\f527"}.fa-calendar-alt,.fa-calendar-days{--fa:"\f073"}.fa-anchor-circle-check{--fa:"\e4aa"}.fa-building-circle-arrow-right{--fa:"\e4d1"}.fa-volleyball,.fa-volleyball-ball{--fa:"\f45f"}.fa-arrows-up-to-line{--fa:"\e4c2"}.fa-sort-desc,.fa-sort-down{--fa:"\f0dd"}.fa-circle-minus,.fa-minus-circle{--fa:"\f056"}.fa-door-open{--fa:"\f52b"}.fa-right-from-bracket,.fa-sign-out-alt{--fa:"\f2f5"}.fa-atom{--fa:"\f5d2"}.fa-soap{--fa:"\e06e"}.fa-heart-music-camera-bolt,.fa-icons{--fa:"\f86d"}.fa-microphone-alt-slash,.fa-microphone-lines-slash{--fa:"\f539"}.fa-bridge-circle-check{--fa:"\e4c9"}.fa-pump-medical{--fa:"\e06a"}.fa-fingerprint{--fa:"\f577"}.fa-hand-point-right{--fa:"\f0a4"}.fa-magnifying-glass-location,.fa-search-location{--fa:"\f689"}.fa-forward-step,.fa-step-forward{--fa:"\f051"}.fa-face-smile-beam,.fa-smile-beam{--fa:"\f5b8"}.fa-flag-checkered{--fa:"\f11e"}.fa-football,.fa-football-ball{--fa:"\f44e"}.fa-school-circle-exclamation{--fa:"\e56c"}.fa-crop{--fa:"\f125"}.fa-angle-double-down,.fa-angles-down{--fa:"\f103"}.fa-users-rectangle{--fa:"\e594"}.fa-people-roof{--fa:"\e537"}.fa-people-line{--fa:"\e534"}.fa-beer,.fa-beer-mug-empty{--fa:"\f0fc"}.fa-diagram-predecessor{--fa:"\e477"}.fa-arrow-up-long,.fa-long-arrow-up{--fa:"\f176"}.fa-burn,.fa-fire-flame-simple{--fa:"\f46a"}.fa-male,.fa-person{--fa:"\f183"}.fa-laptop{--fa:"\f109"}.fa-file-csv{--fa:"\f6dd"}.fa-menorah{--fa:"\f676"}.fa-truck-plane{--fa:"\e58f"}.fa-record-vinyl{--fa:"\f8d9"}.fa-face-grin-stars,.fa-grin-stars{--fa:"\f587"}.fa-bong{--fa:"\f55c"}.fa-pastafarianism,.fa-spaghetti-monster-flying{--fa:"\f67b"}.fa-arrow-down-up-across-line{--fa:"\e4af"}.fa-spoon,.fa-utensil-spoon{--fa:"\f2e5"}.fa-jar-wheat{--fa:"\e517"}.fa-envelopes-bulk,.fa-mail-bulk{--fa:"\f674"}.fa-file-circle-exclamation{--fa:"\e4eb"}.fa-circle-h,.fa-hospital-symbol{--fa:"\f47e"}.fa-pager{--fa:"\f815"}.fa-address-book,.fa-contact-book{--fa:"\f2b9"}.fa-strikethrough{--fa:"\f0cc"}.fa-k{--fa:"\4b"}.fa-landmark-flag{--fa:"\e51c"}.fa-pencil,.fa-pencil-alt{--fa:"\f303"}.fa-backward{--fa:"\f04a"}.fa-caret-right{--fa:"\f0da"}.fa-comments{--fa:"\f086"}.fa-file-clipboard,.fa-paste{--fa:"\f0ea"}.fa-code-pull-request{--fa:"\e13c"}.fa-clipboard-list{--fa:"\f46d"}.fa-truck-loading,.fa-truck-ramp-box{--fa:"\f4de"}.fa-user-check{--fa:"\f4fc"}.fa-vial-virus{--fa:"\e597"}.fa-sheet-plastic{--fa:"\e571"}.fa-blog{--fa:"\f781"}.fa-user-ninja{--fa:"\f504"}.fa-person-arrow-up-from-line{--fa:"\e539"}.fa-scroll-torah,.fa-torah{--fa:"\f6a0"}.fa-broom-ball,.fa-quidditch,.fa-quidditch-broom-ball{--fa:"\f458"}.fa-toggle-off{--fa:"\f204"}.fa-archive,.fa-box-archive{--fa:"\f187"}.fa-person-drowning{--fa:"\e545"}.fa-arrow-down-9-1,.fa-sort-numeric-desc,.fa-sort-numeric-down-alt{--fa:"\f886"}.fa-face-grin-tongue-squint,.fa-grin-tongue-squint{--fa:"\f58a"}.fa-spray-can{--fa:"\f5bd"}.fa-truck-monster{--fa:"\f63b"}.fa-w{--fa:"\57"}.fa-earth-africa,.fa-globe-africa{--fa:"\f57c"}.fa-rainbow{--fa:"\f75b"}.fa-circle-notch{--fa:"\f1ce"}.fa-tablet-alt,.fa-tablet-screen-button{--fa:"\f3fa"}.fa-paw{--fa:"\f1b0"}.fa-cloud{--fa:"\f0c2"}.fa-trowel-bricks{--fa:"\e58a"}.fa-face-flushed,.fa-flushed{--fa:"\f579"}.fa-hospital-user{--fa:"\f80d"}.fa-tent-arrow-left-right{--fa:"\e57f"}.fa-gavel,.fa-legal{--fa:"\f0e3"}.fa-binoculars{--fa:"\f1e5"}.fa-microphone-slash{--fa:"\f131"}.fa-box-tissue{--fa:"\e05b"}.fa-motorcycle{--fa:"\f21c"}.fa-bell-concierge,.fa-concierge-bell{--fa:"\f562"}.fa-pen-ruler,.fa-pencil-ruler{--fa:"\f5ae"}.fa-people-arrows,.fa-people-arrows-left-right{--fa:"\e068"}.fa-mars-and-venus-burst{--fa:"\e523"}.fa-caret-square-right,.fa-square-caret-right{--fa:"\f152"}.fa-cut,.fa-scissors{--fa:"\f0c4"}.fa-sun-plant-wilt{--fa:"\e57a"}.fa-toilets-portable{--fa:"\e584"}.fa-hockey-puck{--fa:"\f453"}.fa-table{--fa:"\f0ce"}.fa-magnifying-glass-arrow-right{--fa:"\e521"}.fa-digital-tachograph,.fa-tachograph-digital{--fa:"\f566"}.fa-users-slash{--fa:"\e073"}.fa-clover{--fa:"\e139"}.fa-mail-reply,.fa-reply{--fa:"\f3e5"}.fa-star-and-crescent{--fa:"\f699"}.fa-house-fire{--fa:"\e50c"}.fa-minus-square,.fa-square-minus{--fa:"\f146"}.fa-helicopter{--fa:"\f533"}.fa-compass{--fa:"\f14e"}.fa-caret-square-down,.fa-square-caret-down{--fa:"\f150"}.fa-file-circle-question{--fa:"\e4ef"}.fa-laptop-code{--fa:"\f5fc"}.fa-swatchbook{--fa:"\f5c3"}.fa-prescription-bottle{--fa:"\f485"}.fa-bars,.fa-navicon{--fa:"\f0c9"}.fa-people-group{--fa:"\e533"}.fa-hourglass-3,.fa-hourglass-end{--fa:"\f253"}.fa-heart-broken,.fa-heart-crack{--fa:"\f7a9"}.fa-external-link-square-alt,.fa-square-up-right{--fa:"\f360"}.fa-face-kiss-beam,.fa-kiss-beam{--fa:"\f597"}.fa-film{--fa:"\f008"}.fa-ruler-horizontal{--fa:"\f547"}.fa-people-robbery{--fa:"\e536"}.fa-lightbulb{--fa:"\f0eb"}.fa-caret-left{--fa:"\f0d9"}.fa-circle-exclamation,.fa-exclamation-circle{--fa:"\f06a"}.fa-school-circle-xmark{--fa:"\e56d"}.fa-arrow-right-from-bracket,.fa-sign-out{--fa:"\f08b"}.fa-chevron-circle-down,.fa-circle-chevron-down{--fa:"\f13a"}.fa-unlock-alt,.fa-unlock-keyhole{--fa:"\f13e"}.fa-cloud-showers-heavy{--fa:"\f740"}.fa-headphones-alt,.fa-headphones-simple{--fa:"\f58f"}.fa-sitemap{--fa:"\f0e8"}.fa-circle-dollar-to-slot,.fa-donate{--fa:"\f4b9"}.fa-memory{--fa:"\f538"}.fa-road-spikes{--fa:"\e568"}.fa-fire-burner{--fa:"\e4f1"}.fa-flag{--fa:"\f024"}.fa-hanukiah{--fa:"\f6e6"}.fa-feather{--fa:"\f52d"}.fa-volume-down,.fa-volume-low{--fa:"\f027"}.fa-comment-slash{--fa:"\f4b3"}.fa-cloud-sun-rain{--fa:"\f743"}.fa-compress{--fa:"\f066"}.fa-wheat-alt,.fa-wheat-awn{--fa:"\e2cd"}.fa-ankh{--fa:"\f644"}.fa-hands-holding-child{--fa:"\e4fa"}.fa-asterisk{--fa:"\2a"}.fa-check-square,.fa-square-check{--fa:"\f14a"}.fa-peseta-sign{--fa:"\e221"}.fa-header,.fa-heading{--fa:"\f1dc"}.fa-ghost{--fa:"\f6e2"}.fa-list,.fa-list-squares{--fa:"\f03a"}.fa-phone-square-alt,.fa-square-phone-flip{--fa:"\f87b"}.fa-cart-plus{--fa:"\f217"}.fa-gamepad{--fa:"\f11b"}.fa-circle-dot,.fa-dot-circle{--fa:"\f192"}.fa-dizzy,.fa-face-dizzy{--fa:"\f567"}.fa-egg{--fa:"\f7fb"}.fa-house-medical-circle-xmark{--fa:"\e513"}.fa-campground{--fa:"\f6bb"}.fa-folder-plus{--fa:"\f65e"}.fa-futbol,.fa-futbol-ball,.fa-soccer-ball{--fa:"\f1e3"}.fa-paint-brush,.fa-paintbrush{--fa:"\f1fc"}.fa-lock{--fa:"\f023"}.fa-gas-pump{--fa:"\f52f"}.fa-hot-tub,.fa-hot-tub-person{--fa:"\f593"}.fa-map-location,.fa-map-marked{--fa:"\f59f"}.fa-house-flood-water{--fa:"\e50e"}.fa-tree{--fa:"\f1bb"}.fa-bridge-lock{--fa:"\e4cc"}.fa-sack-dollar{--fa:"\f81d"}.fa-edit,.fa-pen-to-square{--fa:"\f044"}.fa-car-side{--fa:"\f5e4"}.fa-share-alt,.fa-share-nodes{--fa:"\f1e0"}.fa-heart-circle-minus{--fa:"\e4ff"}.fa-hourglass-2,.fa-hourglass-half{--fa:"\f252"}.fa-microscope{--fa:"\f610"}.fa-sink{--fa:"\e06d"}.fa-bag-shopping,.fa-shopping-bag{--fa:"\f290"}.fa-arrow-down-z-a,.fa-sort-alpha-desc,.fa-sort-alpha-down-alt{--fa:"\f881"}.fa-mitten{--fa:"\f7b5"}.fa-person-rays{--fa:"\e54d"}.fa-users{--fa:"\f0c0"}.fa-eye-slash{--fa:"\f070"}.fa-flask-vial{--fa:"\e4f3"}.fa-hand,.fa-hand-paper{--fa:"\f256"}.fa-om{--fa:"\f679"}.fa-worm{--fa:"\e599"}.fa-house-circle-xmark{--fa:"\e50b"}.fa-plug{--fa:"\f1e6"}.fa-chevron-up{--fa:"\f077"}.fa-hand-spock{--fa:"\f259"}.fa-stopwatch{--fa:"\f2f2"}.fa-face-kiss,.fa-kiss{--fa:"\f596"}.fa-bridge-circle-xmark{--fa:"\e4cb"}.fa-face-grin-tongue,.fa-grin-tongue{--fa:"\f589"}.fa-chess-bishop{--fa:"\f43a"}.fa-face-grin-wink,.fa-grin-wink{--fa:"\f58c"}.fa-deaf,.fa-deafness,.fa-ear-deaf,.fa-hard-of-hearing{--fa:"\f2a4"}.fa-road-circle-check{--fa:"\e564"}.fa-dice-five{--fa:"\f523"}.fa-rss-square,.fa-square-rss{--fa:"\f143"}.fa-land-mine-on{--fa:"\e51b"}.fa-i-cursor{--fa:"\f246"}.fa-stamp{--fa:"\f5bf"}.fa-stairs{--fa:"\e289"}.fa-i{--fa:"\49"}.fa-hryvnia,.fa-hryvnia-sign{--fa:"\f6f2"}.fa-pills{--fa:"\f484"}.fa-face-grin-wide,.fa-grin-alt{--fa:"\f581"}.fa-tooth{--fa:"\f5c9"}.fa-v{--fa:"\56"}.fa-bangladeshi-taka-sign{--fa:"\e2e6"}.fa-bicycle{--fa:"\f206"}.fa-rod-asclepius,.fa-rod-snake,.fa-staff-aesculapius,.fa-staff-snake{--fa:"\e579"}.fa-head-side-cough-slash{--fa:"\e062"}.fa-ambulance,.fa-truck-medical{--fa:"\f0f9"}.fa-wheat-awn-circle-exclamation{--fa:"\e598"}.fa-snowman{--fa:"\f7d0"}.fa-mortar-pestle{--fa:"\f5a7"}.fa-road-barrier{--fa:"\e562"}.fa-school{--fa:"\f549"}.fa-igloo{--fa:"\f7ae"}.fa-joint{--fa:"\f595"}.fa-angle-right{--fa:"\f105"}.fa-horse{--fa:"\f6f0"}.fa-q{--fa:"\51"}.fa-g{--fa:"\47"}.fa-notes-medical{--fa:"\f481"}.fa-temperature-2,.fa-temperature-half,.fa-thermometer-2,.fa-thermometer-half{--fa:"\f2c9"}.fa-dong-sign{--fa:"\e169"}.fa-capsules{--fa:"\f46b"}.fa-poo-bolt,.fa-poo-storm{--fa:"\f75a"}.fa-face-frown-open,.fa-frown-open{--fa:"\f57a"}.fa-hand-point-up{--fa:"\f0a6"}.fa-money-bill{--fa:"\f0d6"}.fa-bookmark{--fa:"\f02e"}.fa-align-justify{--fa:"\f039"}.fa-umbrella-beach{--fa:"\f5ca"}.fa-helmet-un{--fa:"\e503"}.fa-bullseye{--fa:"\f140"}.fa-bacon{--fa:"\f7e5"}.fa-hand-point-down{--fa:"\f0a7"}.fa-arrow-up-from-bracket{--fa:"\e09a"}.fa-folder,.fa-folder-blank{--fa:"\f07b"}.fa-file-medical-alt,.fa-file-waveform{--fa:"\f478"}.fa-radiation{--fa:"\f7b9"}.fa-chart-simple{--fa:"\e473"}.fa-mars-stroke{--fa:"\f229"}.fa-vial{--fa:"\f492"}.fa-dashboard,.fa-gauge,.fa-gauge-med,.fa-tachometer-alt-average{--fa:"\f624"}.fa-magic-wand-sparkles,.fa-wand-magic-sparkles{--fa:"\e2ca"}.fa-e{--fa:"\45"}.fa-pen-alt,.fa-pen-clip{--fa:"\f305"}.fa-bridge-circle-exclamation{--fa:"\e4ca"}.fa-user{--fa:"\f007"}.fa-school-circle-check{--fa:"\e56b"}.fa-dumpster{--fa:"\f793"}.fa-shuttle-van,.fa-van-shuttle{--fa:"\f5b6"}.fa-building-user{--fa:"\e4da"}.fa-caret-square-left,.fa-square-caret-left{--fa:"\f191"}.fa-highlighter{--fa:"\f591"}.fa-key{--fa:"\f084"}.fa-bullhorn{--fa:"\f0a1"}.fa-globe{--fa:"\f0ac"}.fa-synagogue{--fa:"\f69b"}.fa-person-half-dress{--fa:"\e548"}.fa-road-bridge{--fa:"\e563"}.fa-location-arrow{--fa:"\f124"}.fa-c{--fa:"\43"}.fa-tablet-button{--fa:"\f10a"}.fa-building-lock{--fa:"\e4d6"}.fa-pizza-slice{--fa:"\f818"}.fa-money-bill-wave{--fa:"\f53a"}.fa-area-chart,.fa-chart-area{--fa:"\f1fe"}.fa-house-flag{--fa:"\e50d"}.fa-person-circle-minus{--fa:"\e540"}.fa-ban,.fa-cancel{--fa:"\f05e"}.fa-camera-rotate{--fa:"\e0d8"}.fa-air-freshener,.fa-spray-can-sparkles{--fa:"\f5d0"}.fa-star{--fa:"\f005"}.fa-repeat{--fa:"\f363"}.fa-cross{--fa:"\f654"}.fa-box{--fa:"\f466"}.fa-venus-mars{--fa:"\f228"}.fa-arrow-pointer,.fa-mouse-pointer{--fa:"\f245"}.fa-expand-arrows-alt,.fa-maximize{--fa:"\f31e"}.fa-charging-station{--fa:"\f5e7"}.fa-shapes,.fa-triangle-circle-square{--fa:"\f61f"}.fa-random,.fa-shuffle{--fa:"\f074"}.fa-person-running,.fa-running{--fa:"\f70c"}.fa-mobile-retro{--fa:"\e527"}.fa-grip-lines-vertical{--fa:"\f7a5"}.fa-spider{--fa:"\f717"}.fa-hands-bound{--fa:"\e4f9"}.fa-file-invoice-dollar{--fa:"\f571"}.fa-plane-circle-exclamation{--fa:"\e556"}.fa-x-ray{--fa:"\f497"}.fa-spell-check{--fa:"\f891"}.fa-slash{--fa:"\f715"}.fa-computer-mouse,.fa-mouse{--fa:"\f8cc"}.fa-arrow-right-to-bracket,.fa-sign-in{--fa:"\f090"}.fa-shop-slash,.fa-store-alt-slash{--fa:"\e070"}.fa-server{--fa:"\f233"}.fa-virus-covid-slash{--fa:"\e4a9"}.fa-shop-lock{--fa:"\e4a5"}.fa-hourglass-1,.fa-hourglass-start{--fa:"\f251"}.fa-blender-phone{--fa:"\f6b6"}.fa-building-wheat{--fa:"\e4db"}.fa-person-breastfeeding{--fa:"\e53a"}.fa-right-to-bracket,.fa-sign-in-alt{--fa:"\f2f6"}.fa-venus{--fa:"\f221"}.fa-passport{--fa:"\f5ab"}.fa-thumb-tack-slash,.fa-thumbtack-slash{--fa:"\e68f"}.fa-heart-pulse,.fa-heartbeat{--fa:"\f21e"}.fa-people-carry,.fa-people-carry-box{--fa:"\f4ce"}.fa-temperature-high{--fa:"\f769"}.fa-microchip{--fa:"\f2db"}.fa-crown{--fa:"\f521"}.fa-weight-hanging{--fa:"\f5cd"}.fa-xmarks-lines{--fa:"\e59a"}.fa-file-prescription{--fa:"\f572"}.fa-weight,.fa-weight-scale{--fa:"\f496"}.fa-user-friends,.fa-user-group{--fa:"\f500"}.fa-arrow-up-a-z,.fa-sort-alpha-up{--fa:"\f15e"}.fa-chess-knight{--fa:"\f441"}.fa-face-laugh-squint,.fa-laugh-squint{--fa:"\f59b"}.fa-wheelchair{--fa:"\f193"}.fa-arrow-circle-up,.fa-circle-arrow-up{--fa:"\f0aa"}.fa-toggle-on{--fa:"\f205"}.fa-person-walking,.fa-walking{--fa:"\f554"}.fa-l{--fa:"\4c"}.fa-fire{--fa:"\f06d"}.fa-bed-pulse,.fa-procedures{--fa:"\f487"}.fa-shuttle-space,.fa-space-shuttle{--fa:"\f197"}.fa-face-laugh,.fa-laugh{--fa:"\f599"}.fa-folder-open{--fa:"\f07c"}.fa-heart-circle-plus{--fa:"\e500"}.fa-code-fork{--fa:"\e13b"}.fa-city{--fa:"\f64f"}.fa-microphone-alt,.fa-microphone-lines{--fa:"\f3c9"}.fa-pepper-hot{--fa:"\f816"}.fa-unlock{--fa:"\f09c"}.fa-colon-sign{--fa:"\e140"}.fa-headset{--fa:"\f590"}.fa-store-slash{--fa:"\e071"}.fa-road-circle-xmark{--fa:"\e566"}.fa-user-minus{--fa:"\f503"}.fa-mars-stroke-up,.fa-mars-stroke-v{--fa:"\f22a"}.fa-champagne-glasses,.fa-glass-cheers{--fa:"\f79f"}.fa-clipboard{--fa:"\f328"}.fa-house-circle-exclamation{--fa:"\e50a"}.fa-file-arrow-up,.fa-file-upload{--fa:"\f574"}.fa-wifi,.fa-wifi-3,.fa-wifi-strong{--fa:"\f1eb"}.fa-bath,.fa-bathtub{--fa:"\f2cd"}.fa-underline{--fa:"\f0cd"}.fa-user-edit,.fa-user-pen{--fa:"\f4ff"}.fa-signature{--fa:"\f5b7"}.fa-stroopwafel{--fa:"\f551"}.fa-bold{--fa:"\f032"}.fa-anchor-lock{--fa:"\e4ad"}.fa-building-ngo{--fa:"\e4d7"}.fa-manat-sign{--fa:"\e1d5"}.fa-not-equal{--fa:"\f53e"}.fa-border-style,.fa-border-top-left{--fa:"\f853"}.fa-map-location-dot,.fa-map-marked-alt{--fa:"\f5a0"}.fa-jedi{--fa:"\f669"}.fa-poll,.fa-square-poll-vertical{--fa:"\f681"}.fa-mug-hot{--fa:"\f7b6"}.fa-battery-car,.fa-car-battery{--fa:"\f5df"}.fa-gift{--fa:"\f06b"}.fa-dice-two{--fa:"\f528"}.fa-chess-queen{--fa:"\f445"}.fa-glasses{--fa:"\f530"}.fa-chess-board{--fa:"\f43c"}.fa-building-circle-check{--fa:"\e4d2"}.fa-person-chalkboard{--fa:"\e53d"}.fa-mars-stroke-h,.fa-mars-stroke-right{--fa:"\f22b"}.fa-hand-back-fist,.fa-hand-rock{--fa:"\f255"}.fa-caret-square-up,.fa-square-caret-up{--fa:"\f151"}.fa-cloud-showers-water{--fa:"\e4e4"}.fa-bar-chart,.fa-chart-bar{--fa:"\f080"}.fa-hands-bubbles,.fa-hands-wash{--fa:"\e05e"}.fa-less-than-equal{--fa:"\f537"}.fa-train{--fa:"\f238"}.fa-eye-low-vision,.fa-low-vision{--fa:"\f2a8"}.fa-crow{--fa:"\f520"}.fa-sailboat{--fa:"\e445"}.fa-window-restore{--fa:"\f2d2"}.fa-plus-square,.fa-square-plus{--fa:"\f0fe"}.fa-torii-gate{--fa:"\f6a1"}.fa-frog{--fa:"\f52e"}.fa-bucket{--fa:"\e4cf"}.fa-image{--fa:"\f03e"}.fa-microphone{--fa:"\f130"}.fa-cow{--fa:"\f6c8"}.fa-caret-up{--fa:"\f0d8"}.fa-screwdriver{--fa:"\f54a"}.fa-folder-closed{--fa:"\e185"}.fa-house-tsunami{--fa:"\e515"}.fa-square-nfi{--fa:"\e576"}.fa-arrow-up-from-ground-water{--fa:"\e4b5"}.fa-glass-martini-alt,.fa-martini-glass{--fa:"\f57b"}.fa-square-binary{--fa:"\e69b"}.fa-rotate-back,.fa-rotate-backward,.fa-rotate-left,.fa-undo-alt{--fa:"\f2ea"}.fa-columns,.fa-table-columns{--fa:"\f0db"}.fa-lemon{--fa:"\f094"}.fa-head-side-mask{--fa:"\e063"}.fa-handshake{--fa:"\f2b5"}.fa-gem{--fa:"\f3a5"}.fa-dolly,.fa-dolly-box{--fa:"\f472"}.fa-smoking{--fa:"\f48d"}.fa-compress-arrows-alt,.fa-minimize{--fa:"\f78c"}.fa-monument{--fa:"\f5a6"}.fa-snowplow{--fa:"\f7d2"}.fa-angle-double-right,.fa-angles-right{--fa:"\f101"}.fa-cannabis{--fa:"\f55f"}.fa-circle-play,.fa-play-circle{--fa:"\f144"}.fa-tablets{--fa:"\f490"}.fa-ethernet{--fa:"\f796"}.fa-eur,.fa-euro,.fa-euro-sign{--fa:"\f153"}.fa-chair{--fa:"\f6c0"}.fa-check-circle,.fa-circle-check{--fa:"\f058"}.fa-circle-stop,.fa-stop-circle{--fa:"\f28d"}.fa-compass-drafting,.fa-drafting-compass{--fa:"\f568"}.fa-plate-wheat{--fa:"\e55a"}.fa-icicles{--fa:"\f7ad"}.fa-person-shelter{--fa:"\e54f"}.fa-neuter{--fa:"\f22c"}.fa-id-badge{--fa:"\f2c1"}.fa-marker{--fa:"\f5a1"}.fa-face-laugh-beam,.fa-laugh-beam{--fa:"\f59a"}.fa-helicopter-symbol{--fa:"\e502"}.fa-universal-access{--fa:"\f29a"}.fa-chevron-circle-up,.fa-circle-chevron-up{--fa:"\f139"}.fa-lari-sign{--fa:"\e1c8"}.fa-volcano{--fa:"\f770"}.fa-person-walking-dashed-line-arrow-right{--fa:"\e553"}.fa-gbp,.fa-pound-sign,.fa-sterling-sign{--fa:"\f154"}.fa-viruses{--fa:"\e076"}.fa-square-person-confined{--fa:"\e577"}.fa-user-tie{--fa:"\f508"}.fa-arrow-down-long,.fa-long-arrow-down{--fa:"\f175"}.fa-tent-arrow-down-to-line{--fa:"\e57e"}.fa-certificate{--fa:"\f0a3"}.fa-mail-reply-all,.fa-reply-all{--fa:"\f122"}.fa-suitcase{--fa:"\f0f2"}.fa-person-skating,.fa-skating{--fa:"\f7c5"}.fa-filter-circle-dollar,.fa-funnel-dollar{--fa:"\f662"}.fa-camera-retro{--fa:"\f083"}.fa-arrow-circle-down,.fa-circle-arrow-down{--fa:"\f0ab"}.fa-arrow-right-to-file,.fa-file-import{--fa:"\f56f"}.fa-external-link-square,.fa-square-arrow-up-right{--fa:"\f14c"}.fa-box-open{--fa:"\f49e"}.fa-scroll{--fa:"\f70e"}.fa-spa{--fa:"\f5bb"}.fa-location-pin-lock{--fa:"\e51f"}.fa-pause{--fa:"\f04c"}.fa-hill-avalanche{--fa:"\e507"}.fa-temperature-0,.fa-temperature-empty,.fa-thermometer-0,.fa-thermometer-empty{--fa:"\f2cb"}.fa-bomb{--fa:"\f1e2"}.fa-registered{--fa:"\f25d"}.fa-address-card,.fa-contact-card,.fa-vcard{--fa:"\f2bb"}.fa-balance-scale-right,.fa-scale-unbalanced-flip{--fa:"\f516"}.fa-subscript{--fa:"\f12c"}.fa-diamond-turn-right,.fa-directions{--fa:"\f5eb"}.fa-burst{--fa:"\e4dc"}.fa-house-laptop,.fa-laptop-house{--fa:"\e066"}.fa-face-tired,.fa-tired{--fa:"\f5c8"}.fa-money-bills{--fa:"\e1f3"}.fa-smog{--fa:"\f75f"}.fa-crutch{--fa:"\f7f7"}.fa-cloud-arrow-up,.fa-cloud-upload,.fa-cloud-upload-alt{--fa:"\f0ee"}.fa-palette{--fa:"\f53f"}.fa-arrows-turn-right{--fa:"\e4c0"}.fa-vest{--fa:"\e085"}.fa-ferry{--fa:"\e4ea"}.fa-arrows-down-to-people{--fa:"\e4b9"}.fa-seedling,.fa-sprout{--fa:"\f4d8"}.fa-arrows-alt-h,.fa-left-right{--fa:"\f337"}.fa-boxes-packing{--fa:"\e4c7"}.fa-arrow-circle-left,.fa-circle-arrow-left{--fa:"\f0a8"}.fa-group-arrows-rotate{--fa:"\e4f6"}.fa-bowl-food{--fa:"\e4c6"}.fa-candy-cane{--fa:"\f786"}.fa-arrow-down-wide-short,.fa-sort-amount-asc,.fa-sort-amount-down{--fa:"\f160"}.fa-cloud-bolt,.fa-thunderstorm{--fa:"\f76c"}.fa-remove-format,.fa-text-slash{--fa:"\f87d"}.fa-face-smile-wink,.fa-smile-wink{--fa:"\f4da"}.fa-file-word{--fa:"\f1c2"}.fa-file-powerpoint{--fa:"\f1c4"}.fa-arrows-h,.fa-arrows-left-right{--fa:"\f07e"}.fa-house-lock{--fa:"\e510"}.fa-cloud-arrow-down,.fa-cloud-download,.fa-cloud-download-alt{--fa:"\f0ed"}.fa-children{--fa:"\e4e1"}.fa-blackboard,.fa-chalkboard{--fa:"\f51b"}.fa-user-alt-slash,.fa-user-large-slash{--fa:"\f4fa"}.fa-envelope-open{--fa:"\f2b6"}.fa-handshake-alt-slash,.fa-handshake-simple-slash{--fa:"\e05f"}.fa-mattress-pillow{--fa:"\e525"}.fa-guarani-sign{--fa:"\e19a"}.fa-arrows-rotate,.fa-refresh,.fa-sync{--fa:"\f021"}.fa-fire-extinguisher{--fa:"\f134"}.fa-cruzeiro-sign{--fa:"\e152"}.fa-greater-than-equal{--fa:"\f532"}.fa-shield-alt,.fa-shield-halved{--fa:"\f3ed"}.fa-atlas,.fa-book-atlas{--fa:"\f558"}.fa-virus{--fa:"\e074"}.fa-envelope-circle-check{--fa:"\e4e8"}.fa-layer-group{--fa:"\f5fd"}.fa-arrows-to-dot{--fa:"\e4be"}.fa-archway{--fa:"\f557"}.fa-heart-circle-check{--fa:"\e4fd"}.fa-house-chimney-crack,.fa-house-damage{--fa:"\f6f1"}.fa-file-archive,.fa-file-zipper{--fa:"\f1c6"}.fa-square{--fa:"\f0c8"}.fa-glass-martini,.fa-martini-glass-empty{--fa:"\f000"}.fa-couch{--fa:"\f4b8"}.fa-cedi-sign{--fa:"\e0df"}.fa-italic{--fa:"\f033"}.fa-table-cells-column-lock{--fa:"\e678"}.fa-church{--fa:"\f51d"}.fa-comments-dollar{--fa:"\f653"}.fa-democrat{--fa:"\f747"}.fa-z{--fa:"\5a"}.fa-person-skiing,.fa-skiing{--fa:"\f7c9"}.fa-road-lock{--fa:"\e567"}.fa-a{--fa:"\41"}.fa-temperature-arrow-down,.fa-temperature-down{--fa:"\e03f"}.fa-feather-alt,.fa-feather-pointed{--fa:"\f56b"}.fa-p{--fa:"\50"}.fa-snowflake{--fa:"\f2dc"}.fa-newspaper{--fa:"\f1ea"}.fa-ad,.fa-rectangle-ad{--fa:"\f641"}.fa-arrow-circle-right,.fa-circle-arrow-right{--fa:"\f0a9"}.fa-filter-circle-xmark{--fa:"\e17b"}.fa-locust{--fa:"\e520"}.fa-sort,.fa-unsorted{--fa:"\f0dc"}.fa-list-1-2,.fa-list-numeric,.fa-list-ol{--fa:"\f0cb"}.fa-person-dress-burst{--fa:"\e544"}.fa-money-check-alt,.fa-money-check-dollar{--fa:"\f53d"}.fa-vector-square{--fa:"\f5cb"}.fa-bread-slice{--fa:"\f7ec"}.fa-language{--fa:"\f1ab"}.fa-face-kiss-wink-heart,.fa-kiss-wink-heart{--fa:"\f598"}.fa-filter{--fa:"\f0b0"}.fa-question{--fa:"\3f"}.fa-file-signature{--fa:"\f573"}.fa-arrows-alt,.fa-up-down-left-right{--fa:"\f0b2"}.fa-house-chimney-user{--fa:"\e065"}.fa-hand-holding-heart{--fa:"\f4be"}.fa-puzzle-piece{--fa:"\f12e"}.fa-money-check{--fa:"\f53c"}.fa-star-half-alt,.fa-star-half-stroke{--fa:"\f5c0"}.fa-code{--fa:"\f121"}.fa-glass-whiskey,.fa-whiskey-glass{--fa:"\f7a0"}.fa-building-circle-exclamation{--fa:"\e4d3"}.fa-magnifying-glass-chart{--fa:"\e522"}.fa-arrow-up-right-from-square,.fa-external-link{--fa:"\f08e"}.fa-cubes-stacked{--fa:"\e4e6"}.fa-krw,.fa-won,.fa-won-sign{--fa:"\f159"}.fa-virus-covid{--fa:"\e4a8"}.fa-austral-sign{--fa:"\e0a9"}.fa-f{--fa:"\46"}.fa-leaf{--fa:"\f06c"}.fa-road{--fa:"\f018"}.fa-cab,.fa-taxi{--fa:"\f1ba"}.fa-person-circle-plus{--fa:"\e541"}.fa-chart-pie,.fa-pie-chart{--fa:"\f200"}.fa-bolt-lightning{--fa:"\e0b7"}.fa-sack-xmark{--fa:"\e56a"}.fa-file-excel{--fa:"\f1c3"}.fa-file-contract{--fa:"\f56c"}.fa-fish-fins{--fa:"\e4f2"}.fa-building-flag{--fa:"\e4d5"}.fa-face-grin-beam,.fa-grin-beam{--fa:"\f582"}.fa-object-ungroup{--fa:"\f248"}.fa-poop{--fa:"\f619"}.fa-location-pin,.fa-map-marker{--fa:"\f041"}.fa-kaaba{--fa:"\f66b"}.fa-toilet-paper{--fa:"\f71e"}.fa-hard-hat,.fa-hat-hard,.fa-helmet-safety{--fa:"\f807"}.fa-eject{--fa:"\f052"}.fa-arrow-alt-circle-right,.fa-circle-right{--fa:"\f35a"}.fa-plane-circle-check{--fa:"\e555"}.fa-face-rolling-eyes,.fa-meh-rolling-eyes{--fa:"\f5a5"}.fa-object-group{--fa:"\f247"}.fa-chart-line,.fa-line-chart{--fa:"\f201"}.fa-mask-ventilator{--fa:"\e524"}.fa-arrow-right{--fa:"\f061"}.fa-map-signs,.fa-signs-post{--fa:"\f277"}.fa-cash-register{--fa:"\f788"}.fa-person-circle-question{--fa:"\e542"}.fa-h{--fa:"\48"}.fa-tarp{--fa:"\e57b"}.fa-screwdriver-wrench,.fa-tools{--fa:"\f7d9"}.fa-arrows-to-eye{--fa:"\e4bf"}.fa-plug-circle-bolt{--fa:"\e55b"}.fa-heart{--fa:"\f004"}.fa-mars-and-venus{--fa:"\f224"}.fa-home-user,.fa-house-user{--fa:"\e1b0"}.fa-dumpster-fire{--fa:"\f794"}.fa-house-crack{--fa:"\e3b1"}.fa-cocktail,.fa-martini-glass-citrus{--fa:"\f561"}.fa-face-surprise,.fa-surprise{--fa:"\f5c2"}.fa-bottle-water{--fa:"\e4c5"}.fa-circle-pause,.fa-pause-circle{--fa:"\f28b"}.fa-toilet-paper-slash{--fa:"\e072"}.fa-apple-alt,.fa-apple-whole{--fa:"\f5d1"}.fa-kitchen-set{--fa:"\e51a"}.fa-r{--fa:"\52"}.fa-temperature-1,.fa-temperature-quarter,.fa-thermometer-1,.fa-thermometer-quarter{--fa:"\f2ca"}.fa-cube{--fa:"\f1b2"}.fa-bitcoin-sign{--fa:"\e0b4"}.fa-shield-dog{--fa:"\e573"}.fa-solar-panel{--fa:"\f5ba"}.fa-lock-open{--fa:"\f3c1"}.fa-elevator{--fa:"\e16d"}.fa-money-bill-transfer{--fa:"\e528"}.fa-money-bill-trend-up{--fa:"\e529"}.fa-house-flood-water-circle-arrow-right{--fa:"\e50f"}.fa-poll-h,.fa-square-poll-horizontal{--fa:"\f682"}.fa-circle{--fa:"\f111"}.fa-backward-fast,.fa-fast-backward{--fa:"\f049"}.fa-recycle{--fa:"\f1b8"}.fa-user-astronaut{--fa:"\f4fb"}.fa-plane-slash{--fa:"\e069"}.fa-trademark{--fa:"\f25c"}.fa-basketball,.fa-basketball-ball{--fa:"\f434"}.fa-satellite-dish{--fa:"\f7c0"}.fa-arrow-alt-circle-up,.fa-circle-up{--fa:"\f35b"}.fa-mobile-alt,.fa-mobile-screen-button{--fa:"\f3cd"}.fa-volume-high,.fa-volume-up{--fa:"\f028"}.fa-users-rays{--fa:"\e593"}.fa-wallet{--fa:"\f555"}.fa-clipboard-check{--fa:"\f46c"}.fa-file-audio{--fa:"\f1c7"}.fa-burger,.fa-hamburger{--fa:"\f805"}.fa-wrench{--fa:"\f0ad"}.fa-bugs{--fa:"\e4d0"}.fa-rupee,.fa-rupee-sign{--fa:"\f156"}.fa-file-image{--fa:"\f1c5"}.fa-circle-question,.fa-question-circle{--fa:"\f059"}.fa-plane-departure{--fa:"\f5b0"}.fa-handshake-slash{--fa:"\e060"}.fa-book-bookmark{--fa:"\e0bb"}.fa-code-branch{--fa:"\f126"}.fa-hat-cowboy{--fa:"\f8c0"}.fa-bridge{--fa:"\e4c8"}.fa-phone-alt,.fa-phone-flip{--fa:"\f879"}.fa-truck-front{--fa:"\e2b7"}.fa-cat{--fa:"\f6be"}.fa-anchor-circle-exclamation{--fa:"\e4ab"}.fa-truck-field{--fa:"\e58d"}.fa-route{--fa:"\f4d7"}.fa-clipboard-question{--fa:"\e4e3"}.fa-panorama{--fa:"\e209"}.fa-comment-medical{--fa:"\f7f5"}.fa-teeth-open{--fa:"\f62f"}.fa-file-circle-minus{--fa:"\e4ed"}.fa-tags{--fa:"\f02c"}.fa-wine-glass{--fa:"\f4e3"}.fa-fast-forward,.fa-forward-fast{--fa:"\f050"}.fa-face-meh-blank,.fa-meh-blank{--fa:"\f5a4"}.fa-parking,.fa-square-parking{--fa:"\f540"}.fa-house-signal{--fa:"\e012"}.fa-bars-progress,.fa-tasks-alt{--fa:"\f828"}.fa-faucet-drip{--fa:"\e006"}.fa-cart-flatbed,.fa-dolly-flatbed{--fa:"\f474"}.fa-ban-smoking,.fa-smoking-ban{--fa:"\f54d"}.fa-terminal{--fa:"\f120"}.fa-mobile-button{--fa:"\f10b"}.fa-house-medical-flag{--fa:"\e514"}.fa-basket-shopping,.fa-shopping-basket{--fa:"\f291"}.fa-tape{--fa:"\f4db"}.fa-bus-alt,.fa-bus-simple{--fa:"\f55e"}.fa-eye{--fa:"\f06e"}.fa-face-sad-cry,.fa-sad-cry{--fa:"\f5b3"}.fa-audio-description{--fa:"\f29e"}.fa-person-military-to-person{--fa:"\e54c"}.fa-file-shield{--fa:"\e4f0"}.fa-user-slash{--fa:"\f506"}.fa-pen{--fa:"\f304"}.fa-tower-observation{--fa:"\e586"}.fa-file-code{--fa:"\f1c9"}.fa-signal,.fa-signal-5,.fa-signal-perfect{--fa:"\f012"}.fa-bus{--fa:"\f207"}.fa-heart-circle-xmark{--fa:"\e501"}.fa-home-lg,.fa-house-chimney{--fa:"\e3af"}.fa-window-maximize{--fa:"\f2d0"}.fa-face-frown,.fa-frown{--fa:"\f119"}.fa-prescription{--fa:"\f5b1"}.fa-shop,.fa-store-alt{--fa:"\f54f"}.fa-floppy-disk,.fa-save{--fa:"\f0c7"}.fa-vihara{--fa:"\f6a7"}.fa-balance-scale-left,.fa-scale-unbalanced{--fa:"\f515"}.fa-sort-asc,.fa-sort-up{--fa:"\f0de"}.fa-comment-dots,.fa-commenting{--fa:"\f4ad"}.fa-plant-wilt{--fa:"\e5aa"}.fa-diamond{--fa:"\f219"}.fa-face-grin-squint,.fa-grin-squint{--fa:"\f585"}.fa-hand-holding-dollar,.fa-hand-holding-usd{--fa:"\f4c0"}.fa-chart-diagram{--fa:"\e695"}.fa-bacterium{--fa:"\e05a"}.fa-hand-pointer{--fa:"\f25a"}.fa-drum-steelpan{--fa:"\f56a"}.fa-hand-scissors{--fa:"\f257"}.fa-hands-praying,.fa-praying-hands{--fa:"\f684"}.fa-arrow-right-rotate,.fa-arrow-rotate-forward,.fa-arrow-rotate-right,.fa-redo{--fa:"\f01e"}.fa-biohazard{--fa:"\f780"}.fa-location,.fa-location-crosshairs{--fa:"\f601"}.fa-mars-double{--fa:"\f227"}.fa-child-dress{--fa:"\e59c"}.fa-users-between-lines{--fa:"\e591"}.fa-lungs-virus{--fa:"\e067"}.fa-face-grin-tears,.fa-grin-tears{--fa:"\f588"}.fa-phone{--fa:"\f095"}.fa-calendar-times,.fa-calendar-xmark{--fa:"\f273"}.fa-child-reaching{--fa:"\e59d"}.fa-head-side-virus{--fa:"\e064"}.fa-user-cog,.fa-user-gear{--fa:"\f4fe"}.fa-arrow-up-1-9,.fa-sort-numeric-up{--fa:"\f163"}.fa-door-closed{--fa:"\f52a"}.fa-shield-virus{--fa:"\e06c"}.fa-dice-six{--fa:"\f526"}.fa-mosquito-net{--fa:"\e52c"}.fa-file-fragment{--fa:"\e697"}.fa-bridge-water{--fa:"\e4ce"}.fa-person-booth{--fa:"\f756"}.fa-text-width{--fa:"\f035"}.fa-hat-wizard{--fa:"\f6e8"}.fa-pen-fancy{--fa:"\f5ac"}.fa-digging,.fa-person-digging{--fa:"\f85e"}.fa-trash{--fa:"\f1f8"}.fa-gauge-simple,.fa-gauge-simple-med,.fa-tachometer-average{--fa:"\f629"}.fa-book-medical{--fa:"\f7e6"}.fa-poo{--fa:"\f2fe"}.fa-quote-right,.fa-quote-right-alt{--fa:"\f10e"}.fa-shirt,.fa-t-shirt,.fa-tshirt{--fa:"\f553"}.fa-cubes{--fa:"\f1b3"}.fa-divide{--fa:"\f529"}.fa-tenge,.fa-tenge-sign{--fa:"\f7d7"}.fa-headphones{--fa:"\f025"}.fa-hands-holding{--fa:"\f4c2"}.fa-hands-clapping{--fa:"\e1a8"}.fa-republican{--fa:"\f75e"}.fa-arrow-left{--fa:"\f060"}.fa-person-circle-xmark{--fa:"\e543"}.fa-ruler{--fa:"\f545"}.fa-align-left{--fa:"\f036"}.fa-dice-d6{--fa:"\f6d1"}.fa-restroom{--fa:"\f7bd"}.fa-j{--fa:"\4a"}.fa-users-viewfinder{--fa:"\e595"}.fa-file-video{--fa:"\f1c8"}.fa-external-link-alt,.fa-up-right-from-square{--fa:"\f35d"}.fa-table-cells,.fa-th{--fa:"\f00a"}.fa-file-pdf{--fa:"\f1c1"}.fa-bible,.fa-book-bible{--fa:"\f647"}.fa-o{--fa:"\4f"}.fa-medkit,.fa-suitcase-medical{--fa:"\f0fa"}.fa-user-secret{--fa:"\f21b"}.fa-otter{--fa:"\f700"}.fa-female,.fa-person-dress{--fa:"\f182"}.fa-comment-dollar{--fa:"\f651"}.fa-briefcase-clock,.fa-business-time{--fa:"\f64a"}.fa-table-cells-large,.fa-th-large{--fa:"\f009"}.fa-book-tanakh,.fa-tanakh{--fa:"\f827"}.fa-phone-volume,.fa-volume-control-phone{--fa:"\f2a0"}.fa-hat-cowboy-side{--fa:"\f8c1"}.fa-clipboard-user{--fa:"\f7f3"}.fa-child{--fa:"\f1ae"}.fa-lira-sign{--fa:"\f195"}.fa-satellite{--fa:"\f7bf"}.fa-plane-lock{--fa:"\e558"}.fa-tag{--fa:"\f02b"}.fa-comment{--fa:"\f075"}.fa-birthday-cake,.fa-cake,.fa-cake-candles{--fa:"\f1fd"}.fa-envelope{--fa:"\f0e0"}.fa-angle-double-up,.fa-angles-up{--fa:"\f102"}.fa-paperclip{--fa:"\f0c6"}.fa-arrow-right-to-city{--fa:"\e4b3"}.fa-ribbon{--fa:"\f4d6"}.fa-lungs{--fa:"\f604"}.fa-arrow-up-9-1,.fa-sort-numeric-up-alt{--fa:"\f887"}.fa-litecoin-sign{--fa:"\e1d3"}.fa-border-none{--fa:"\f850"}.fa-circle-nodes{--fa:"\e4e2"}.fa-parachute-box{--fa:"\f4cd"}.fa-indent{--fa:"\f03c"}.fa-truck-field-un{--fa:"\e58e"}.fa-hourglass,.fa-hourglass-empty{--fa:"\f254"}.fa-mountain{--fa:"\f6fc"}.fa-user-doctor,.fa-user-md{--fa:"\f0f0"}.fa-circle-info,.fa-info-circle{--fa:"\f05a"}.fa-cloud-meatball{--fa:"\f73b"}.fa-camera,.fa-camera-alt{--fa:"\f030"}.fa-square-virus{--fa:"\e578"}.fa-meteor{--fa:"\f753"}.fa-car-on{--fa:"\e4dd"}.fa-sleigh{--fa:"\f7cc"}.fa-arrow-down-1-9,.fa-sort-numeric-asc,.fa-sort-numeric-down{--fa:"\f162"}.fa-hand-holding-droplet,.fa-hand-holding-water{--fa:"\f4c1"}.fa-water{--fa:"\f773"}.fa-calendar-check{--fa:"\f274"}.fa-braille{--fa:"\f2a1"}.fa-prescription-bottle-alt,.fa-prescription-bottle-medical{--fa:"\f486"}.fa-landmark{--fa:"\f66f"}.fa-truck{--fa:"\f0d1"}.fa-crosshairs{--fa:"\f05b"}.fa-person-cane{--fa:"\e53c"}.fa-tent{--fa:"\e57d"}.fa-vest-patches{--fa:"\e086"}.fa-check-double{--fa:"\f560"}.fa-arrow-down-a-z,.fa-sort-alpha-asc,.fa-sort-alpha-down{--fa:"\f15d"}.fa-money-bill-wheat{--fa:"\e52a"}.fa-cookie{--fa:"\f563"}.fa-arrow-left-rotate,.fa-arrow-rotate-back,.fa-arrow-rotate-backward,.fa-arrow-rotate-left,.fa-undo{--fa:"\f0e2"}.fa-hard-drive,.fa-hdd{--fa:"\f0a0"}.fa-face-grin-squint-tears,.fa-grin-squint-tears{--fa:"\f586"}.fa-dumbbell{--fa:"\f44b"}.fa-list-alt,.fa-rectangle-list{--fa:"\f022"}.fa-tarp-droplet{--fa:"\e57c"}.fa-house-medical-circle-check{--fa:"\e511"}.fa-person-skiing-nordic,.fa-skiing-nordic{--fa:"\f7ca"}.fa-calendar-plus{--fa:"\f271"}.fa-plane-arrival{--fa:"\f5af"}.fa-arrow-alt-circle-left,.fa-circle-left{--fa:"\f359"}.fa-subway,.fa-train-subway{--fa:"\f239"}.fa-chart-gantt{--fa:"\e0e4"}.fa-indian-rupee,.fa-indian-rupee-sign,.fa-inr{--fa:"\e1bc"}.fa-crop-alt,.fa-crop-simple{--fa:"\f565"}.fa-money-bill-1,.fa-money-bill-alt{--fa:"\f3d1"}.fa-left-long,.fa-long-arrow-alt-left{--fa:"\f30a"}.fa-dna{--fa:"\f471"}.fa-virus-slash{--fa:"\e075"}.fa-minus,.fa-subtract{--fa:"\f068"}.fa-chess{--fa:"\f439"}.fa-arrow-left-long,.fa-long-arrow-left{--fa:"\f177"}.fa-plug-circle-check{--fa:"\e55c"}.fa-street-view{--fa:"\f21d"}.fa-franc-sign{--fa:"\e18f"}.fa-volume-off{--fa:"\f026"}.fa-american-sign-language-interpreting,.fa-asl-interpreting,.fa-hands-american-sign-language-interpreting,.fa-hands-asl-interpreting{--fa:"\f2a3"}.fa-cog,.fa-gear{--fa:"\f013"}.fa-droplet-slash,.fa-tint-slash{--fa:"\f5c7"}.fa-mosque{--fa:"\f678"}.fa-mosquito{--fa:"\e52b"}.fa-star-of-david{--fa:"\f69a"}.fa-person-military-rifle{--fa:"\e54b"}.fa-cart-shopping,.fa-shopping-cart{--fa:"\f07a"}.fa-vials{--fa:"\f493"}.fa-plug-circle-plus{--fa:"\e55f"}.fa-place-of-worship{--fa:"\f67f"}.fa-grip-vertical{--fa:"\f58e"}.fa-hexagon-nodes{--fa:"\e699"}.fa-arrow-turn-up,.fa-level-up{--fa:"\f148"}.fa-u{--fa:"\55"}.fa-square-root-alt,.fa-square-root-variable{--fa:"\f698"}.fa-clock,.fa-clock-four{--fa:"\f017"}.fa-backward-step,.fa-step-backward{--fa:"\f048"}.fa-pallet{--fa:"\f482"}.fa-faucet{--fa:"\e005"}.fa-baseball-bat-ball{--fa:"\f432"}.fa-s{--fa:"\53"}.fa-timeline{--fa:"\e29c"}.fa-keyboard{--fa:"\f11c"}.fa-caret-down{--fa:"\f0d7"}.fa-clinic-medical,.fa-house-chimney-medical{--fa:"\f7f2"}.fa-temperature-3,.fa-temperature-three-quarters,.fa-thermometer-3,.fa-thermometer-three-quarters{--fa:"\f2c8"}.fa-mobile-android-alt,.fa-mobile-screen{--fa:"\f3cf"}.fa-plane-up{--fa:"\e22d"}.fa-piggy-bank{--fa:"\f4d3"}.fa-battery-3,.fa-battery-half{--fa:"\f242"}.fa-mountain-city{--fa:"\e52e"}.fa-coins{--fa:"\f51e"}.fa-khanda{--fa:"\f66d"}.fa-sliders,.fa-sliders-h{--fa:"\f1de"}.fa-folder-tree{--fa:"\f802"}.fa-network-wired{--fa:"\f6ff"}.fa-map-pin{--fa:"\f276"}.fa-hamsa{--fa:"\f665"}.fa-cent-sign{--fa:"\e3f5"}.fa-flask{--fa:"\f0c3"}.fa-person-pregnant{--fa:"\e31e"}.fa-wand-sparkles{--fa:"\f72b"}.fa-ellipsis-v,.fa-ellipsis-vertical{--fa:"\f142"}.fa-ticket{--fa:"\f145"}.fa-power-off{--fa:"\f011"}.fa-long-arrow-alt-right,.fa-right-long{--fa:"\f30b"}.fa-flag-usa{--fa:"\f74d"}.fa-laptop-file{--fa:"\e51d"}.fa-teletype,.fa-tty{--fa:"\f1e4"}.fa-diagram-next{--fa:"\e476"}.fa-person-rifle{--fa:"\e54e"}.fa-house-medical-circle-exclamation{--fa:"\e512"}.fa-closed-captioning{--fa:"\f20a"}.fa-hiking,.fa-person-hiking{--fa:"\f6ec"}.fa-venus-double{--fa:"\f226"}.fa-images{--fa:"\f302"}.fa-calculator{--fa:"\f1ec"}.fa-people-pulling{--fa:"\e535"}.fa-n{--fa:"\4e"}.fa-cable-car,.fa-tram{--fa:"\f7da"}.fa-cloud-rain{--fa:"\f73d"}.fa-building-circle-xmark{--fa:"\e4d4"}.fa-ship{--fa:"\f21a"}.fa-arrows-down-to-line{--fa:"\e4b8"}.fa-download{--fa:"\f019"}.fa-face-grin,.fa-grin{--fa:"\f580"}.fa-backspace,.fa-delete-left{--fa:"\f55a"}.fa-eye-dropper,.fa-eye-dropper-empty,.fa-eyedropper{--fa:"\f1fb"}.fa-file-circle-check{--fa:"\e5a0"}.fa-forward{--fa:"\f04e"}.fa-mobile,.fa-mobile-android,.fa-mobile-phone{--fa:"\f3ce"}.fa-face-meh,.fa-meh{--fa:"\f11a"}.fa-align-center{--fa:"\f037"}.fa-book-dead,.fa-book-skull{--fa:"\f6b7"}.fa-drivers-license,.fa-id-card{--fa:"\f2c2"}.fa-dedent,.fa-outdent{--fa:"\f03b"}.fa-heart-circle-exclamation{--fa:"\e4fe"}.fa-home,.fa-home-alt,.fa-home-lg-alt,.fa-house{--fa:"\f015"}.fa-calendar-week{--fa:"\f784"}.fa-laptop-medical{--fa:"\f812"}.fa-b{--fa:"\42"}.fa-file-medical{--fa:"\f477"}.fa-dice-one{--fa:"\f525"}.fa-kiwi-bird{--fa:"\f535"}.fa-arrow-right-arrow-left,.fa-exchange{--fa:"\f0ec"}.fa-redo-alt,.fa-rotate-forward,.fa-rotate-right{--fa:"\f2f9"}.fa-cutlery,.fa-utensils{--fa:"\f2e7"}.fa-arrow-up-wide-short,.fa-sort-amount-up{--fa:"\f161"}.fa-mill-sign{--fa:"\e1ed"}.fa-bowl-rice{--fa:"\e2eb"}.fa-skull{--fa:"\f54c"}.fa-broadcast-tower,.fa-tower-broadcast{--fa:"\f519"}.fa-truck-pickup{--fa:"\f63c"}.fa-long-arrow-alt-up,.fa-up-long{--fa:"\f30c"}.fa-stop{--fa:"\f04d"}.fa-code-merge{--fa:"\f387"}.fa-upload{--fa:"\f093"}.fa-hurricane{--fa:"\f751"}.fa-mound{--fa:"\e52d"}.fa-toilet-portable{--fa:"\e583"}.fa-compact-disc{--fa:"\f51f"}.fa-file-arrow-down,.fa-file-download{--fa:"\f56d"}.fa-caravan{--fa:"\f8ff"}.fa-shield-cat{--fa:"\e572"}.fa-bolt,.fa-zap{--fa:"\f0e7"}.fa-glass-water{--fa:"\e4f4"}.fa-oil-well{--fa:"\e532"}.fa-vault{--fa:"\e2c5"}.fa-mars{--fa:"\f222"}.fa-toilet{--fa:"\f7d8"}.fa-plane-circle-xmark{--fa:"\e557"}.fa-cny,.fa-jpy,.fa-rmb,.fa-yen,.fa-yen-sign{--fa:"\f157"}.fa-rouble,.fa-rub,.fa-ruble,.fa-ruble-sign{--fa:"\f158"}.fa-sun{--fa:"\f185"}.fa-guitar{--fa:"\f7a6"}.fa-face-laugh-wink,.fa-laugh-wink{--fa:"\f59c"}.fa-horse-head{--fa:"\f7ab"}.fa-bore-hole{--fa:"\e4c3"}.fa-industry{--fa:"\f275"}.fa-arrow-alt-circle-down,.fa-circle-down{--fa:"\f358"}.fa-arrows-turn-to-dots{--fa:"\e4c1"}.fa-florin-sign{--fa:"\e184"}.fa-arrow-down-short-wide,.fa-sort-amount-desc,.fa-sort-amount-down-alt{--fa:"\f884"}.fa-less-than{--fa:"\3c"}.fa-angle-down{--fa:"\f107"}.fa-car-tunnel{--fa:"\e4de"}.fa-head-side-cough{--fa:"\e061"}.fa-grip-lines{--fa:"\f7a4"}.fa-thumbs-down{--fa:"\f165"}.fa-user-lock{--fa:"\f502"}.fa-arrow-right-long,.fa-long-arrow-right{--fa:"\f178"}.fa-anchor-circle-xmark{--fa:"\e4ac"}.fa-ellipsis,.fa-ellipsis-h{--fa:"\f141"}.fa-chess-pawn{--fa:"\f443"}.fa-first-aid,.fa-kit-medical{--fa:"\f479"}.fa-person-through-window{--fa:"\e5a9"}.fa-toolbox{--fa:"\f552"}.fa-hands-holding-circle{--fa:"\e4fb"}.fa-bug{--fa:"\f188"}.fa-credit-card,.fa-credit-card-alt{--fa:"\f09d"}.fa-automobile,.fa-car{--fa:"\f1b9"}.fa-hand-holding-hand{--fa:"\e4f7"}.fa-book-open-reader,.fa-book-reader{--fa:"\f5da"}.fa-mountain-sun{--fa:"\e52f"}.fa-arrows-left-right-to-line{--fa:"\e4ba"}.fa-dice-d20{--fa:"\f6cf"}.fa-truck-droplet{--fa:"\e58c"}.fa-file-circle-xmark{--fa:"\e5a1"}.fa-temperature-arrow-up,.fa-temperature-up{--fa:"\e040"}.fa-medal{--fa:"\f5a2"}.fa-bed{--fa:"\f236"}.fa-h-square,.fa-square-h{--fa:"\f0fd"}.fa-podcast{--fa:"\f2ce"}.fa-temperature-4,.fa-temperature-full,.fa-thermometer-4,.fa-thermometer-full{--fa:"\f2c7"}.fa-bell{--fa:"\f0f3"}.fa-superscript{--fa:"\f12b"}.fa-plug-circle-xmark{--fa:"\e560"}.fa-star-of-life{--fa:"\f621"}.fa-phone-slash{--fa:"\f3dd"}.fa-paint-roller{--fa:"\f5aa"}.fa-hands-helping,.fa-handshake-angle{--fa:"\f4c4"}.fa-location-dot,.fa-map-marker-alt{--fa:"\f3c5"}.fa-file{--fa:"\f15b"}.fa-greater-than{--fa:"\3e"}.fa-person-swimming,.fa-swimmer{--fa:"\f5c4"}.fa-arrow-down{--fa:"\f063"}.fa-droplet,.fa-tint{--fa:"\f043"}.fa-eraser{--fa:"\f12d"}.fa-earth,.fa-earth-america,.fa-earth-americas,.fa-globe-americas{--fa:"\f57d"}.fa-person-burst{--fa:"\e53b"}.fa-dove{--fa:"\f4ba"}.fa-battery-0,.fa-battery-empty{--fa:"\f244"}.fa-socks{--fa:"\f696"}.fa-inbox{--fa:"\f01c"}.fa-section{--fa:"\e447"}.fa-gauge-high,.fa-tachometer-alt,.fa-tachometer-alt-fast{--fa:"\f625"}.fa-envelope-open-text{--fa:"\f658"}.fa-hospital,.fa-hospital-alt,.fa-hospital-wide{--fa:"\f0f8"}.fa-wine-bottle{--fa:"\f72f"}.fa-chess-rook{--fa:"\f447"}.fa-bars-staggered,.fa-reorder,.fa-stream{--fa:"\f550"}.fa-dharmachakra{--fa:"\f655"}.fa-hotdog{--fa:"\f80f"}.fa-blind,.fa-person-walking-with-cane{--fa:"\f29d"}.fa-drum{--fa:"\f569"}.fa-ice-cream{--fa:"\f810"}.fa-heart-circle-bolt{--fa:"\e4fc"}.fa-fax{--fa:"\f1ac"}.fa-paragraph{--fa:"\f1dd"}.fa-check-to-slot,.fa-vote-yea{--fa:"\f772"}.fa-star-half{--fa:"\f089"}.fa-boxes,.fa-boxes-alt,.fa-boxes-stacked{--fa:"\f468"}.fa-chain,.fa-link{--fa:"\f0c1"}.fa-assistive-listening-systems,.fa-ear-listen{--fa:"\f2a2"}.fa-tree-city{--fa:"\e587"}.fa-play{--fa:"\f04b"}.fa-font{--fa:"\f031"}.fa-table-cells-row-lock{--fa:"\e67a"}.fa-rupiah-sign{--fa:"\e23d"}.fa-magnifying-glass,.fa-search{--fa:"\f002"}.fa-ping-pong-paddle-ball,.fa-table-tennis,.fa-table-tennis-paddle-ball{--fa:"\f45d"}.fa-diagnoses,.fa-person-dots-from-line{--fa:"\f470"}.fa-trash-can-arrow-up,.fa-trash-restore-alt{--fa:"\f82a"}.fa-naira-sign{--fa:"\e1f6"}.fa-cart-arrow-down{--fa:"\f218"}.fa-walkie-talkie{--fa:"\f8ef"}.fa-file-edit,.fa-file-pen{--fa:"\f31c"}.fa-receipt{--fa:"\f543"}.fa-pen-square,.fa-pencil-square,.fa-square-pen{--fa:"\f14b"}.fa-suitcase-rolling{--fa:"\f5c1"}.fa-person-circle-exclamation{--fa:"\e53f"}.fa-chevron-down{--fa:"\f078"}.fa-battery,.fa-battery-5,.fa-battery-full{--fa:"\f240"}.fa-skull-crossbones{--fa:"\f714"}.fa-code-compare{--fa:"\e13a"}.fa-list-dots,.fa-list-ul{--fa:"\f0ca"}.fa-school-lock{--fa:"\e56f"}.fa-tower-cell{--fa:"\e585"}.fa-down-long,.fa-long-arrow-alt-down{--fa:"\f309"}.fa-ranking-star{--fa:"\e561"}.fa-chess-king{--fa:"\f43f"}.fa-person-harassing{--fa:"\e549"}.fa-brazilian-real-sign{--fa:"\e46c"}.fa-landmark-alt,.fa-landmark-dome{--fa:"\f752"}.fa-arrow-up{--fa:"\f062"}.fa-television,.fa-tv,.fa-tv-alt{--fa:"\f26c"}.fa-shrimp{--fa:"\e448"}.fa-list-check,.fa-tasks{--fa:"\f0ae"}.fa-jug-detergent{--fa:"\e519"}.fa-circle-user,.fa-user-circle{--fa:"\f2bd"}.fa-user-shield{--fa:"\f505"}.fa-wind{--fa:"\f72e"}.fa-car-burst,.fa-car-crash{--fa:"\f5e1"}.fa-y{--fa:"\59"}.fa-person-snowboarding,.fa-snowboarding{--fa:"\f7ce"}.fa-shipping-fast,.fa-truck-fast{--fa:"\f48b"}.fa-fish{--fa:"\f578"}.fa-user-graduate{--fa:"\f501"}.fa-adjust,.fa-circle-half-stroke{--fa:"\f042"}.fa-clapperboard{--fa:"\e131"}.fa-circle-radiation,.fa-radiation-alt{--fa:"\f7ba"}.fa-baseball,.fa-baseball-ball{--fa:"\f433"}.fa-jet-fighter-up{--fa:"\e518"}.fa-diagram-project,.fa-project-diagram{--fa:"\f542"}.fa-copy{--fa:"\f0c5"}.fa-volume-mute,.fa-volume-times,.fa-volume-xmark{--fa:"\f6a9"}.fa-hand-sparkles{--fa:"\e05d"}.fa-grip,.fa-grip-horizontal{--fa:"\f58d"}.fa-share-from-square,.fa-share-square{--fa:"\f14d"}.fa-child-combatant,.fa-child-rifle{--fa:"\e4e0"}.fa-gun{--fa:"\e19b"}.fa-phone-square,.fa-square-phone{--fa:"\f098"}.fa-add,.fa-plus{--fa:"\2b"}.fa-expand{--fa:"\f065"}.fa-computer{--fa:"\e4e5"}.fa-close,.fa-multiply,.fa-remove,.fa-times,.fa-xmark{--fa:"\f00d"}.fa-arrows,.fa-arrows-up-down-left-right{--fa:"\f047"}.fa-chalkboard-teacher,.fa-chalkboard-user{--fa:"\f51c"}.fa-peso-sign{--fa:"\e222"}.fa-building-shield{--fa:"\e4d8"}.fa-baby{--fa:"\f77c"}.fa-users-line{--fa:"\e592"}.fa-quote-left,.fa-quote-left-alt{--fa:"\f10d"}.fa-tractor{--fa:"\f722"}.fa-trash-arrow-up,.fa-trash-restore{--fa:"\f829"}.fa-arrow-down-up-lock{--fa:"\e4b0"}.fa-lines-leaning{--fa:"\e51e"}.fa-ruler-combined{--fa:"\f546"}.fa-copyright{--fa:"\f1f9"}.fa-equals{--fa:"\3d"}.fa-blender{--fa:"\f517"}.fa-teeth{--fa:"\f62e"}.fa-ils,.fa-shekel,.fa-shekel-sign,.fa-sheqel,.fa-sheqel-sign{--fa:"\f20b"}.fa-map{--fa:"\f279"}.fa-rocket{--fa:"\f135"}.fa-photo-film,.fa-photo-video{--fa:"\f87c"}.fa-folder-minus{--fa:"\f65d"}.fa-hexagon-nodes-bolt{--fa:"\e69a"}.fa-store{--fa:"\f54e"}.fa-arrow-trend-up{--fa:"\e098"}.fa-plug-circle-minus{--fa:"\e55e"}.fa-sign,.fa-sign-hanging{--fa:"\f4d9"}.fa-bezier-curve{--fa:"\f55b"}.fa-bell-slash{--fa:"\f1f6"}.fa-tablet,.fa-tablet-android{--fa:"\f3fb"}.fa-school-flag{--fa:"\e56e"}.fa-fill{--fa:"\f575"}.fa-angle-up{--fa:"\f106"}.fa-drumstick-bite{--fa:"\f6d7"}.fa-holly-berry{--fa:"\f7aa"}.fa-chevron-left{--fa:"\f053"}.fa-bacteria{--fa:"\e059"}.fa-hand-lizard{--fa:"\f258"}.fa-notdef{--fa:"\e1fe"}.fa-disease{--fa:"\f7fa"}.fa-briefcase-medical{--fa:"\f469"}.fa-genderless{--fa:"\f22d"}.fa-chevron-right{--fa:"\f054"}.fa-retweet{--fa:"\f079"}.fa-car-alt,.fa-car-rear{--fa:"\f5de"}.fa-pump-soap{--fa:"\e06b"}.fa-video-slash{--fa:"\f4e2"}.fa-battery-2,.fa-battery-quarter{--fa:"\f243"}.fa-radio{--fa:"\f8d7"}.fa-baby-carriage,.fa-carriage-baby{--fa:"\f77d"}.fa-traffic-light{--fa:"\f637"}.fa-thermometer{--fa:"\f491"}.fa-vr-cardboard{--fa:"\f729"}.fa-hand-middle-finger{--fa:"\f806"}.fa-percent,.fa-percentage{--fa:"\25"}.fa-truck-moving{--fa:"\f4df"}.fa-glass-water-droplet{--fa:"\e4f5"}.fa-display{--fa:"\e163"}.fa-face-smile,.fa-smile{--fa:"\f118"}.fa-thumb-tack,.fa-thumbtack{--fa:"\f08d"}.fa-trophy{--fa:"\f091"}.fa-person-praying,.fa-pray{--fa:"\f683"}.fa-hammer{--fa:"\f6e3"}.fa-hand-peace{--fa:"\f25b"}.fa-rotate,.fa-sync-alt{--fa:"\f2f1"}.fa-spinner{--fa:"\f110"}.fa-robot{--fa:"\f544"}.fa-peace{--fa:"\f67c"}.fa-cogs,.fa-gears{--fa:"\f085"}.fa-warehouse{--fa:"\f494"}.fa-arrow-up-right-dots{--fa:"\e4b7"}.fa-splotch{--fa:"\f5bc"}.fa-face-grin-hearts,.fa-grin-hearts{--fa:"\f584"}.fa-dice-four{--fa:"\f524"}.fa-sim-card{--fa:"\f7c4"}.fa-transgender,.fa-transgender-alt{--fa:"\f225"}.fa-mercury{--fa:"\f223"}.fa-arrow-turn-down,.fa-level-down{--fa:"\f149"}.fa-person-falling-burst{--fa:"\e547"}.fa-award{--fa:"\f559"}.fa-ticket-alt,.fa-ticket-simple{--fa:"\f3ff"}.fa-building{--fa:"\f1ad"}.fa-angle-double-left,.fa-angles-left{--fa:"\f100"}.fa-qrcode{--fa:"\f029"}.fa-clock-rotate-left,.fa-history{--fa:"\f1da"}.fa-face-grin-beam-sweat,.fa-grin-beam-sweat{--fa:"\f583"}.fa-arrow-right-from-file,.fa-file-export{--fa:"\f56e"}.fa-shield,.fa-shield-blank{--fa:"\f132"}.fa-arrow-up-short-wide,.fa-sort-amount-up-alt{--fa:"\f885"}.fa-comment-nodes{--fa:"\e696"}.fa-house-medical{--fa:"\e3b2"}.fa-golf-ball,.fa-golf-ball-tee{--fa:"\f450"}.fa-chevron-circle-left,.fa-circle-chevron-left{--fa:"\f137"}.fa-house-chimney-window{--fa:"\e00d"}.fa-pen-nib{--fa:"\f5ad"}.fa-tent-arrow-turn-left{--fa:"\e580"}.fa-tents{--fa:"\e582"}.fa-magic,.fa-wand-magic{--fa:"\f0d0"}.fa-dog{--fa:"\f6d3"}.fa-carrot{--fa:"\f787"}.fa-moon{--fa:"\f186"}.fa-wine-glass-alt,.fa-wine-glass-empty{--fa:"\f5ce"}.fa-cheese{--fa:"\f7ef"}.fa-yin-yang{--fa:"\f6ad"}.fa-music{--fa:"\f001"}.fa-code-commit{--fa:"\f386"}.fa-temperature-low{--fa:"\f76b"}.fa-biking,.fa-person-biking{--fa:"\f84a"}.fa-broom{--fa:"\f51a"}.fa-shield-heart{--fa:"\e574"}.fa-gopuram{--fa:"\f664"}.fa-earth-oceania,.fa-globe-oceania{--fa:"\e47b"}.fa-square-xmark,.fa-times-square,.fa-xmark-square{--fa:"\f2d3"}.fa-hashtag{--fa:"\23"}.fa-expand-alt,.fa-up-right-and-down-left-from-center{--fa:"\f424"}.fa-oil-can{--fa:"\f613"}.fa-t{--fa:"\54"}.fa-hippo{--fa:"\f6ed"}.fa-chart-column{--fa:"\e0e3"}.fa-infinity{--fa:"\f534"}.fa-vial-circle-check{--fa:"\e596"}.fa-person-arrow-down-to-line{--fa:"\e538"}.fa-voicemail{--fa:"\f897"}.fa-fan{--fa:"\f863"}.fa-person-walking-luggage{--fa:"\e554"}.fa-arrows-alt-v,.fa-up-down{--fa:"\f338"}.fa-cloud-moon-rain{--fa:"\f73c"}.fa-calendar{--fa:"\f133"}.fa-trailer{--fa:"\e041"}.fa-bahai,.fa-haykal{--fa:"\f666"}.fa-sd-card{--fa:"\f7c2"}.fa-dragon{--fa:"\f6d5"}.fa-shoe-prints{--fa:"\f54b"}.fa-circle-plus,.fa-plus-circle{--fa:"\f055"}.fa-face-grin-tongue-wink,.fa-grin-tongue-wink{--fa:"\f58b"}.fa-hand-holding{--fa:"\f4bd"}.fa-plug-circle-exclamation{--fa:"\e55d"}.fa-chain-broken,.fa-chain-slash,.fa-link-slash,.fa-unlink{--fa:"\f127"}.fa-clone{--fa:"\f24d"}.fa-person-walking-arrow-loop-left{--fa:"\e551"}.fa-arrow-up-z-a,.fa-sort-alpha-up-alt{--fa:"\f882"}.fa-fire-alt,.fa-fire-flame-curved{--fa:"\f7e4"}.fa-tornado{--fa:"\f76f"}.fa-file-circle-plus{--fa:"\e494"}.fa-book-quran,.fa-quran{--fa:"\f687"}.fa-anchor{--fa:"\f13d"}.fa-border-all{--fa:"\f84c"}.fa-angry,.fa-face-angry{--fa:"\f556"}.fa-cookie-bite{--fa:"\f564"}.fa-arrow-trend-down{--fa:"\e097"}.fa-feed,.fa-rss{--fa:"\f09e"}.fa-draw-polygon{--fa:"\f5ee"}.fa-balance-scale,.fa-scale-balanced{--fa:"\f24e"}.fa-gauge-simple-high,.fa-tachometer,.fa-tachometer-fast{--fa:"\f62a"}.fa-shower{--fa:"\f2cc"}.fa-desktop,.fa-desktop-alt{--fa:"\f390"}.fa-m{--fa:"\4d"}.fa-table-list,.fa-th-list{--fa:"\f00b"}.fa-comment-sms,.fa-sms{--fa:"\f7cd"}.fa-book{--fa:"\f02d"}.fa-user-plus{--fa:"\f234"}.fa-check{--fa:"\f00c"}.fa-battery-4,.fa-battery-three-quarters{--fa:"\f241"}.fa-house-circle-check{--fa:"\e509"}.fa-angle-left{--fa:"\f104"}.fa-diagram-successor{--fa:"\e47a"}.fa-truck-arrow-right{--fa:"\e58b"}.fa-arrows-split-up-and-left{--fa:"\e4bc"}.fa-fist-raised,.fa-hand-fist{--fa:"\f6de"}.fa-cloud-moon{--fa:"\f6c3"}.fa-briefcase{--fa:"\f0b1"}.fa-person-falling{--fa:"\e546"}.fa-image-portrait,.fa-portrait{--fa:"\f3e0"}.fa-user-tag{--fa:"\f507"}.fa-rug{--fa:"\e569"}.fa-earth-europe,.fa-globe-europe{--fa:"\f7a2"}.fa-cart-flatbed-suitcase,.fa-luggage-cart{--fa:"\f59d"}.fa-rectangle-times,.fa-rectangle-xmark,.fa-times-rectangle,.fa-window-close{--fa:"\f410"}.fa-baht-sign{--fa:"\e0ac"}.fa-book-open{--fa:"\f518"}.fa-book-journal-whills,.fa-journal-whills{--fa:"\f66a"}.fa-handcuffs{--fa:"\e4f8"}.fa-exclamation-triangle,.fa-triangle-exclamation,.fa-warning{--fa:"\f071"}.fa-database{--fa:"\f1c0"}.fa-mail-forward,.fa-share{--fa:"\f064"}.fa-bottle-droplet{--fa:"\e4c4"}.fa-mask-face{--fa:"\e1d7"}.fa-hill-rockslide{--fa:"\e508"}.fa-exchange-alt,.fa-right-left{--fa:"\f362"}.fa-paper-plane{--fa:"\f1d8"}.fa-road-circle-exclamation{--fa:"\e565"}.fa-dungeon{--fa:"\f6d9"}.fa-align-right{--fa:"\f038"}.fa-money-bill-1-wave,.fa-money-bill-wave-alt{--fa:"\f53b"}.fa-life-ring{--fa:"\f1cd"}.fa-hands,.fa-sign-language,.fa-signing{--fa:"\f2a7"}.fa-calendar-day{--fa:"\f783"}.fa-ladder-water,.fa-swimming-pool,.fa-water-ladder{--fa:"\f5c5"}.fa-arrows-up-down,.fa-arrows-v{--fa:"\f07d"}.fa-face-grimace,.fa-grimace{--fa:"\f57f"}.fa-wheelchair-alt,.fa-wheelchair-move{--fa:"\e2ce"}.fa-level-down-alt,.fa-turn-down{--fa:"\f3be"}.fa-person-walking-arrow-right{--fa:"\e552"}.fa-envelope-square,.fa-square-envelope{--fa:"\f199"}.fa-dice{--fa:"\f522"}.fa-bowling-ball{--fa:"\f436"}.fa-brain{--fa:"\f5dc"}.fa-band-aid,.fa-bandage{--fa:"\f462"}.fa-calendar-minus{--fa:"\f272"}.fa-circle-xmark,.fa-times-circle,.fa-xmark-circle{--fa:"\f057"}.fa-gifts{--fa:"\f79c"}.fa-hotel{--fa:"\f594"}.fa-earth-asia,.fa-globe-asia{--fa:"\f57e"}.fa-id-card-alt,.fa-id-card-clip{--fa:"\f47f"}.fa-magnifying-glass-plus,.fa-search-plus{--fa:"\f00e"}.fa-thumbs-up{--fa:"\f164"}.fa-user-clock{--fa:"\f4fd"}.fa-allergies,.fa-hand-dots{--fa:"\f461"}.fa-file-invoice{--fa:"\f570"}.fa-window-minimize{--fa:"\f2d1"}.fa-coffee,.fa-mug-saucer{--fa:"\f0f4"}.fa-brush{--fa:"\f55d"}.fa-file-half-dashed{--fa:"\e698"}.fa-mask{--fa:"\f6fa"}.fa-magnifying-glass-minus,.fa-search-minus{--fa:"\f010"}.fa-ruler-vertical{--fa:"\f548"}.fa-user-alt,.fa-user-large{--fa:"\f406"}.fa-train-tram{--fa:"\e5b4"}.fa-user-nurse{--fa:"\f82f"}.fa-syringe{--fa:"\f48e"}.fa-cloud-sun{--fa:"\f6c4"}.fa-stopwatch-20{--fa:"\e06f"}.fa-square-full{--fa:"\f45c"}.fa-magnet{--fa:"\f076"}.fa-jar{--fa:"\e516"}.fa-note-sticky,.fa-sticky-note{--fa:"\f249"}.fa-bug-slash{--fa:"\e490"}.fa-arrow-up-from-water-pump{--fa:"\e4b6"}.fa-bone{--fa:"\f5d7"}.fa-table-cells-row-unlock{--fa:"\e691"}.fa-user-injured{--fa:"\f728"}.fa-face-sad-tear,.fa-sad-tear{--fa:"\f5b4"}.fa-plane{--fa:"\f072"}.fa-tent-arrows-down{--fa:"\e581"}.fa-exclamation{--fa:"\21"}.fa-arrows-spin{--fa:"\e4bb"}.fa-print{--fa:"\f02f"}.fa-try,.fa-turkish-lira,.fa-turkish-lira-sign{--fa:"\e2bb"}.fa-dollar,.fa-dollar-sign,.fa-usd{--fa:"\24"}.fa-x{--fa:"\58"}.fa-magnifying-glass-dollar,.fa-search-dollar{--fa:"\f688"}.fa-users-cog,.fa-users-gear{--fa:"\f509"}.fa-person-military-pointing{--fa:"\e54a"}.fa-bank,.fa-building-columns,.fa-institution,.fa-museum,.fa-university{--fa:"\f19c"}.fa-umbrella{--fa:"\f0e9"}.fa-trowel{--fa:"\e589"}.fa-d{--fa:"\44"}.fa-stapler{--fa:"\e5af"}.fa-masks-theater,.fa-theater-masks{--fa:"\f630"}.fa-kip-sign{--fa:"\e1c4"}.fa-hand-point-left{--fa:"\f0a5"}.fa-handshake-alt,.fa-handshake-simple{--fa:"\f4c6"}.fa-fighter-jet,.fa-jet-fighter{--fa:"\f0fb"}.fa-share-alt-square,.fa-square-share-nodes{--fa:"\f1e1"}.fa-barcode{--fa:"\f02a"}.fa-plus-minus{--fa:"\e43c"}.fa-video,.fa-video-camera{--fa:"\f03d"}.fa-graduation-cap,.fa-mortar-board{--fa:"\f19d"}.fa-hand-holding-medical{--fa:"\e05c"}.fa-person-circle-check{--fa:"\e53e"}.fa-level-up-alt,.fa-turn-up{--fa:"\f3bf"} -.fa-sr-only,.fa-sr-only-focusable:not(:focus),.sr-only,.sr-only-focusable:not(:focus){position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}:host,:root{--fa-style-family-brands:"Font Awesome 6 Brands";--fa-font-brands:normal 400 1em/1 "Font Awesome 6 Brands"}@font-face{font-family:"Font Awesome 6 Brands";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.ttf) format("truetype")}.fa-brands,.fab{font-weight:400}.fa-monero{--fa:"\f3d0"}.fa-hooli{--fa:"\f427"}.fa-yelp{--fa:"\f1e9"}.fa-cc-visa{--fa:"\f1f0"}.fa-lastfm{--fa:"\f202"}.fa-shopware{--fa:"\f5b5"}.fa-creative-commons-nc{--fa:"\f4e8"}.fa-aws{--fa:"\f375"}.fa-redhat{--fa:"\f7bc"}.fa-yoast{--fa:"\f2b1"}.fa-cloudflare{--fa:"\e07d"}.fa-ups{--fa:"\f7e0"}.fa-pixiv{--fa:"\e640"}.fa-wpexplorer{--fa:"\f2de"}.fa-dyalog{--fa:"\f399"}.fa-bity{--fa:"\f37a"}.fa-stackpath{--fa:"\f842"}.fa-buysellads{--fa:"\f20d"}.fa-first-order{--fa:"\f2b0"}.fa-modx{--fa:"\f285"}.fa-guilded{--fa:"\e07e"}.fa-vnv{--fa:"\f40b"}.fa-js-square,.fa-square-js{--fa:"\f3b9"}.fa-microsoft{--fa:"\f3ca"}.fa-qq{--fa:"\f1d6"}.fa-orcid{--fa:"\f8d2"}.fa-java{--fa:"\f4e4"}.fa-invision{--fa:"\f7b0"}.fa-creative-commons-pd-alt{--fa:"\f4ed"}.fa-centercode{--fa:"\f380"}.fa-glide-g{--fa:"\f2a6"}.fa-drupal{--fa:"\f1a9"}.fa-jxl{--fa:"\e67b"}.fa-dart-lang{--fa:"\e693"}.fa-hire-a-helper{--fa:"\f3b0"}.fa-creative-commons-by{--fa:"\f4e7"}.fa-unity{--fa:"\e049"}.fa-whmcs{--fa:"\f40d"}.fa-rocketchat{--fa:"\f3e8"}.fa-vk{--fa:"\f189"}.fa-untappd{--fa:"\f405"}.fa-mailchimp{--fa:"\f59e"}.fa-css3-alt{--fa:"\f38b"}.fa-reddit-square,.fa-square-reddit{--fa:"\f1a2"}.fa-vimeo-v{--fa:"\f27d"}.fa-contao{--fa:"\f26d"}.fa-square-font-awesome{--fa:"\e5ad"}.fa-deskpro{--fa:"\f38f"}.fa-brave{--fa:"\e63c"}.fa-sistrix{--fa:"\f3ee"}.fa-instagram-square,.fa-square-instagram{--fa:"\e055"}.fa-battle-net{--fa:"\f835"}.fa-the-red-yeti{--fa:"\f69d"}.fa-hacker-news-square,.fa-square-hacker-news{--fa:"\f3af"}.fa-edge{--fa:"\f282"}.fa-threads{--fa:"\e618"}.fa-napster{--fa:"\f3d2"}.fa-snapchat-square,.fa-square-snapchat{--fa:"\f2ad"}.fa-google-plus-g{--fa:"\f0d5"}.fa-artstation{--fa:"\f77a"}.fa-markdown{--fa:"\f60f"}.fa-sourcetree{--fa:"\f7d3"}.fa-google-plus{--fa:"\f2b3"}.fa-diaspora{--fa:"\f791"}.fa-foursquare{--fa:"\f180"}.fa-stack-overflow{--fa:"\f16c"}.fa-github-alt{--fa:"\f113"}.fa-phoenix-squadron{--fa:"\f511"}.fa-pagelines{--fa:"\f18c"}.fa-algolia{--fa:"\f36c"}.fa-red-river{--fa:"\f3e3"}.fa-creative-commons-sa{--fa:"\f4ef"}.fa-safari{--fa:"\f267"}.fa-google{--fa:"\f1a0"}.fa-font-awesome-alt,.fa-square-font-awesome-stroke{--fa:"\f35c"}.fa-atlassian{--fa:"\f77b"}.fa-linkedin-in{--fa:"\f0e1"}.fa-digital-ocean{--fa:"\f391"}.fa-nimblr{--fa:"\f5a8"}.fa-chromecast{--fa:"\f838"}.fa-evernote{--fa:"\f839"}.fa-hacker-news{--fa:"\f1d4"}.fa-creative-commons-sampling{--fa:"\f4f0"}.fa-adversal{--fa:"\f36a"}.fa-creative-commons{--fa:"\f25e"}.fa-watchman-monitoring{--fa:"\e087"}.fa-fonticons{--fa:"\f280"}.fa-weixin{--fa:"\f1d7"}.fa-shirtsinbulk{--fa:"\f214"}.fa-codepen{--fa:"\f1cb"}.fa-git-alt{--fa:"\f841"}.fa-lyft{--fa:"\f3c3"}.fa-rev{--fa:"\f5b2"}.fa-windows{--fa:"\f17a"}.fa-wizards-of-the-coast{--fa:"\f730"}.fa-square-viadeo,.fa-viadeo-square{--fa:"\f2aa"}.fa-meetup{--fa:"\f2e0"}.fa-centos{--fa:"\f789"}.fa-adn{--fa:"\f170"}.fa-cloudsmith{--fa:"\f384"}.fa-opensuse{--fa:"\e62b"}.fa-pied-piper-alt{--fa:"\f1a8"}.fa-dribbble-square,.fa-square-dribbble{--fa:"\f397"}.fa-codiepie{--fa:"\f284"}.fa-node{--fa:"\f419"}.fa-mix{--fa:"\f3cb"}.fa-steam{--fa:"\f1b6"}.fa-cc-apple-pay{--fa:"\f416"}.fa-scribd{--fa:"\f28a"}.fa-debian{--fa:"\e60b"}.fa-openid{--fa:"\f19b"}.fa-instalod{--fa:"\e081"}.fa-files-pinwheel{--fa:"\e69f"}.fa-expeditedssl{--fa:"\f23e"}.fa-sellcast{--fa:"\f2da"}.fa-square-twitter,.fa-twitter-square{--fa:"\f081"}.fa-r-project{--fa:"\f4f7"}.fa-delicious{--fa:"\f1a5"}.fa-freebsd{--fa:"\f3a4"}.fa-vuejs{--fa:"\f41f"}.fa-accusoft{--fa:"\f369"}.fa-ioxhost{--fa:"\f208"}.fa-fonticons-fi{--fa:"\f3a2"}.fa-app-store{--fa:"\f36f"}.fa-cc-mastercard{--fa:"\f1f1"}.fa-itunes-note{--fa:"\f3b5"}.fa-golang{--fa:"\e40f"}.fa-kickstarter,.fa-square-kickstarter{--fa:"\f3bb"}.fa-grav{--fa:"\f2d6"}.fa-weibo{--fa:"\f18a"}.fa-uncharted{--fa:"\e084"}.fa-firstdraft{--fa:"\f3a1"}.fa-square-youtube,.fa-youtube-square{--fa:"\f431"}.fa-wikipedia-w{--fa:"\f266"}.fa-rendact,.fa-wpressr{--fa:"\f3e4"}.fa-angellist{--fa:"\f209"}.fa-galactic-republic{--fa:"\f50c"}.fa-nfc-directional{--fa:"\e530"}.fa-skype{--fa:"\f17e"}.fa-joget{--fa:"\f3b7"}.fa-fedora{--fa:"\f798"}.fa-stripe-s{--fa:"\f42a"}.fa-meta{--fa:"\e49b"}.fa-laravel{--fa:"\f3bd"}.fa-hotjar{--fa:"\f3b1"}.fa-bluetooth-b{--fa:"\f294"}.fa-square-letterboxd{--fa:"\e62e"}.fa-sticker-mule{--fa:"\f3f7"}.fa-creative-commons-zero{--fa:"\f4f3"}.fa-hips{--fa:"\f452"}.fa-css{--fa:"\e6a2"}.fa-behance{--fa:"\f1b4"}.fa-reddit{--fa:"\f1a1"}.fa-discord{--fa:"\f392"}.fa-chrome{--fa:"\f268"}.fa-app-store-ios{--fa:"\f370"}.fa-cc-discover{--fa:"\f1f2"}.fa-wpbeginner{--fa:"\f297"}.fa-confluence{--fa:"\f78d"}.fa-shoelace{--fa:"\e60c"}.fa-mdb{--fa:"\f8ca"}.fa-dochub{--fa:"\f394"}.fa-accessible-icon{--fa:"\f368"}.fa-ebay{--fa:"\f4f4"}.fa-amazon{--fa:"\f270"}.fa-unsplash{--fa:"\e07c"}.fa-yarn{--fa:"\f7e3"}.fa-square-steam,.fa-steam-square{--fa:"\f1b7"}.fa-500px{--fa:"\f26e"}.fa-square-vimeo,.fa-vimeo-square{--fa:"\f194"}.fa-asymmetrik{--fa:"\f372"}.fa-font-awesome,.fa-font-awesome-flag,.fa-font-awesome-logo-full{--fa:"\f2b4"}.fa-gratipay{--fa:"\f184"}.fa-apple{--fa:"\f179"}.fa-hive{--fa:"\e07f"}.fa-gitkraken{--fa:"\f3a6"}.fa-keybase{--fa:"\f4f5"}.fa-apple-pay{--fa:"\f415"}.fa-padlet{--fa:"\e4a0"}.fa-amazon-pay{--fa:"\f42c"}.fa-github-square,.fa-square-github{--fa:"\f092"}.fa-stumbleupon{--fa:"\f1a4"}.fa-fedex{--fa:"\f797"}.fa-phoenix-framework{--fa:"\f3dc"}.fa-shopify{--fa:"\e057"}.fa-neos{--fa:"\f612"}.fa-square-threads{--fa:"\e619"}.fa-hackerrank{--fa:"\f5f7"}.fa-researchgate{--fa:"\f4f8"}.fa-swift{--fa:"\f8e1"}.fa-angular{--fa:"\f420"}.fa-speakap{--fa:"\f3f3"}.fa-angrycreative{--fa:"\f36e"}.fa-y-combinator{--fa:"\f23b"}.fa-empire{--fa:"\f1d1"}.fa-envira{--fa:"\f299"}.fa-google-scholar{--fa:"\e63b"}.fa-gitlab-square,.fa-square-gitlab{--fa:"\e5ae"}.fa-studiovinari{--fa:"\f3f8"}.fa-pied-piper{--fa:"\f2ae"}.fa-wordpress{--fa:"\f19a"}.fa-product-hunt{--fa:"\f288"}.fa-firefox{--fa:"\f269"}.fa-linode{--fa:"\f2b8"}.fa-goodreads{--fa:"\f3a8"}.fa-odnoklassniki-square,.fa-square-odnoklassniki{--fa:"\f264"}.fa-jsfiddle{--fa:"\f1cc"}.fa-sith{--fa:"\f512"}.fa-themeisle{--fa:"\f2b2"}.fa-page4{--fa:"\f3d7"}.fa-hashnode{--fa:"\e499"}.fa-react{--fa:"\f41b"}.fa-cc-paypal{--fa:"\f1f4"}.fa-squarespace{--fa:"\f5be"}.fa-cc-stripe{--fa:"\f1f5"}.fa-creative-commons-share{--fa:"\f4f2"}.fa-bitcoin{--fa:"\f379"}.fa-keycdn{--fa:"\f3ba"}.fa-opera{--fa:"\f26a"}.fa-itch-io{--fa:"\f83a"}.fa-umbraco{--fa:"\f8e8"}.fa-galactic-senate{--fa:"\f50d"}.fa-ubuntu{--fa:"\f7df"}.fa-draft2digital{--fa:"\f396"}.fa-stripe{--fa:"\f429"}.fa-houzz{--fa:"\f27c"}.fa-gg{--fa:"\f260"}.fa-dhl{--fa:"\f790"}.fa-pinterest-square,.fa-square-pinterest{--fa:"\f0d3"}.fa-xing{--fa:"\f168"}.fa-blackberry{--fa:"\f37b"}.fa-creative-commons-pd{--fa:"\f4ec"}.fa-playstation{--fa:"\f3df"}.fa-quinscape{--fa:"\f459"}.fa-less{--fa:"\f41d"}.fa-blogger-b{--fa:"\f37d"}.fa-opencart{--fa:"\f23d"}.fa-vine{--fa:"\f1ca"}.fa-signal-messenger{--fa:"\e663"}.fa-paypal{--fa:"\f1ed"}.fa-gitlab{--fa:"\f296"}.fa-typo3{--fa:"\f42b"}.fa-reddit-alien{--fa:"\f281"}.fa-yahoo{--fa:"\f19e"}.fa-dailymotion{--fa:"\e052"}.fa-affiliatetheme{--fa:"\f36b"}.fa-pied-piper-pp{--fa:"\f1a7"}.fa-bootstrap{--fa:"\f836"}.fa-odnoklassniki{--fa:"\f263"}.fa-nfc-symbol{--fa:"\e531"}.fa-mintbit{--fa:"\e62f"}.fa-ethereum{--fa:"\f42e"}.fa-speaker-deck{--fa:"\f83c"}.fa-creative-commons-nc-eu{--fa:"\f4e9"}.fa-patreon{--fa:"\f3d9"}.fa-avianex{--fa:"\f374"}.fa-ello{--fa:"\f5f1"}.fa-gofore{--fa:"\f3a7"}.fa-bimobject{--fa:"\f378"}.fa-brave-reverse{--fa:"\e63d"}.fa-facebook-f{--fa:"\f39e"}.fa-google-plus-square,.fa-square-google-plus{--fa:"\f0d4"}.fa-web-awesome{--fa:"\e682"}.fa-mandalorian{--fa:"\f50f"}.fa-first-order-alt{--fa:"\f50a"}.fa-osi{--fa:"\f41a"}.fa-google-wallet{--fa:"\f1ee"}.fa-d-and-d-beyond{--fa:"\f6ca"}.fa-periscope{--fa:"\f3da"}.fa-fulcrum{--fa:"\f50b"}.fa-cloudscale{--fa:"\f383"}.fa-forumbee{--fa:"\f211"}.fa-mizuni{--fa:"\f3cc"}.fa-schlix{--fa:"\f3ea"}.fa-square-xing,.fa-xing-square{--fa:"\f169"}.fa-bandcamp{--fa:"\f2d5"}.fa-wpforms{--fa:"\f298"}.fa-cloudversify{--fa:"\f385"}.fa-usps{--fa:"\f7e1"}.fa-megaport{--fa:"\f5a3"}.fa-magento{--fa:"\f3c4"}.fa-spotify{--fa:"\f1bc"}.fa-optin-monster{--fa:"\f23c"}.fa-fly{--fa:"\f417"}.fa-square-bluesky{--fa:"\e6a3"}.fa-aviato{--fa:"\f421"}.fa-itunes{--fa:"\f3b4"}.fa-cuttlefish{--fa:"\f38c"}.fa-blogger{--fa:"\f37c"}.fa-flickr{--fa:"\f16e"}.fa-viber{--fa:"\f409"}.fa-soundcloud{--fa:"\f1be"}.fa-digg{--fa:"\f1a6"}.fa-tencent-weibo{--fa:"\f1d5"}.fa-letterboxd{--fa:"\e62d"}.fa-symfony{--fa:"\f83d"}.fa-maxcdn{--fa:"\f136"}.fa-etsy{--fa:"\f2d7"}.fa-facebook-messenger{--fa:"\f39f"}.fa-audible{--fa:"\f373"}.fa-think-peaks{--fa:"\f731"}.fa-bilibili{--fa:"\e3d9"}.fa-erlang{--fa:"\f39d"}.fa-x-twitter{--fa:"\e61b"}.fa-cotton-bureau{--fa:"\f89e"}.fa-dashcube{--fa:"\f210"}.fa-42-group,.fa-innosoft{--fa:"\e080"}.fa-stack-exchange{--fa:"\f18d"}.fa-elementor{--fa:"\f430"}.fa-pied-piper-square,.fa-square-pied-piper{--fa:"\e01e"}.fa-creative-commons-nd{--fa:"\f4eb"}.fa-palfed{--fa:"\f3d8"}.fa-superpowers{--fa:"\f2dd"}.fa-resolving{--fa:"\f3e7"}.fa-xbox{--fa:"\f412"}.fa-square-web-awesome-stroke{--fa:"\e684"}.fa-searchengin{--fa:"\f3eb"}.fa-tiktok{--fa:"\e07b"}.fa-facebook-square,.fa-square-facebook{--fa:"\f082"}.fa-renren{--fa:"\f18b"}.fa-linux{--fa:"\f17c"}.fa-glide{--fa:"\f2a5"}.fa-linkedin{--fa:"\f08c"}.fa-hubspot{--fa:"\f3b2"}.fa-deploydog{--fa:"\f38e"}.fa-twitch{--fa:"\f1e8"}.fa-flutter{--fa:"\e694"}.fa-ravelry{--fa:"\f2d9"}.fa-mixer{--fa:"\e056"}.fa-lastfm-square,.fa-square-lastfm{--fa:"\f203"}.fa-vimeo{--fa:"\f40a"}.fa-mendeley{--fa:"\f7b3"}.fa-uniregistry{--fa:"\f404"}.fa-figma{--fa:"\f799"}.fa-creative-commons-remix{--fa:"\f4ee"}.fa-cc-amazon-pay{--fa:"\f42d"}.fa-dropbox{--fa:"\f16b"}.fa-instagram{--fa:"\f16d"}.fa-cmplid{--fa:"\e360"}.fa-upwork{--fa:"\e641"}.fa-facebook{--fa:"\f09a"}.fa-gripfire{--fa:"\f3ac"}.fa-jedi-order{--fa:"\f50e"}.fa-uikit{--fa:"\f403"}.fa-fort-awesome-alt{--fa:"\f3a3"}.fa-phabricator{--fa:"\f3db"}.fa-ussunnah{--fa:"\f407"}.fa-earlybirds{--fa:"\f39a"}.fa-trade-federation{--fa:"\f513"}.fa-autoprefixer{--fa:"\f41c"}.fa-whatsapp{--fa:"\f232"}.fa-square-upwork{--fa:"\e67c"}.fa-slideshare{--fa:"\f1e7"}.fa-google-play{--fa:"\f3ab"}.fa-viadeo{--fa:"\f2a9"}.fa-line{--fa:"\f3c0"}.fa-google-drive{--fa:"\f3aa"}.fa-servicestack{--fa:"\f3ec"}.fa-simplybuilt{--fa:"\f215"}.fa-bitbucket{--fa:"\f171"}.fa-imdb{--fa:"\f2d8"}.fa-deezer{--fa:"\e077"}.fa-raspberry-pi{--fa:"\f7bb"}.fa-jira{--fa:"\f7b1"}.fa-docker{--fa:"\f395"}.fa-screenpal{--fa:"\e570"}.fa-bluetooth{--fa:"\f293"}.fa-gitter{--fa:"\f426"}.fa-d-and-d{--fa:"\f38d"}.fa-microblog{--fa:"\e01a"}.fa-cc-diners-club{--fa:"\f24c"}.fa-gg-circle{--fa:"\f261"}.fa-pied-piper-hat{--fa:"\f4e5"}.fa-kickstarter-k{--fa:"\f3bc"}.fa-yandex{--fa:"\f413"}.fa-readme{--fa:"\f4d5"}.fa-html5{--fa:"\f13b"}.fa-sellsy{--fa:"\f213"}.fa-square-web-awesome{--fa:"\e683"}.fa-sass{--fa:"\f41e"}.fa-wirsindhandwerk,.fa-wsh{--fa:"\e2d0"}.fa-buromobelexperte{--fa:"\f37f"}.fa-salesforce{--fa:"\f83b"}.fa-octopus-deploy{--fa:"\e082"}.fa-medapps{--fa:"\f3c6"}.fa-ns8{--fa:"\f3d5"}.fa-pinterest-p{--fa:"\f231"}.fa-apper{--fa:"\f371"}.fa-fort-awesome{--fa:"\f286"}.fa-waze{--fa:"\f83f"}.fa-bluesky{--fa:"\e671"}.fa-cc-jcb{--fa:"\f24b"}.fa-snapchat,.fa-snapchat-ghost{--fa:"\f2ab"}.fa-fantasy-flight-games{--fa:"\f6dc"}.fa-rust{--fa:"\e07a"}.fa-wix{--fa:"\f5cf"}.fa-behance-square,.fa-square-behance{--fa:"\f1b5"}.fa-supple{--fa:"\f3f9"}.fa-webflow{--fa:"\e65c"}.fa-rebel{--fa:"\f1d0"}.fa-css3{--fa:"\f13c"}.fa-staylinked{--fa:"\f3f5"}.fa-kaggle{--fa:"\f5fa"}.fa-space-awesome{--fa:"\e5ac"}.fa-deviantart{--fa:"\f1bd"}.fa-cpanel{--fa:"\f388"}.fa-goodreads-g{--fa:"\f3a9"}.fa-git-square,.fa-square-git{--fa:"\f1d2"}.fa-square-tumblr,.fa-tumblr-square{--fa:"\f174"}.fa-trello{--fa:"\f181"}.fa-creative-commons-nc-jp{--fa:"\f4ea"}.fa-get-pocket{--fa:"\f265"}.fa-perbyte{--fa:"\e083"}.fa-grunt{--fa:"\f3ad"}.fa-weebly{--fa:"\f5cc"}.fa-connectdevelop{--fa:"\f20e"}.fa-leanpub{--fa:"\f212"}.fa-black-tie{--fa:"\f27e"}.fa-themeco{--fa:"\f5c6"}.fa-python{--fa:"\f3e2"}.fa-android{--fa:"\f17b"}.fa-bots{--fa:"\e340"}.fa-free-code-camp{--fa:"\f2c5"}.fa-hornbill{--fa:"\f592"}.fa-js{--fa:"\f3b8"}.fa-ideal{--fa:"\e013"}.fa-git{--fa:"\f1d3"}.fa-dev{--fa:"\f6cc"}.fa-sketch{--fa:"\f7c6"}.fa-yandex-international{--fa:"\f414"}.fa-cc-amex{--fa:"\f1f3"}.fa-uber{--fa:"\f402"}.fa-github{--fa:"\f09b"}.fa-php{--fa:"\f457"}.fa-alipay{--fa:"\f642"}.fa-youtube{--fa:"\f167"}.fa-skyatlas{--fa:"\f216"}.fa-firefox-browser{--fa:"\e007"}.fa-replyd{--fa:"\f3e6"}.fa-suse{--fa:"\f7d6"}.fa-jenkins{--fa:"\f3b6"}.fa-twitter{--fa:"\f099"}.fa-rockrms{--fa:"\f3e9"}.fa-pinterest{--fa:"\f0d2"}.fa-buffer{--fa:"\f837"}.fa-npm{--fa:"\f3d4"}.fa-yammer{--fa:"\f840"}.fa-btc{--fa:"\f15a"}.fa-dribbble{--fa:"\f17d"}.fa-stumbleupon-circle{--fa:"\f1a3"}.fa-internet-explorer{--fa:"\f26b"}.fa-stubber{--fa:"\e5c7"}.fa-telegram,.fa-telegram-plane{--fa:"\f2c6"}.fa-old-republic{--fa:"\f510"}.fa-odysee{--fa:"\e5c6"}.fa-square-whatsapp,.fa-whatsapp-square{--fa:"\f40c"}.fa-node-js{--fa:"\f3d3"}.fa-edge-legacy{--fa:"\e078"}.fa-slack,.fa-slack-hash{--fa:"\f198"}.fa-medrt{--fa:"\f3c8"}.fa-usb{--fa:"\f287"}.fa-tumblr{--fa:"\f173"}.fa-vaadin{--fa:"\f408"}.fa-quora{--fa:"\f2c4"}.fa-square-x-twitter{--fa:"\e61a"}.fa-reacteurope{--fa:"\f75d"}.fa-medium,.fa-medium-m{--fa:"\f23a"}.fa-amilia{--fa:"\f36d"}.fa-mixcloud{--fa:"\f289"}.fa-flipboard{--fa:"\f44d"}.fa-viacoin{--fa:"\f237"}.fa-critical-role{--fa:"\f6c9"}.fa-sitrox{--fa:"\e44a"}.fa-discourse{--fa:"\f393"}.fa-joomla{--fa:"\f1aa"}.fa-mastodon{--fa:"\f4f6"}.fa-airbnb{--fa:"\f834"}.fa-wolf-pack-battalion{--fa:"\f514"}.fa-buy-n-large{--fa:"\f8a6"}.fa-gulp{--fa:"\f3ae"}.fa-creative-commons-sampling-plus{--fa:"\f4f1"}.fa-strava{--fa:"\f428"}.fa-ember{--fa:"\f423"}.fa-canadian-maple-leaf{--fa:"\f785"}.fa-teamspeak{--fa:"\f4f9"}.fa-pushed{--fa:"\f3e1"}.fa-wordpress-simple{--fa:"\f411"}.fa-nutritionix{--fa:"\f3d6"}.fa-wodu{--fa:"\e088"}.fa-google-pay{--fa:"\e079"}.fa-intercom{--fa:"\f7af"}.fa-zhihu{--fa:"\f63f"}.fa-korvue{--fa:"\f42f"}.fa-pix{--fa:"\e43a"}.fa-steam-symbol{--fa:"\f3f6"}:host,:root{--fa-font-regular:normal 400 1em/1 "Font Awesome 6 Free"}@font-face{font-family:"Font Awesome 6 Free";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype")}.fa-regular,.far{font-weight:400}:host,:root{--fa-style-family-classic:"Font Awesome 6 Free";--fa-font-solid:normal 900 1em/1 "Font Awesome 6 Free"}@font-face{font-family:"Font Awesome 6 Free";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}.fa-solid,.fas{font-weight:900}@font-face{font-family:"Font Awesome 5 Brands";font-display:block;font-weight:400;src:url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.ttf) format("truetype")}@font-face{font-family:"Font Awesome 5 Free";font-display:block;font-weight:900;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}@font-face{font-family:"Font Awesome 5 Free";font-display:block;font-weight:400;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.ttf) format("truetype")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype");unicode-range:u+f003,u+f006,u+f014,u+f016-f017,u+f01a-f01b,u+f01d,u+f022,u+f03e,u+f044,u+f046,u+f05c-f05d,u+f06e,u+f070,u+f087-f088,u+f08a,u+f094,u+f096-f097,u+f09d,u+f0a0,u+f0a2,u+f0a4-f0a7,u+f0c5,u+f0c7,u+f0e5-f0e6,u+f0eb,u+f0f6-f0f8,u+f10c,u+f114-f115,u+f118-f11a,u+f11c-f11d,u+f133,u+f147,u+f14e,u+f150-f152,u+f185-f186,u+f18e,u+f190-f192,u+f196,u+f1c1-f1c9,u+f1d9,u+f1db,u+f1e3,u+f1ea,u+f1f7,u+f1f9,u+f20a,u+f247-f248,u+f24a,u+f24d,u+f255-f25b,u+f25d,u+f271-f274,u+f278,u+f27b,u+f28c,u+f28e,u+f29c,u+f2b5,u+f2b7,u+f2ba,u+f2bc,u+f2be,u+f2c0-f2c1,u+f2c3,u+f2d0,u+f2d2,u+f2d4,u+f2dc}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-v4compatibility.woff2) format("woff2"),url(../webfonts/fa-v4compatibility.ttf) format("truetype");unicode-range:u+f041,u+f047,u+f065-f066,u+f07d-f07e,u+f080,u+f08b,u+f08e,u+f090,u+f09a,u+f0ac,u+f0ae,u+f0b2,u+f0d0,u+f0d6,u+f0e4,u+f0ec,u+f10a-f10b,u+f123,u+f13e,u+f148-f149,u+f14c,u+f156,u+f15e,u+f160-f161,u+f163,u+f175-f178,u+f195,u+f1f8,u+f219,u+f27a} \ No newline at end of file diff --git a/static/css/main.css b/static/css/main.css deleted file mode 100644 index 2919ad0..0000000 --- a/static/css/main.css +++ /dev/null @@ -1,651 +0,0 @@ -/* Light mode */ -:root { - --text: #000000; - --link: #1565C0; - --link_visited: #1565C0; - --accent1: #333333; - --accent2: #666666; - --background: #ffffff; - --code: #e3e3e3; - --button-text: #ffffff; - --blockquote: #fffee0; - --blockquote-border: #e5d600; - --aside: #e0f7fa; - --aside-border: #0097a7; - --note: #e8f5e9; - --note-border: #d5e1d6; - --alert: #ffebee; - --alert-border: #d32f2f; - --field: #fffee0; - --mark: #FFFF99; - --audio-link: #d32f2f; -} - -/* Dark mode */ -@media (prefers-color-scheme: dark) { - :root { - --text: #f8f8f2; - --link: #8be9fd; - --link_visited: #8be9fd; - --accent1: #f8f8f2; - --accent2: #f8f8f2; - --background: #282a36; - --code: #44475a; - --button-text: #282a36; - --blockquote: #44475a; - --blockquote-border: #6272a4; - --aside: #6272a4; - --aside-border: #7797b7 ; - --note: #3f444a; - --note-border: #4f545a; - --alert: #ff5555; - --alert-border: #ff6e6e; - --field: #44475a; - --mark: #FFFF99; - --audio-link: #ff6e6e; - } -} - -/* Font stacks */ -:root { - --font_system_ui: system-ui, sans-serif; - --font_transitional: Charter, 'Bitstream Charter', 'Sitka Text', Cambria, serif; - --font_old_style: 'Iowan Old Style', 'Palatino Linotype', 'URW Palladio L', P052, serif; - --font_humanist: Seravek, 'Gill Sans Nova', Ubuntu, Calibri, 'DejaVu Sans', source-sans-pro, sans-serif; - --font_geometric_humanist: Avenir, Montserrat, Corbel, 'URW Gothic', source-sans-pro, sans-serif; - --font_classical_humanist: Optima, Candara, 'Noto Sans', source-sans-pro, sans-serif; - --font_neo_grotesque: Inter, Roboto, 'Helvetica Neue', 'Arial Nova', 'Nimbus Sans', Arial, sans-serif; - --font_monospace_slab_serif: 'Nimbus Mono PS', 'Courier New', monospace; - --font_monospace_code: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace; - --font_industrial: Bahnschrift, 'DIN Alternate', 'Franklin Gothic Medium', 'Nimbus Sans Narrow', sans-serif-condensed, sans-serif; - --font_rounded_sans: ui-rounded, 'Hiragino Maru Gothic ProN', Quicksand, Comfortaa, Manjari, 'Arial Rounded MT', 'Arial Rounded MT Bold', Calibri, source-sans-pro, sans-serif; - --font_slab_serif: Rockwell, 'Rockwell Nova', 'Roboto Slab', 'DejaVu Serif', 'Sitka Small', serif; - --font_antique: Superclarendon, 'Bookman Old Style', 'URW Bookman', 'URW Bookman L', 'Georgia Pro', Georgia, serif; - --font_didone: Didot, 'Bodoni MT', 'Noto Serif Display', 'URW Palladio L', P052, Sylfaen, serif; - --font_handwritten: 'Segoe Print', 'Bradley Hand', Chilanka, TSCu_Comic, casual, cursive; -} - -body { - max-width: 40em; - margin: 2em auto; - font-family: var(--font_system_ui); - font-size: 18px; - padding: 0 1em; - line-height: 1.6; - background-color: var(--background); - color: var(--text); -} - -header { - margin-bottom: 2em; -} - -.post-header { - margin-bottom: 0; -} - -header h1 a, -header h1 a:visited { - text-decoration: none; - color: var(--text); -} - -header h1 a:hover { - color: var(--accent1); - text-decoration: none; -} - -header p { - margin-top: 0; -} - -a { - color: var(--link); -} - -a:hover { - text-decoration: none; -} - -a:visited { - color: var(--link_visited) -} - -a.post-date { - font-size: 0.8em; - color: var(--link); - text-decoration: none; -} - -span.post-date { - font-size: 0.8em; -} - -a.post-date:hover { - text-decoration: none; -} - -.p-name { - text-wrap: balance; -} - -.e-content { - margin-bottom: 2em; - overflow-wrap: anywhere; -} - -.e-content p:first-of-type, -article p:first-of-type { - margin-top: 0; -} - -img.profile_photo { - border-radius: 80px; -} - -nav ul, -ul.reply-buttons { - list-style-type: none; - padding: 0; -} - -nav ul li, -ul.reply-buttons li { - display: inline; - margin-right: 0.2em; - line-height: 2.15em; - white-space: nowrap; -} - -nav a, -nav a:visited, -nav a:hover, -a.conversation-on-mb, -a.reply-on-mastodon, -a.reply-by-email, -a.read-more { - text-decoration: none; - padding: 5px 10px; - border: 1px solid var(--link); - color: var(--link); - border-radius: 5px; - font-size: 0.9em; -} - -nav a:hover, -a.conversation-on-mb:hover, -a.reply-on-mastodon:hover, -a.reply-by-email:hover, -a.read-more:hover { - background: var(--link); - color: var(--button-text); -} - -button { - cursor: pointer; -} - -.reply-to { - background: var(--code); - border-radius: 5px; - padding: 0 .333em; - display: inline-block; - font-size: 0.8em; -} - -header h1 { - margin-top: 0.2em; - margin-bottom: 0.2em; -} - -h1, -h2, -h3 { - line-height: 1.2em; -} - -h2 { - margin-top: 0; -} - -.post-nav { - margin-top: 2.5em; - margin-bottom: 2.5em; - text-align: center; -} - -.post-nav span { - padding: 0 5px; -} - -.post-nav a:visited { - color: var(--link); -} - -.post-meta { - color: var(--accent2); -} - -article img, -.e-content img, -.p-summary img { - width: 100%; - height: auto; - border-radius: 5px; -} - -ul.post-tags li { - display: inline; - font-size: 0.8em; -} - -ul.post-tags, -ul.post-list { - padding-left: 0; -} - -ul.post-list { - list-style-type: none; -} - -ul.post-list a.u-url { - text-decoration: none; -} - -.callout { - background: var(--code); - padding: 1em; - border-radius: 5px; - margin-bottom: 2em; -} - -blockquote, aside, .aside, .note, .alert, .blockquote { - padding: 1em; - border-left: 4px solid; - border-radius: 0 5px 5px 0; - font-size: 0.9em; - margin: 1em; -} - -blockquote, .blockquote { - background: var(--blockquote); - border-left: 4px solid var(--blockquote-border); -} - -blockquote p:last-of-type, .blockquote p:last-of-type, aside p:last-of-type, .aside p:last-of-type, .alert p:last-of-type, .note p:last-of-type { - margin-bottom: 0; -} - -blockquote p:first-of-type, .blockquote p:first-of-type, aside p:first-of-type, .aside p:first-of-type, .alert p:first-of-type, .note p:first-of-type { - margin-top: 0; -} - -blockquote cite, aside cite, .aside cite { - display: block; - text-align: right; - margin-top: 1em; -} - -aside, .aside { - background: var(--aside); - border-left: 4px solid var(--aside-border); -} - -.note { - background: var(--note); - border-left: 4px solid var(--note-border); - font-style: italic; -} - -@keyframes blinkBorder { - 0%, 100% { border-color: var(--alert-border); } /* Default border color */ - 50% { border-color: var(--alert); } /* Blink to black */ -} - -.alert { - background: var(--alert); - border-left: 4px solid var(--alert-border); - font-weight: bold; - animation: blinkBorder 2s infinite ease-in-out; -} - -div.highlight div { - border-radius: 5px; -} - -hr { - margin: 2em 0; - border: none; - text-align: center; -} - -hr::before { - content: "•••••"; - display: block; - color: var(--link); -} - -sup a { - text-decoration: none; -} - -.footnote-backref { - text-decoration: none; -} - -.microblog_conversation { - margin-top: 2em; - margin-bottom: 2em; -} - -.microblog_post { - margin-bottom: 1em; - padding: 1em; - border: 1px solid var(--code); - border-radius: 5px; -} - -.microblog_user { - font-weight: bold; -} - -.microblog_user img { - vertical-align: middle; - width: 40px; - height: auto; - border-radius: 40px; - max-width: 40px !important; -} - -.microblog_text img { - max-width: 100%; - border-radius: 5px; -} - -.microblog_time a, -.microblog_time a:visited { - color: var(--accent2); - font-size: 0.8em; - text-decoration: none; -} - -.microblog_narration_button { - color: var(--audio-link); -} - -.microblog_narration_button span { - vertical-align: baseline !important; -} - -footer { - margin-top: 2em; - text-align: center; -} - -footer .custom_footer { - font-size: 0.75em; - color: var(--accent2); -} - -footer .attribution { - display: none; -} - -footer i { - font-size: 1.5em; - padding: 0 5px; -} - -footer a i:hover { - color: var(--text); -} - -.full-archives { - overflow-wrap: anywhere; -} - -p>code, -li>code, -span.tinylytics_hits, -span.tinylytics_uptime { - background: var(--code); - padding: 2px 4px; - font-size: 0.9em; - border-radius: 5px; - font-family: var(--font_monospace_code); -} - -.tinylytics_countries { - font-size: 1.5em; - line-height: 1em; -} - -mark { - background: var(--mark); - color: var(); -} - -.tiny-img { - max-width: 25em; -} - -.tiny-text { - font-size: 0.6em; -} - -/* IF USING THE TINY THEME ADD ON FOR SUMMARY POSTS */ - -.p-summary { - margin-bottom: 2em; -} - -/* IFRAME FIX */ -iframe {max-width: 100%;} - -/* MAKES VIDEO EMBEDS THAT DON'T USE IFRAME RESPONSIVE. DOES NOT WORK WITH YOUTUBE. */ -video { - width: 100% !important; - height: auto !important; - background: var(--code); - border-radius: 5px; -} - -/* Styling specific to Tinylytics Plugin */ - -.did_select { - background: var(--link); - color: var(--button-text); - opacity: 0.8; - cursor: not-allowed; -} - -.tinylytics_webring { - align-items: center; - display: flex; - flex-direction: row; - gap: 3px; - justify-content: center; -} - -a.tinylytics_webring { - text-decoration: none; -} - -.tinylytics_webring_avatar { - width: auto; - height: 1.75em; - border-radius: 100%; -} - -/* STYLING TO TWEAK CODE BLOCKS (SYNTAX HIGHLIGHTING) */ - -.highlight { - font-size: 0.9em; - line-height: 1em; -} - -pre { - overflow: auto; - padding: 1em; -} - -/* OVERRIDING DEFAULT MICROBLOG AND PLUGIN CSS. Using !important isn't ideal, but it's the most effective for these things. */ - -.photos-grid-container { - grid-column-gap: 5px !important; -} - -input[type=text], -input[type=password], -input[type=email], -input[type=url], -input[type=tel], -input[type=search], -input[type=number], -textarea { - padding: 10px; - font-size: 0.9em; - border: 1px solid var(--link) !important; - border-radius: 5px !important; - color: var(--text); - display: block; - height: auto; - background: var(--field); - margin: 5px 0; -} - -input[type=submit], -button { - vertical-align: baseline; - padding: 5px 10px; - font-size: 0.9em; - border-radius: 5px; - border: 1px solid var(--link); - background: none; - color: var(--link); - -webkit-appearance: none; - margin-top: 5px; - font-weight: normal; - cursor: pointer; -} - -input[type=submit]:hover, -button:hover { - background: var(--link); - color: var(--button-text); -} - -label { - font-weight: bold; -} - -form p { - margin-bottom: 0; -} - -#search-space-info { - font-size: 0.9em; - font-style: italic; -} - -.bookshelf_book { - margin-bottom: 2em; -} - -.bookshelf_title { - font-weight: bold; -} - -.bigfoot-footnote__content { - color: #000; -} - -.microblog_shared_note { - background: red; - margin: 0 auto; - padding: 5px; - border-radius: 5px; - color: white; - width: fit-content; -} - -.blogroll li a { - color: var(--text); - text-decoration: none; -} - -.blogroll li a span { - color: var(--link); - text-decoration: underline; -} - -.blogroll li a span:hover { - text-decoration: none; -} - -.microblog_reply_textarea textarea { - width: calc(100% - 2em); - border-radius: 5px; - border: 1px solid var(--code); - padding: 1em; - font-size: 1em; -} - -.microblog_reply_button { - margin-top: 0; -} - -/* Adaptive Photo Layout Feature */ - -.adaptive_photo_layout ul { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); /* Flexible grid items */ - gap: 10px; /* Adds spacing between items */ - padding: 0; - margin: 0; - list-style: none; - align-items: start; /* Aligns items at the top of the container */ -} - -.adaptive_photo_layout li { - display: block; /* Block display for better control over individual items */ - width: 100%; - overflow: hidden; /* Keeps images within the boundaries */ - border-radius:5px; -} - -.adaptive_photo_layout img { - width: 100%; /* Ensures the image scales up to the container width */ - height: auto; /* Allows height to adjust naturally, preserving the image's aspect ratio */ - object-fit: cover; /* Covers the area, ensures no white space around images */ - vertical-align: bottom; - border-radius: 0; - transition: transform 0.3s ease, opacity 0.3s ease; /* Smooth transition for transform and opacity */ -} - -.adaptive_photo_layout img:hover { - transform: scale(1.05); /* Slightly enlarges the image */ - opacity: 0.9; /* Slightly reduces the opacity */ -} - -@media (max-aspect-ratio: 1/1) { - .adaptive_photo_layout li { - height: auto; /* Auto height for more natural flow */ - } -} - -@media (max-height: 480px) { - .adaptive_photo_layout li { - height: auto; /* Consistent with masonry style, allowing natural height */ - } -} - -@media (max-aspect-ratio: 1/1) and (max-width: 480px) { - .adaptive_photo_layout ul { - grid-template-columns: 100%; /* One column layout for very narrow screens */ - } - - .adaptive_photo_layout li { - height: auto; - } -} diff --git a/static/css/photos.css b/static/css/photos.css new file mode 100644 index 0000000..39d575f --- /dev/null +++ b/static/css/photos.css @@ -0,0 +1,221 @@ +/* CSS Variablen */ +:root { + --gap: 15px; + --max-width: 1400px; + --transition-speed: 0.2s; +} + +@media (max-width: 768px) { + :root { + --gap: 12px; + --radius: 6px; + } +} + +@media (max-width: 480px) { + :root { + --gap: 8px; + } +} + +/* Main Container */ +.photos.content { + max-width: none; + width: 100%; + margin: 0; + overscroll-behavior-y: contain; + -webkit-tap-highlight-color: transparent; +} + +/* Month Headers */ +.month-header { + font-size: 1.5rem; + font-weight: 600; + margin: 2rem 0 1rem; + padding-bottom: 0.5rem; + color: var(--accent1); + text-align: center; + display: flex; + align-items: center; + gap: 1.5rem; +} + +.month-header:first-child { + margin-top: 0; +} + +.month-header::before, +.month-header::after { + content: ''; + flex: 1; + height: 1px; + background: var(--accent2); + opacity: 0.3; +} + +/* Instagram-Style Grid */ +.photos-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + grid-gap: var(--gap); + margin-bottom: 2rem; +} + +@media (max-width: 768px) { + .photos-grid { + grid-template-columns: repeat(2, 1fr); + } +} + +/* Photo Tiles */ +.photo-tile { + position: relative; + aspect-ratio: 1 / 1; + overflow: hidden; + cursor: pointer; + transition: transform var(--transition-speed) ease, + box-shadow var(--transition-speed) ease; + display: block; + text-decoration: none; +} + +.photo-tile.keyboard-focused { + outline: 3px solid var(--link); + outline-offset: 4px; + border-radius: var(--radius-default); + transition: outline 0.2s ease; +} + +.photo-tile:hover { + transform: translateY(-4px); + box-shadow: 0 12px 24px rgba(0, 0, 0, 0.15); + z-index: 10; +} + +.photo-tile:active { + transform: translateY(-2px); +} + +/* Photo Images */ +.photo-tile img { + width: 100%; + height: 100%; + object-fit: cover; + display: block; +} + +/* Hover Overlay - Bottom-to-Mid Gradient */ +.photo-tile.has-title::before { + content: ''; + position: absolute; + inset: 0; + background: linear-gradient( + 0deg, + rgba(0, 0, 0, 0.65) 0%, + rgba(0, 0, 0, 0.48) 35%, + rgba(0, 0, 0, 0.18) 60%, + rgba(0, 0, 0, 0) 80% + ); + opacity: 0; + transition: opacity var(--transition-speed) ease; + pointer-events: none; + z-index: 1; +} + +.photo-tile.has-title:hover::before, +.photo-tile.has-title:focus-visible::before, +.photo-tile.has-title.show-info::before { + opacity: 1; +} + +/* Date Badge - Top Right */ +.date-badge { + position: absolute; + top: 10px; + right: 10px; + padding: 4px 8px; + font-size: 0.68rem; + font-weight: 500; + line-height: 1.2; + color: #ffffff; + background: rgba(0, 0, 0, 0.65); + border-radius: 999px; + opacity: 0; + transform: translateY(-6px); + transition: opacity var(--transition-speed) ease, + transform var(--transition-speed) ease; + pointer-events: none; + backdrop-filter: blur(6px); + z-index: 2; + white-space: nowrap; + letter-spacing: 0.01em; +} + +.photo-tile:hover .date-badge, +.photo-tile:focus-visible .date-badge, +.photo-tile.show-info .date-badge { + opacity: 1; + transform: translateY(0); +} + +/* Title Badge - Bottom mit sanftem Gradient */ +.title-badge { + position: absolute; + bottom: 0; + left: 0; + right: 0; + display: flex; + align-items: flex-end; + padding: 2.5rem 1rem 0.8rem; + font-size: 0.72rem; + font-weight: 500; + line-height: 1.35; + color: #ffffff; + background: linear-gradient(0deg, + rgba(0, 0, 0, 0.6) 0%, + rgba(0, 0, 0, 0.4) 40%, + rgba(0, 0, 0, 0.15) 75%, + transparent 100%); + border-radius: inherit; + opacity: 0; + transform: translateY(8px); + transition: opacity var(--transition-speed) ease, + transform var(--transition-speed) ease; + pointer-events: none; + z-index: 2; + white-space: normal; + overflow: hidden; + overflow-wrap: anywhere; + text-align: left; + text-shadow: 0 1px 3px rgba(0, 0, 0, 0.38); +} + +.photo-tile.has-title:hover .title-badge, +.photo-tile.has-title:focus-visible .title-badge, +.photo-tile.has-title.show-info .title-badge { + opacity: 1; + transform: translateY(0); +} + +/* Focus States für Accessibility */ +.photo-tile:focus-visible { + outline: 3px solid var(--link); + outline-offset: 3px; +} + +/* Dark Mode Support */ +@media (prefers-color-scheme: dark) { + .photo-tile { + background: var(--accent1); + } +} + +/* Reduced Motion */ +@media (prefers-reduced-motion: reduce) { + .photo-tile, + .photo-tile.has-title::before, + .date-badge, + .title-badge { + transition: none; + } +} diff --git a/static/img/404.webp b/static/img/404.webp new file mode 100644 index 0000000..1440eba Binary files /dev/null and b/static/img/404.webp differ diff --git a/static/img/avatar.jpg b/static/img/avatar.jpg new file mode 100644 index 0000000..75172e1 Binary files /dev/null and b/static/img/avatar.jpg differ diff --git a/static/img/favicon.png b/static/img/favicon.png new file mode 100644 index 0000000..27949b5 Binary files /dev/null and b/static/img/favicon.png differ diff --git a/static/js/404-redirect.js b/static/js/404-redirect.js new file mode 100644 index 0000000..f36e5ed --- /dev/null +++ b/static/js/404-redirect.js @@ -0,0 +1,37 @@ +/** + * 404 Page - Automatic Redirect with Countdown + * Redirects to /random after 6 seconds with visual countdown + */ + +(function() { + 'use strict'; + + const REDIRECT_DELAY = 6; // seconds + const REDIRECT_URL = '/random'; + + const countdownContainer = document.getElementById('countdown-container'); + const countdownElement = document.getElementById('countdown-value'); + + if (!countdownContainer || !countdownElement) { + return; + } + + // Show countdown container + countdownContainer.style.display = 'inline'; + + let seconds = REDIRECT_DELAY; + countdownElement.textContent = seconds; + + const interval = setInterval(() => { + seconds -= 1; + + if (seconds <= 0) { + countdownElement.textContent = '0'; + clearInterval(interval); + window.location.href = REDIRECT_URL; + return; + } + + countdownElement.textContent = seconds; + }, 1000); +})(); diff --git a/static/js/copy-code.js b/static/js/copy-code.js new file mode 100644 index 0000000..b42cd1e --- /dev/null +++ b/static/js/copy-code.js @@ -0,0 +1,192 @@ +// Add copy button to all code blocks with event delegation +(function() { + 'use strict'; + + // Constants + const SELECTORS = { + CODE_BLOCK: '.highlight', + COPY_BUTTON: '.copy-code-button', + CODE: 'pre code, pre' + }; + + const CLASSES = { + WRAPPER: 'code-block-wrapper', + BUTTON: 'copy-code-button', + COPIED: 'copied', + ERROR: 'error' + }; + + const MESSAGES = { + DEFAULT: 'Copy', + COPIED: 'Copied!', + FAILED: 'Copy failed', + EMPTY: 'Nothing to copy' + }; + + const FEEDBACK_DURATION = 2000; + + // Check clipboard capabilities + const hasClipboardAPI = typeof navigator !== 'undefined' && + navigator.clipboard && typeof navigator.clipboard.writeText === 'function'; + + let hasExecCommand = false; + if (typeof document !== 'undefined') { + if (typeof document.queryCommandSupported === 'function') { + try { + hasExecCommand = document.queryCommandSupported('copy'); + } catch (error) { + hasExecCommand = false; + } + } + + if (!hasExecCommand && typeof document.execCommand === 'function') { + hasExecCommand = true; + } + } + const canCopy = hasClipboardAPI || hasExecCommand; + + // Fallback copy method using execCommand + const copyWithFallback = (text) => { + return new Promise((resolve, reject) => { + const textarea = document.createElement('textarea'); + textarea.value = text; + textarea.setAttribute('readonly', ''); + textarea.style.position = 'absolute'; + textarea.style.left = '-9999px'; + document.body.appendChild(textarea); + + const selection = document.getSelection(); + const selectedRange = selection && selection.rangeCount > 0 ? selection.getRangeAt(0) : null; + + textarea.select(); + + try { + const successful = document.execCommand('copy'); + if (!successful) { + reject(new Error('Copy command was unsuccessful')); + } else { + resolve(); + } + } catch (error) { + reject(error); + } finally { + document.body.removeChild(textarea); + + if (selectedRange && selection) { + selection.removeAllRanges(); + selection.addRange(selectedRange); + } + } + }); + }; + + // Copy text to clipboard + const copyText = (text) => { + if (hasClipboardAPI) { + return navigator.clipboard.writeText(text); + } + + if (hasExecCommand) { + return copyWithFallback(text); + } + + return Promise.reject(new Error('Copy to clipboard is not supported')); + }; + + // Show temporary feedback message + const showTemporaryMessage = (button, message, className) => { + button.textContent = message; + if (className) { + button.classList.add(className); + } + + setTimeout(() => { + button.textContent = MESSAGES.DEFAULT; + if (className) { + button.classList.remove(className); + } + }, FEEDBACK_DURATION); + }; + + // Initialize code blocks with copy buttons + const initializeCodeBlocks = () => { + if (!canCopy) { + return; + } + + const codeBlocks = document.querySelectorAll(SELECTORS.CODE_BLOCK); + + codeBlocks.forEach((codeBlock) => { + // Skip if already wrapped + if (codeBlock.parentNode.classList.contains(CLASSES.WRAPPER)) { + return; + } + + // Create wrapper for positioning + const wrapper = document.createElement('div'); + wrapper.className = CLASSES.WRAPPER; + + // Wrap the code block + codeBlock.parentNode.insertBefore(wrapper, codeBlock); + wrapper.appendChild(codeBlock); + + // Create copy button + const copyButton = document.createElement('button'); + copyButton.className = CLASSES.BUTTON; + copyButton.type = 'button'; + copyButton.setAttribute('aria-label', 'Copy code'); + copyButton.setAttribute('aria-live', 'polite'); + copyButton.textContent = MESSAGES.DEFAULT; + + // Insert button before code block + wrapper.insertBefore(copyButton, codeBlock); + }); + }; + + // Event delegation: Handle all copy button clicks + const handleCopyClick = (event) => { + const button = event.target; + + // Check if clicked element is a copy button + if (!button.matches(SELECTORS.COPY_BUTTON)) { + return; + } + + event.preventDefault(); + + // Find the code block + const wrapper = button.closest('.' + CLASSES.WRAPPER); + if (!wrapper) { + return; + } + + const codeBlock = wrapper.querySelector(SELECTORS.CODE_BLOCK); + if (!codeBlock) { + return; + } + + const code = codeBlock.querySelector(SELECTORS.CODE); + const textToCopy = code ? code.textContent : ''; + + if (!textToCopy) { + showTemporaryMessage(button, MESSAGES.EMPTY, CLASSES.ERROR); + return; + } + + copyText(textToCopy) + .then(() => { + showTemporaryMessage(button, MESSAGES.COPIED, CLASSES.COPIED); + }) + .catch(() => { + showTemporaryMessage(button, MESSAGES.FAILED, CLASSES.ERROR); + }); + }; + + // Initialize on DOM ready + document.addEventListener('DOMContentLoaded', () => { + initializeCodeBlocks(); + + // Event delegation: Single event listener for all copy buttons + document.body.addEventListener('click', handleCopyClick); + }); +})(); diff --git a/static/js/count.js b/static/js/count.js new file mode 100644 index 0000000..b40052d --- /dev/null +++ b/static/js/count.js @@ -0,0 +1,267 @@ +// GoatCounter: https://www.goatcounter.com +// This file is released under the ISC license: https://opensource.org/licenses/ISC +;(function() { + 'use strict'; + + window.goatcounter = window.goatcounter || {} + + // Load settings from data-goatcounter-settings. + var s = document.querySelector('script[data-goatcounter]') + if (s && s.dataset.goatcounterSettings) { + try { var set = JSON.parse(s.dataset.goatcounterSettings) } + catch (err) { console.error('invalid JSON in data-goatcounter-settings: ' + err) } + for (var k in set) + if (['no_onload', 'no_events', 'allow_local', 'allow_frame', 'path', 'title', 'referrer', 'event'].indexOf(k) > -1) + window.goatcounter[k] = set[k] + } + + var enc = encodeURIComponent + + // Get all data we're going to send off to the counter endpoint. + window.goatcounter.get_data = function(vars) { + vars = vars || {} + var data = { + p: (vars.path === undefined ? goatcounter.path : vars.path), + r: (vars.referrer === undefined ? goatcounter.referrer : vars.referrer), + t: (vars.title === undefined ? goatcounter.title : vars.title), + e: !!(vars.event || goatcounter.event), + s: window.screen.width, + b: is_bot(), + q: location.search, + } + + var rcb, pcb, tcb // Save callbacks to apply later. + if (typeof(data.r) === 'function') rcb = data.r + if (typeof(data.t) === 'function') tcb = data.t + if (typeof(data.p) === 'function') pcb = data.p + + if (is_empty(data.r)) data.r = document.referrer + if (is_empty(data.t)) data.t = document.title + if (is_empty(data.p)) data.p = get_path() + + if (rcb) data.r = rcb(data.r) + if (tcb) data.t = tcb(data.t) + if (pcb) data.p = pcb(data.p) + return data + } + + // Check if a value is "empty" for the purpose of get_data(). + var is_empty = function(v) { return v === null || v === undefined || typeof(v) === 'function' } + + // See if this looks like a bot; there is some additional filtering on the + // backend, but these properties can't be fetched from there. + var is_bot = function() { + // Headless browsers are probably a bot. + var w = window, d = document + if (w.callPhantom || w._phantom || w.phantom) + return 150 + if (w.__nightmare) + return 151 + if (d.__selenium_unwrapped || d.__webdriver_evaluate || d.__driver_evaluate) + return 152 + if (navigator.webdriver) + return 153 + return 0 + } + + // Object to urlencoded string, starting with a ?. + var urlencode = function(obj) { + var p = [] + for (var k in obj) + if (obj[k] !== '' && obj[k] !== null && obj[k] !== undefined && obj[k] !== false) + p.push(enc(k) + '=' + enc(obj[k])) + return '?' + p.join('&') + } + + // Show a warning in the console. + var warn = function(msg) { + if (console && 'warn' in console) + console.warn('goatcounter: ' + msg) + } + + // Get the endpoint to send requests to. + var get_endpoint = function() { + var s = document.querySelector('script[data-goatcounter]') + return (s && s.dataset.goatcounter) ? s.dataset.goatcounter : goatcounter.endpoint + } + + // Get current path. + var get_path = function() { + var loc = location, + c = document.querySelector('link[rel="canonical"][href]') + if (c) { // May be relative or point to different domain. + var a = document.createElement('a') + a.href = c.href + if (a.hostname.replace(/^www\./, '') === location.hostname.replace(/^www\./, '')) + loc = a + } + return (loc.pathname + loc.search) || '/' + } + + // Run function after DOM is loaded. + var on_load = function(f) { + if (document.body === null) + document.addEventListener('DOMContentLoaded', function() { f() }, false) + else + f() + } + + // Filter some requests that we (probably) don't want to count. + window.goatcounter.filter = function() { + if ('visibilityState' in document && document.visibilityState === 'prerender') + return 'visibilityState' + if (!goatcounter.allow_frame && location !== parent.location) + return 'frame' + if (!goatcounter.allow_local && location.hostname.match(/(localhost$|^127\.|^10\.|^172\.(1[6-9]|2[0-9]|3[0-1])\.|^192\.168\.|^0\.0\.0\.0$)/)) + return 'localhost' + if (!goatcounter.allow_local && location.protocol === 'file:') + return 'localfile' + if (localStorage && localStorage.getItem('skipgc') === 't') + return 'disabled with #toggle-goatcounter' + return false + } + + // Get URL to send to GoatCounter. + window.goatcounter.url = function(vars) { + var data = window.goatcounter.get_data(vars || {}) + if (data.p === null) // null from user callback. + return + data.rnd = Math.random().toString(36).substr(2, 5) // Browsers don't always listen to Cache-Control. + + var endpoint = get_endpoint() + if (!endpoint) + return warn('no endpoint found') + + return endpoint + urlencode(data) + } + + // Count a hit. + window.goatcounter.count = function(vars) { + var f = goatcounter.filter() + if (f) + return warn('not counting because of: ' + f) + var url = goatcounter.url(vars) + if (!url) + return warn('not counting because path callback returned null') + + if (!navigator.sendBeacon(url)) { + // This mostly fails due to being blocked by CSP; try again with an + // image-based fallback. + var img = document.createElement('img') + img.src = url + img.style.position = 'absolute' // Affect layout less. + img.style.bottom = '0px' + img.style.width = '1px' + img.style.height = '1px' + img.loading = 'eager' + img.setAttribute('alt', '') + img.setAttribute('aria-hidden', 'true') + + var rm = function() { if (img && img.parentNode) img.parentNode.removeChild(img) } + img.addEventListener('load', rm, false) + document.body.appendChild(img) + } + } + + // Get a query parameter. + window.goatcounter.get_query = function(name) { + var s = location.search.substr(1).split('&') + for (var i = 0; i < s.length; i++) + if (s[i].toLowerCase().indexOf(name.toLowerCase() + '=') === 0) + return s[i].substr(name.length + 1) + } + + // Track click events. + window.goatcounter.bind_events = function() { + if (!document.querySelectorAll) // Just in case someone uses an ancient browser. + return + + var send = function(elem) { + return function() { + goatcounter.count({ + event: true, + path: (elem.dataset.goatcounterClick || elem.name || elem.id || ''), + title: (elem.dataset.goatcounterTitle || elem.title || (elem.innerHTML || '').substr(0, 200) || ''), + referrer: (elem.dataset.goatcounterReferrer || elem.dataset.goatcounterReferral || ''), + }) + } + } + + Array.prototype.slice.call(document.querySelectorAll("*[data-goatcounter-click]")).forEach(function(elem) { + if (elem.dataset.goatcounterBound) + return + var f = send(elem) + elem.addEventListener('click', f, false) + elem.addEventListener('auxclick', f, false) // Middle click. + elem.dataset.goatcounterBound = 'true' + }) + } + + // Add a "visitor counter" frame or image. + window.goatcounter.visit_count = function(opt) { + on_load(function() { + opt = opt || {} + opt.type = opt.type || 'html' + opt.append = opt.append || 'body' + opt.path = opt.path || get_path() + opt.attr = opt.attr || {width: '200', height: (opt.no_branding ? '60' : '80')} + + opt.attr['src'] = get_endpoint() + 'er/' + enc(opt.path) + '.' + enc(opt.type) + '?' + if (opt.no_branding) opt.attr['src'] += '&no_branding=1' + if (opt.style) opt.attr['src'] += '&style=' + enc(opt.style) + if (opt.start) opt.attr['src'] += '&start=' + enc(opt.start) + if (opt.end) opt.attr['src'] += '&end=' + enc(opt.end) + + var tag = {png: 'img', svg: 'img', html: 'iframe'}[opt.type] + if (!tag) + return warn('visit_count: unknown type: ' + opt.type) + + if (opt.type === 'html') { + opt.attr['frameborder'] = '0' + opt.attr['scrolling'] = 'no' + } + + var d = document.createElement(tag) + for (var k in opt.attr) + d.setAttribute(k, opt.attr[k]) + + var p = document.querySelector(opt.append) + if (!p) + return warn('visit_count: element to append to not found: ' + opt.append) + p.appendChild(d) + }) + } + + // Make it easy to skip your own views. + if (location.hash === '#toggle-goatcounter') { + if (localStorage.getItem('skipgc') === 't') { + localStorage.removeItem('skipgc', 't') + alert('GoatCounter tracking is now ENABLED in this browser.') + } + else { + localStorage.setItem('skipgc', 't') + alert('GoatCounter tracking is now DISABLED in this browser until ' + location + ' is loaded again.') + } + } + + if (!goatcounter.no_onload) + on_load(function() { + // 1. Page is visible, count request. + // 2. Page is not yet visible; wait until it switches to 'visible' and count. + // See #487 + if (!('visibilityState' in document) || document.visibilityState === 'visible') + goatcounter.count() + else { + var f = function(e) { + if (document.visibilityState !== 'visible') + return + document.removeEventListener('visibilitychange', f) + goatcounter.count() + } + document.addEventListener('visibilitychange', f) + } + + if (!goatcounter.no_events) + goatcounter.bind_events() + }) +})(); diff --git a/static/js/keyboard-shortcuts.js b/static/js/keyboard-shortcuts.js new file mode 100644 index 0000000..c7029de --- /dev/null +++ b/static/js/keyboard-shortcuts.js @@ -0,0 +1,597 @@ +/** + * Keyboard Shortcuts für bessere Navigation + * + * Bietet Tastatur-basierte Navigation für: + * - Post-Listen (j/k für vor/zurück) + * - Foto-Galerien (j/k für vor/zurück, n/p für Monate) + * - Seiten-Navigation (n/p für Pagination) + * - Utility-Funktionen (h für Home, t für Scroll-to-Top) + * - Hilfe-Overlay (? zum Anzeigen) + */ +(function() { + 'use strict'; + + /* ========================================================================= + STATE MANAGEMENT + ========================================================================= */ + + let currentPostIndex = -1; + let posts = []; + let photoTiles = []; + let monthSections = []; + let helpOverlay = null; + let previouslyFocusedElement = null; + let focusableElements = []; + let managedPageElements = []; + let currentPhotoIndex = -1; + + /* ========================================================================= + INITIALIZATION + ========================================================================= */ + + document.addEventListener('DOMContentLoaded', () => { + try { + // Sammle alle Post-Previews auf Listen-Seiten + posts = Array.from(document.querySelectorAll('.post-preview')); + + // Sammle alle Fotos in der Galerie + photoTiles = Array.from(document.querySelectorAll('.photo-tile')); + monthSections = Array.from(document.querySelectorAll('.month-section')); + + // Erstelle Hilfe-Overlay + createHelpOverlay(); + + // Keyboard Event Listener + document.addEventListener('keydown', handleKeyPress); + } catch (error) { + console.error('Error initializing keyboard shortcuts:', error); + } + }); + + /* ========================================================================= + EVENT HANDLERS + ========================================================================= */ + + const handleKeyPress = (e) => { + try { + // Ignoriere Tastatureingaben in Formularfeldern + if (e.target.tagName === 'INPUT' || + e.target.tagName === 'TEXTAREA' || + e.target.isContentEditable) { + return; + } + + // Verhindere Standardverhalten für unsere Shortcuts + const key = e.key.toLowerCase(); + + switch(key) { + case 'j': + e.preventDefault(); + if (photoTiles.length > 0) { + navigateToNextPhoto(); + } else { + navigateToNextPost(); + } + break; + + case 'k': + e.preventDefault(); + if (photoTiles.length > 0) { + navigateToPreviousPhoto(); + } else { + navigateToPreviousPost(); + } + break; + + case 'n': + e.preventDefault(); + if (photoTiles.length > 0 && navigateToMonth('next')) { + return; + } + navigateToPage('next'); + break; + + case 'p': + e.preventDefault(); + if (photoTiles.length > 0 && navigateToMonth('prev')) { + return; + } + navigateToPage('prev'); + break; + + case 'h': + e.preventDefault(); + window.location.href = '/'; + break; + + case 't': + e.preventDefault(); + scrollToTop(); + break; + + case '?': + e.preventDefault(); + toggleHelpOverlay(); + break; + + case 'escape': + e.preventDefault(); + closeHelpOverlay(); + break; + } + } catch (error) { + console.error('Error handling key press:', error); + } + }; + + /* ========================================================================= + POST NAVIGATION + ========================================================================= */ + + const navigateToNextPost = () => { + try { + if (posts.length === 0) return; + + currentPostIndex++; + if (currentPostIndex >= posts.length) { + currentPostIndex = posts.length - 1; + + // Versuche beim Erreichen des letzten Beitrags zur nächsten Seite zu wechseln + if (!navigateToPage('next')) { + return; + } + + return; + } + + scrollToPost(currentPostIndex); + } catch (error) { + console.error('Error navigating to next post:', error); + } + }; + + const navigateToPreviousPost = () => { + try { + if (posts.length === 0) return; + + currentPostIndex--; + if (currentPostIndex < 0) { + currentPostIndex = 0; + return; + } + + scrollToPost(currentPostIndex); + } catch (error) { + console.error('Error navigating to previous post:', error); + } + }; + + /* ========================================================================= + PHOTO NAVIGATION + ========================================================================= */ + + const navigateToNextPhoto = () => { + try { + if (photoTiles.length === 0) return; + + currentPhotoIndex++; + if (currentPhotoIndex >= photoTiles.length) { + currentPhotoIndex = photoTiles.length - 1; + } + + scrollToPhoto(currentPhotoIndex); + } catch (error) { + console.error('Error navigating to next photo:', error); + } + }; + + const navigateToPreviousPhoto = () => { + try { + if (photoTiles.length === 0) return; + + currentPhotoIndex--; + if (currentPhotoIndex < 0) { + currentPhotoIndex = 0; + return; + } + + scrollToPhoto(currentPhotoIndex); + } catch (error) { + console.error('Error navigating to previous photo:', error); + } + }; + + const scrollToPost = (index) => { + try { + if (posts[index]) { + posts[index].scrollIntoView({ + behavior: 'smooth', + block: 'start' + }); + + // Visuelles Feedback + highlightPost(posts[index]); + } + } catch (error) { + console.error('Error scrolling to post:', error); + } + }; + + const scrollToPhoto = (index) => { + try { + const tile = photoTiles[index]; + if (tile) { + tile.scrollIntoView({ + behavior: 'smooth', + block: 'center', + inline: 'center' + }); + + tile.focus({ preventScroll: true }); + + highlightPhoto(tile); + } + } catch (error) { + console.error('Error scrolling to photo:', error); + } + }; + + const highlightPost = (post) => { + try { + // Entferne vorherige Highlights + posts.forEach(p => p.classList.remove('keyboard-focused')); + + // Füge temporäres Highlight hinzu + post.classList.add('keyboard-focused'); + + // Entferne Highlight nach 1 Sekunde + setTimeout(() => { + post.classList.remove('keyboard-focused'); + }, 1000); + } catch (error) { + console.error('Error highlighting post:', error); + } + }; + + const highlightPhoto = (tile) => { + try { + photoTiles.forEach(photo => photo.classList.remove('keyboard-focused')); + + tile.classList.add('keyboard-focused'); + + setTimeout(() => { + tile.classList.remove('keyboard-focused'); + }, 1000); + } catch (error) { + console.error('Error highlighting photo:', error); + } + }; + + /* ========================================================================= + PAGE & MONTH NAVIGATION + ========================================================================= */ + + const navigateToPage = (direction) => { + try { + const nav = document.querySelector('.post-nav'); + if (!nav) return false; + + let link; + if (direction === 'next') { + link = nav.querySelector('.next a'); + } else if (direction === 'prev') { + link = nav.querySelector('.prev a'); + } + + if (link) { + window.location.href = link.href; + return true; + } + + return false; + } catch (error) { + console.error('Error navigating to page:', error); + return false; + } + }; + + const navigateToMonth = (direction) => { + try { + if (monthSections.length === 0) { + return false; + } + + const activeIndex = getActiveMonthIndex(); + let targetIndex = activeIndex; + + if (direction === 'next' && activeIndex < monthSections.length - 1) { + targetIndex = activeIndex + 1; + } else if (direction === 'prev' && activeIndex > 0) { + targetIndex = activeIndex - 1; + } else { + return false; + } + + const targetSection = monthSections[targetIndex]; + const header = targetSection.querySelector('.month-header'); + const targetElement = header || targetSection; + + if (targetElement) { + targetElement.scrollIntoView({ + behavior: 'smooth', + block: 'start' + }); + } + + const firstTile = targetSection.querySelector('.photo-tile'); + if (firstTile) { + const tileIndex = photoTiles.indexOf(firstTile); + if (tileIndex !== -1) { + currentPhotoIndex = tileIndex; + firstTile.focus({ preventScroll: true }); + highlightPhoto(firstTile); + } + } + + return true; + } catch (error) { + console.error('Error navigating to month:', error); + return false; + } + }; + + const getActiveMonthIndex = () => { + try { + const scrollPosition = window.scrollY; + let activeIndex = 0; + + monthSections.forEach((section, index) => { + const rect = section.getBoundingClientRect(); + const offsetTop = rect.top + window.scrollY; + + if (offsetTop - 100 <= scrollPosition) { + activeIndex = index; + } + }); + + return activeIndex; + } catch (error) { + console.error('Error getting active month index:', error); + return 0; + } + }; + + /* ========================================================================= + UTILITY FUNCTIONS + ========================================================================= */ + + const scrollToTop = () => { + try { + if (window.utils && window.utils.scrollToTop) { + window.utils.scrollToTop(); + } else { + // Fallback if utils.js is not loaded + window.scrollTo({ + top: 0, + behavior: 'smooth' + }); + } + } catch (error) { + console.error('Error scrolling to top:', error); + } + }; + + /* ========================================================================= + HELP OVERLAY + ========================================================================= */ + + const createHelpOverlay = () => { + try { + helpOverlay = document.createElement('div'); + helpOverlay.id = 'keyboard-shortcuts-help'; + helpOverlay.className = 'keyboard-help-overlay'; + helpOverlay.setAttribute('role', 'dialog'); + helpOverlay.setAttribute('aria-labelledby', 'shortcuts-title'); + helpOverlay.setAttribute('aria-modal', 'true'); + helpOverlay.setAttribute('aria-hidden', 'true'); + helpOverlay.setAttribute('tabindex', '-1'); + + helpOverlay.innerHTML = ` +
    +

    Tastatur-Shortcuts

    + + +
    +
    +

    Navigation

    +
    +
    j
    +
    Nächster Beitrag/Foto
    + +
    k
    +
    Vorheriger Beitrag/Foto
    + +
    n
    +
    Nächste Seite/Monat
    + +
    p
    +
    Vorherige Seite/Monat
    + +
    h
    +
    Zur Startseite
    +
    +
    + +
    +

    Aktionen

    +
    +
    t
    +
    Nach oben scrollen
    + +
    ?
    +
    Diese Hilfe anzeigen
    + +
    Esc
    +
    Hilfe schließen
    +
    +
    +
    +
    + `; + + document.body.appendChild(helpOverlay); + helpOverlay.style.display = 'none'; + + // Close Button Event + const closeBtn = helpOverlay.querySelector('.keyboard-help-close'); + closeBtn.addEventListener('click', closeHelpOverlay); + + // Click außerhalb schließt Overlay + helpOverlay.addEventListener('click', (e) => { + if (e.target === helpOverlay) { + closeHelpOverlay(); + } + }); + + helpOverlay.addEventListener('keydown', trapFocusInsideOverlay); + } catch (error) { + console.error('Error creating help overlay:', error); + } + }; + + const toggleHelpOverlay = () => { + try { + if (helpOverlay && helpOverlay.style.display === 'flex') { + closeHelpOverlay(); + } else { + openHelpOverlay(); + } + } catch (error) { + console.error('Error toggling help overlay:', error); + } + }; + + const openHelpOverlay = () => { + try { + if (!helpOverlay) return; + + previouslyFocusedElement = document.activeElement instanceof HTMLElement ? document.activeElement : null; + updateFocusableElements(); + helpOverlay.style.display = 'flex'; + helpOverlay.setAttribute('aria-hidden', 'false'); + setPageInert(true); + if (focusableElements.length > 0) { + focusableElements[0].focus(); + } else { + helpOverlay.focus(); + } + } catch (error) { + console.error('Error opening help overlay:', error); + } + }; + + const closeHelpOverlay = () => { + try { + if (!helpOverlay) return; + + helpOverlay.style.display = 'none'; + helpOverlay.setAttribute('aria-hidden', 'true'); + setPageInert(false); + if (previouslyFocusedElement) { + previouslyFocusedElement.focus(); + } + } catch (error) { + console.error('Error closing help overlay:', error); + } + }; + + const updateFocusableElements = () => { + try { + if (!helpOverlay) return; + + focusableElements = Array.from( + helpOverlay.querySelectorAll( + 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])' + ) + ).filter((element) => { + return !element.hasAttribute('disabled') && !element.getAttribute('aria-hidden'); + }); + } catch (error) { + console.error('Error updating focusable elements:', error); + } + }; + + const trapFocusInsideOverlay = (e) => { + try { + if (e.key !== 'Tab') { + return; + } + + updateFocusableElements(); + if (focusableElements.length === 0) { + e.preventDefault(); + helpOverlay.focus(); + return; + } + + const firstElement = focusableElements[0]; + const lastElement = focusableElements[focusableElements.length - 1]; + const isShiftPressed = e.shiftKey; + const activeElement = document.activeElement; + + if (!isShiftPressed && activeElement === lastElement) { + e.preventDefault(); + firstElement.focus(); + } else if (isShiftPressed && activeElement === firstElement) { + e.preventDefault(); + lastElement.focus(); + } + } catch (error) { + console.error('Error trapping focus:', error); + } + }; + + const setPageInert = (shouldInert) => { + try { + const bodyChildren = Array.from(document.body.children).filter((child) => { + return child !== helpOverlay; + }); + + if (shouldInert) { + managedPageElements = bodyChildren.map((child) => { + const record = { + element: child, + hadInert: 'inert' in child ? child.inert : null, + previousAriaHidden: child.getAttribute('aria-hidden') + }; + + if ('inert' in child) { + child.inert = true; + } else { + child.setAttribute('aria-hidden', 'true'); + } + + return record; + }); + } else { + managedPageElements.forEach((record) => { + const el = record.element; + if ('inert' in el && record.hadInert !== null) { + el.inert = record.hadInert; + } + + if (!('inert' in el)) { + if (record.previousAriaHidden === null) { + el.removeAttribute('aria-hidden'); + } else { + el.setAttribute('aria-hidden', record.previousAriaHidden); + } + } + }); + managedPageElements = []; + } + } catch (error) { + console.error('Error setting page inert:', error); + } + }; +})(); diff --git a/static/js/photo-gallery-mobile.js b/static/js/photo-gallery-mobile.js new file mode 100644 index 0000000..f965c44 --- /dev/null +++ b/static/js/photo-gallery-mobile.js @@ -0,0 +1,64 @@ +/** + * Mobile Touch Interaction für Foto-Galerie + * - Erster Tap: Zeigt Datum und Titel + * - Zweiter Tap: Navigiert zur Detailseite + * - Tap außerhalb: Schließt alle offenen Infos + */ + +(function() { + 'use strict'; + + // Prüfe ob Touch-Device + const isTouchDevice = 'ontouchstart' in window || navigator.maxTouchPoints > 0; + + if (!isTouchDevice) { + return; // Auf Desktop nichts machen, Hover funktioniert + } + + const photoTiles = document.querySelectorAll('.photo-tile'); + let currentlyOpen = null; + + // Handler für Photo-Tap + function handlePhotoTap(event) { + const tile = event.currentTarget; + + // Wenn dieses Foto bereits die Infos zeigt -> zweiter Tap -> Navigation erlauben + if (tile.classList.contains('show-info')) { + // Kein preventDefault, Link funktioniert normal + return; + } + + // Erster Tap -> Infos anzeigen + event.preventDefault(); + + // Schließe alle anderen geöffneten Infos + if (currentlyOpen && currentlyOpen !== tile) { + currentlyOpen.classList.remove('show-info'); + } + + // Zeige Infos für dieses Foto + tile.classList.add('show-info'); + currentlyOpen = tile; + } + + // Handler für Tap außerhalb + function handleOutsideTap(event) { + // Prüfe ob Tap auf ein Photo-Tile war + const clickedTile = event.target.closest('.photo-tile'); + + if (!clickedTile && currentlyOpen) { + // Tap war außerhalb -> Schließe alle Infos + currentlyOpen.classList.remove('show-info'); + currentlyOpen = null; + } + } + + // Event Listener hinzufügen + photoTiles.forEach(tile => { + tile.addEventListener('click', handlePhotoTap); + }); + + // Global listener für Taps außerhalb + document.addEventListener('click', handleOutsideTap); + +})(); diff --git a/static/js/scroll-to-top.js b/static/js/scroll-to-top.js new file mode 100644 index 0000000..c7c7b08 --- /dev/null +++ b/static/js/scroll-to-top.js @@ -0,0 +1,63 @@ +/** + * Scroll-to-Top Button + * Shows button after scrolling down 20px with progress indicator + */ + +(function() { + 'use strict'; + + const scrollButton = document.getElementById('myBtn'); + + if (!scrollButton) { + return; + } + + /** + * Scrolls to the top of the page using shared utility + */ + function scrollToTop() { + if (window.utils && window.utils.scrollToTop) { + window.utils.scrollToTop(scrollButton); + } else { + // Fallback if utils.js is not loaded + window.scrollTo({ + top: 0, + behavior: 'smooth' + }); + scrollButton.blur(); + } + } + + /** + * Updates button visibility and progress indicator based on scroll position + */ + function updateScrollButton() { + const docElement = document.documentElement; + const body = document.body; + const scrollTop = docElement.scrollTop || body.scrollTop; + const docHeight = docElement.scrollHeight - docElement.clientHeight; + + // Update progress indicator + if (docHeight > 0) { + const progress = Math.min((scrollTop / docHeight) * 100, 100); + scrollButton.style.setProperty('--scroll-progress', `${progress}%`); + } else { + scrollButton.style.setProperty('--scroll-progress', '100%'); + } + + // Show/hide button based on scroll position + if (scrollTop > 20) { + scrollButton.style.display = 'flex'; + } else { + scrollButton.style.display = 'none'; + scrollButton.blur(); + } + } + + // Event listeners + scrollButton.addEventListener('click', scrollToTop); + window.addEventListener('scroll', updateScrollButton, { passive: true }); + + // Initial state + updateScrollButton(); +})(); diff --git a/static/js/utils.js b/static/js/utils.js new file mode 100644 index 0000000..a946ffc --- /dev/null +++ b/static/js/utils.js @@ -0,0 +1,28 @@ +/** + * Shared Utility Functions + * Provides common functionality used across multiple scripts + */ + +(function(window) { + 'use strict'; + + // Create namespace for utilities + window.utils = window.utils || {}; + + /** + * Smoothly scrolls to the top of the page + * @param {HTMLElement} [elementToBlur] - Optional element to blur after scrolling + */ + window.utils.scrollToTop = function(elementToBlur) { + window.scrollTo({ + top: 0, + behavior: 'smooth' + }); + + // Optionally blur an element (useful for buttons) + if (elementToBlur && typeof elementToBlur.blur === 'function') { + elementToBlur.blur(); + } + }; + +})(window); diff --git a/static/version.txt b/static/version.txt deleted file mode 100644 index 885a808..0000000 --- a/static/version.txt +++ /dev/null @@ -1,3 +0,0 @@ -Tiny Theme for Micro.blog Version 2.9.7 -Created by Matt Langford (mattlangford.com) -Documentation: tiny.micro.blog diff --git a/static/webfonts/fa-brands-400.ttf b/static/webfonts/fa-brands-400.ttf deleted file mode 100644 index 0f82a83..0000000 Binary files a/static/webfonts/fa-brands-400.ttf and /dev/null differ diff --git a/static/webfonts/fa-brands-400.woff2 b/static/webfonts/fa-brands-400.woff2 deleted file mode 100644 index 3c5cf97..0000000 Binary files a/static/webfonts/fa-brands-400.woff2 and /dev/null differ diff --git a/static/webfonts/fa-regular-400.ttf b/static/webfonts/fa-regular-400.ttf deleted file mode 100644 index 9ee1919..0000000 Binary files a/static/webfonts/fa-regular-400.ttf and /dev/null differ diff --git a/static/webfonts/fa-regular-400.woff2 b/static/webfonts/fa-regular-400.woff2 deleted file mode 100644 index 57d9179..0000000 Binary files a/static/webfonts/fa-regular-400.woff2 and /dev/null differ diff --git a/static/webfonts/fa-solid-900.ttf b/static/webfonts/fa-solid-900.ttf deleted file mode 100644 index 1c10972..0000000 Binary files a/static/webfonts/fa-solid-900.ttf and /dev/null differ diff --git a/static/webfonts/fa-solid-900.woff2 b/static/webfonts/fa-solid-900.woff2 deleted file mode 100644 index 1672102..0000000 Binary files a/static/webfonts/fa-solid-900.woff2 and /dev/null differ diff --git a/static/webfonts/fa-v4compatibility.ttf b/static/webfonts/fa-v4compatibility.ttf deleted file mode 100644 index 3bcb67f..0000000 Binary files a/static/webfonts/fa-v4compatibility.ttf and /dev/null differ diff --git a/static/webfonts/fa-v4compatibility.woff2 b/static/webfonts/fa-v4compatibility.woff2 deleted file mode 100644 index fbafb22..0000000 Binary files a/static/webfonts/fa-v4compatibility.woff2 and /dev/null differ diff --git a/theme.toml b/theme.toml deleted file mode 100644 index e69de29..0000000