diff --git a/content/_index.md b/content/_index.md index 3614f39..a85616c 100644 --- a/content/_index.md +++ b/content/_index.md @@ -6,7 +6,7 @@ toc: false {{< hextra/hero-badge >}}
- Pre-Release 0.8.3 · Aktiv in Entwicklung + Pre-Release 0.8.2 · Aktiv in Entwicklung {{< /hextra/hero-badge >}}
@@ -23,7 +23,7 @@ toc: false
- Download · 0.8.3 (macOS) + Download · 0.8.2 (macOS) Quellcode ↗
diff --git a/content/docs/changelog.md b/content/docs/changelog.md index 5f87a69..d9e78a7 100644 --- a/content/docs/changelog.md +++ b/content/docs/changelog.md @@ -7,20 +7,20 @@ toc: true Versionsgeschichte von RAPPORT. Aktuelle Releases: [Gitea](https://git.kgva.ch/karim/RAPPORT/releases). -## 0.8.3 — Aktuelle Version Aktuell +## 0.8.2 — Aktuelle Version Aktuell Veröffentlicht am 2026-05-24. **Neu / Verbessert** -- Diverse Verbesserungen und Bugfixes (Details werden im [Release auf Gitea](https://git.kgva.ch/karim/RAPPORT/releases/tag/0.8.3) gepflegt) +- Diverse Verbesserungen und Bugfixes (Details werden im [Release auf Gitea](https://git.kgva.ch/karim/RAPPORT/releases/tag/0.8.2) gepflegt) **Bekannte Einschränkungen** - Builds sind Tauri-signiert, aber noch nicht Apple-notarisiert — siehe [Installation § Gatekeeper](../installation#3--erster-start-macos-gatekeeper) - Linux- und Windows-Builds noch nicht verfügbar -## 0.8.0–0.8.2 — Patch-Releases +## 0.8.0–0.8.1 — Patch-Releases Patch-Reihe mit kleineren Verbesserungen und Bugfixes. Details siehe [Releases auf Gitea](https://git.kgva.ch/karim/RAPPORT/releases). diff --git a/content/downloads/_index.md b/content/downloads/_index.md index df05579..ec488f4 100644 --- a/content/downloads/_index.md +++ b/content/downloads/_index.md @@ -11,22 +11,22 @@ Rapport besteht aus zwei Komponenten: | Komponente | Für wen | Aktuelle Version | |---|---|---| -| **Desktop-App** | Solo-Büro, lokale Datenhaltung | 0.8.3 | +| **Desktop-App** | Solo-Büro, lokale Datenhaltung | 0.8.2 | | **Rapport Server** | Team / Multi-User / Selfhost | 0.1.0 | --- -## Desktop-App — Pre-Release 0.8.3 +## Desktop-App — Pre-Release 0.8.2 Aktuelle Version -**Neuerungen** — siehe [Changelog](../docs/changelog#083) für Details. +**Neuerungen** — siehe [Changelog](../docs/changelog#082) für Details. ### macOS | Architektur | Download | |---|---| -| **Apple Silicon (M1–M4)** | [RAPPORT_0.8.3_aarch64.dmg](https://git.kgva.ch/karim/RAPPORT/releases/download/0.8.3/RAPPORT%20PRE-RELEASE_0.8.3_aarch64.dmg) | +| **Apple Silicon (M1–M4)** | [RAPPORT_0.8.2_aarch64.dmg](https://git.kgva.ch/karim/RAPPORT/releases/download/0.8.2/RAPPORT%20PRE-RELEASE_0.8.2_aarch64.dmg) | | **Intel (x86_64)** | [auf Anfrage](https://git.kgva.ch/karim/RAPPORT/issues/new) | > **Erstinstallation:** *Systemeinstellungen → Datenschutz & Sicherheit* öffnen und Rapport zulassen. Die Builds sind über Tauri signiert, aber (noch) nicht Apple-notarisiert. diff --git a/content/faq/_index.md b/content/faq/_index.md index 9a80a8d..c2e7682 100644 --- a/content/faq/_index.md +++ b/content/faq/_index.md @@ -30,7 +30,7 @@ In beiden Fällen bleibt die Kontrolle über die Daten bei dir. ## Ist die Software stabil genug für den Betrieb? -**Noch nicht.** Aktuell befindet sich Rapport in aktiver Entwicklung (Pre-Release **0.8.3**). Funktionen können sich ändern, Bugs sind möglich. Regelmässige Backups sind empfohlen. Testen und Feedback geben ist erwünscht. +**Noch nicht.** Aktuell befindet sich Rapport in aktiver Entwicklung (Pre-Release **0.8.2**). Funktionen können sich ändern, Bugs sind möglich. Regelmässige Backups sind empfohlen. Testen und Feedback geben ist erwünscht. ## Was ist mit dem QR-Einzahlungsschein? diff --git a/content/features/auto-updater.md b/content/features/auto-updater.md index f78a391..1102c23 100644 --- a/content/features/auto-updater.md +++ b/content/features/auto-updater.md @@ -36,13 +36,13 @@ Updates können in den Einstellungen komplett deaktiviert werden. ```json { - "version": "0.8.3", - "notes": "Rapport 0.8.3", + "version": "0.8.2", + "notes": "Rapport 0.8.2", "pub_date": "2026-05-24T00:00:00Z", "platforms": { "darwin-aarch64": { "signature": "…", - "url": "https://git.kgva.ch/karim/RAPPORT/releases/download/0.8.3/RAPPORT%20PRE-RELEASE.app.tar.gz" + "url": "https://git.kgva.ch/karim/RAPPORT/releases/download/0.8.2/RAPPORT%20PRE-RELEASE.app.tar.gz" } } } diff --git a/public/css/compiled/main.css b/public/css/compiled/main.css deleted file mode 100644 index a221a0b..0000000 --- a/public/css/compiled/main.css +++ /dev/null @@ -1,2 +0,0 @@ -/*! tailwindcss v4.3.0 | MIT License | https://tailwindcss.com */ -@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-border-style:solid;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-duration:initial;--tw-ease:initial;--tw-content:"";--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial}}}@layer theme{:root,:host{--hx-font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--hx-font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--hx-color-red-100:oklch(93.6% .032 17.717);--hx-color-red-200:oklch(88.5% .062 18.334);--hx-color-red-900:oklch(39.6% .141 25.723);--hx-color-orange-50:oklch(98% .016 73.684);--hx-color-orange-100:oklch(95.4% .038 75.164);--hx-color-orange-300:oklch(83.7% .128 66.29);--hx-color-orange-400:oklch(75% .183 55.934);--hx-color-orange-800:oklch(47% .157 37.304);--hx-color-amber-100:oklch(96.2% .059 95.617);--hx-color-amber-200:oklch(92.4% .12 95.746);--hx-color-amber-900:oklch(41.4% .112 45.904);--hx-color-yellow-50:oklch(98.7% .026 102.212);--hx-color-yellow-100:oklch(97.3% .071 103.193);--hx-color-yellow-200:oklch(94.5% .129 101.54);--hx-color-yellow-700:oklch(55.4% .135 66.442);--hx-color-yellow-900:oklch(42.1% .095 57.708);--hx-color-green-100:oklch(96.2% .044 156.743);--hx-color-green-200:oklch(92.5% .084 155.995);--hx-color-green-900:oklch(39.3% .095 152.535);--hx-color-blue-100:oklch(93.2% .032 255.585);--hx-color-blue-200:oklch(88.2% .059 254.128);--hx-color-blue-900:oklch(37.9% .146 265.522);--hx-color-indigo-100:oklch(93% .034 272.788);--hx-color-indigo-200:oklch(87% .065 274.039);--hx-color-indigo-900:oklch(35.9% .144 278.697);--hx-color-purple-100:oklch(94.6% .033 307.174);--hx-color-purple-200:oklch(90.2% .063 306.703);--hx-color-purple-900:oklch(38.1% .176 304.987);--hx-color-slate-50:oklch(98.4% .003 247.858);--hx-color-slate-100:oklch(96.8% .007 247.896);--hx-color-slate-900:oklch(20.8% .042 265.755);--hx-color-gray-50:oklch(98.5% .002 247.839);--hx-color-gray-100:oklch(96.7% .003 264.542);--hx-color-gray-200:oklch(92.8% .006 264.531);--hx-color-gray-300:oklch(87.2% .01 258.338);--hx-color-gray-400:oklch(70.7% .022 261.325);--hx-color-gray-500:oklch(55.1% .027 264.364);--hx-color-gray-600:oklch(44.6% .03 256.802);--hx-color-gray-700:oklch(37.3% .034 259.733);--hx-color-gray-800:oklch(27.8% .033 256.848);--hx-color-gray-900:oklch(21% .034 264.665);--hx-color-neutral-50:oklch(98.5% 0 0);--hx-color-neutral-200:oklch(92.2% 0 0);--hx-color-neutral-300:oklch(87% 0 0);--hx-color-neutral-400:oklch(70.8% 0 0);--hx-color-neutral-500:oklch(55.6% 0 0);--hx-color-neutral-600:oklch(43.9% 0 0);--hx-color-neutral-700:oklch(37.1% 0 0);--hx-color-neutral-800:oklch(26.9% 0 0);--hx-color-neutral-900:oklch(20.5% 0 0);--hx-color-black:#000;--hx-color-white:#fff;--hx-spacing:.25rem;--hx-breakpoint-xl:80rem;--hx-text-xs:.75rem;--hx-text-xs--line-height:calc(1 / .75);--hx-text-sm:.875rem;--hx-text-sm--line-height:calc(1.25 / .875);--hx-text-base:1rem;--hx-text-base--line-height:calc(1.5 / 1);--hx-text-lg:1.125rem;--hx-text-lg--line-height:calc(1.75 / 1.125);--hx-text-xl:1.25rem;--hx-text-xl--line-height:calc(1.75 / 1.25);--hx-text-2xl:1.5rem;--hx-text-2xl--line-height:calc(2 / 1.5);--hx-text-3xl:1.875rem;--hx-text-3xl--line-height:calc(2.25 / 1.875);--hx-text-4xl:2.25rem;--hx-text-4xl--line-height:calc(2.5 / 2.25);--hx-text-5xl:3rem;--hx-text-5xl--line-height:1;--hx-font-weight-normal:400;--hx-font-weight-medium:500;--hx-font-weight-semibold:600;--hx-font-weight-bold:700;--hx-font-weight-extrabold:800;--hx-tracking-tighter:-.05em;--hx-tracking-tight:-.025em;--hx-leading-tight:1.25;--hx-radius-xs:.125rem;--hx-radius-sm:.25rem;--hx-radius-md:.375rem;--hx-radius-lg:.5rem;--hx-radius-xl:.75rem;--hx-radius-3xl:1.5rem;--hx-ease-in:cubic-bezier(.4, 0, 1, 1);--hx-ease-out:cubic-bezier(0, 0, .2, 1);--hx-ease-in-out:cubic-bezier(.4, 0, .2, 1);--hx-blur-md:12px;--hx-default-transition-duration:.15s;--hx-default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--hx-default-font-family:var(--hx-font-sans);--hx-default-mono-font-family:var(--hx-font-mono);--hx-color-primary-100:hsl(var(--primary-hue) var(--primary-saturation) calc(var(--primary-lightness) + calc(calc(100% - var(--primary-lightness)) / 50) * 44));--hx-color-primary-200:hsl(var(--primary-hue) var(--primary-saturation) calc(var(--primary-lightness) + calc(calc(100% - var(--primary-lightness)) / 50) * 36));--hx-color-primary-300:hsl(var(--primary-hue) var(--primary-saturation) calc(var(--primary-lightness) + calc(calc(100% - var(--primary-lightness)) / 50) * 27));--hx-color-primary-400:hsl(var(--primary-hue) var(--primary-saturation) calc(var(--primary-lightness) + calc(calc(100% - var(--primary-lightness)) / 50) * 16));--hx-color-primary-500:hsl(var(--primary-hue) var(--primary-saturation) var(--primary-lightness));--hx-color-primary-600:hsl(var(--primary-hue) var(--primary-saturation) calc(calc(var(--primary-lightness) / 50) * 45));--hx-color-primary-700:hsl(var(--primary-hue) var(--primary-saturation) calc(calc(var(--primary-lightness) / 50) * 39));--hx-color-primary-800:hsl(var(--primary-hue) var(--primary-saturation) calc(calc(var(--primary-lightness) / 50) * 32));--hx-color-primary-900:hsl(var(--primary-hue) var(--primary-saturation) calc(calc(var(--primary-lightness) / 50) * 24));--hx-color-dark:#111}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--hx-default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--hx-default-font-feature-settings,normal);font-variation-settings:var(--hx-default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--hx-default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--hx-default-mono-font-feature-settings,normal);font-variation-settings:var(--hx-default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}abbr:where([title]){cursor:help}:where(a,button,[role=tab],[role=menuitem],[role=menuitemradio],input,select,textarea,[tabindex="0"]):not([class*=hextra-focus-visible]):focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--hx-color-primary-200);--tw-ring-offset-width:1px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-offset-color:var(--hx-color-primary-300);--tw-outline-style:none;outline-style:none}:where(a,button,[role=tab],[role=menuitem],[role=menuitemradio],input,select,textarea,[tabindex="0"]):not([class*=hextra-focus-visible]):focus-visible:where(.dark,.dark *){--tw-ring-color:var(--hx-color-primary-800);--tw-ring-offset-color:var(--hx-color-primary-700)}}@layer components;@layer utilities{.hx\:pointer-events-none{pointer-events:none}.hx\:sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.hx\:absolute{position:absolute}.hx\:relative{position:relative}.hx\:sticky{position:sticky}.hx\:inset-x-0{inset-inline:calc(var(--hx-spacing) * 0)}.hx\:inset-y-0{inset-block:calc(var(--hx-spacing) * 0)}.hx\:top-0{top:calc(var(--hx-spacing) * 0)}.hx\:top-1\/2{top:50%}.hx\:top-8{top:calc(var(--hx-spacing) * 8)}.hx\:top-16{top:calc(var(--hx-spacing) * 16)}.hx\:top-\[40\%\]{top:40%}.hx\:top-full{top:100%}.hx\:right-0{right:calc(var(--hx-spacing) * 0)}.hx\:bottom-0{bottom:calc(var(--hx-spacing) * 0)}.hx\:left-0{left:calc(var(--hx-spacing) * 0)}.hx\:left-\[24px\]{left:24px}.hx\:left-\[36px\]{left:36px}.hx\:z-20{z-index:20}.hx\:z-\[-1\]{z-index:-1}.hx\:order-last{order:9999}.hx\:m-\[11px\]{margin:11px}.hx\:mx-1{margin-inline:calc(var(--hx-spacing) * 1)}.hx\:mx-4{margin-inline:calc(var(--hx-spacing) * 4)}.hx\:mx-auto{margin-inline:auto}.hx\:my-1{margin-block:calc(var(--hx-spacing) * 1)}.hx\:my-1\.5{margin-block:calc(var(--hx-spacing) * 1.5)}.hx\:my-2{margin-block:calc(var(--hx-spacing) * 2)}.hx\:-mt-20{margin-top:calc(var(--hx-spacing) * -20)}.hx\:mt-1{margin-top:calc(var(--hx-spacing) * 1)}.hx\:mt-1\.5{margin-top:calc(var(--hx-spacing) * 1.5)}.hx\:mt-2{margin-top:calc(var(--hx-spacing) * 2)}.hx\:mt-4{margin-top:calc(var(--hx-spacing) * 4)}.hx\:mt-5{margin-top:calc(var(--hx-spacing) * 5)}.hx\:mt-6{margin-top:calc(var(--hx-spacing) * 6)}.hx\:mt-8{margin-top:calc(var(--hx-spacing) * 8)}.hx\:mt-12{margin-top:calc(var(--hx-spacing) * 12)}.hx\:mt-16{margin-top:calc(var(--hx-spacing) * 16)}.hx\:mt-auto{margin-top:auto}.hx\:-mr-2{margin-right:calc(var(--hx-spacing) * -2)}.hx\:mr-1{margin-right:calc(var(--hx-spacing) * 1)}.hx\:mr-2{margin-right:calc(var(--hx-spacing) * 2)}.hx\:-mb-0\.5{margin-bottom:calc(var(--hx-spacing) * -.5)}.hx\:mb-0{margin-bottom:calc(var(--hx-spacing) * 0)}.hx\:mb-2{margin-bottom:calc(var(--hx-spacing) * 2)}.hx\:mb-4{margin-bottom:calc(var(--hx-spacing) * 4)}.hx\:mb-6{margin-bottom:calc(var(--hx-spacing) * 6)}.hx\:mb-8{margin-bottom:calc(var(--hx-spacing) * 8)}.hx\:mb-10{margin-bottom:calc(var(--hx-spacing) * 10)}.hx\:mb-12{margin-bottom:calc(var(--hx-spacing) * 12)}.hx\:mb-16{margin-bottom:calc(var(--hx-spacing) * 16)}.hx\:-ml-2{margin-left:calc(var(--hx-spacing) * -2)}.hx\:ml-2{margin-left:calc(var(--hx-spacing) * 2)}.hx\:ml-4{margin-left:calc(var(--hx-spacing) * 4)}.hx\:line-clamp-3{-webkit-line-clamp:3;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.hx\:block{display:block}.hx\:flex{display:flex}.hx\:grid{display:grid}.hx\:hidden{display:none}.hx\:inline{display:inline}.hx\:inline-block{display:inline-block}.hx\:inline-flex{display:inline-flex}.hx\:aspect-auto{aspect-ratio:auto}.hx\:size-4{width:calc(var(--hx-spacing) * 4);height:calc(var(--hx-spacing) * 4)}.hx\:h-0{height:calc(var(--hx-spacing) * 0)}.hx\:h-2{height:calc(var(--hx-spacing) * 2)}.hx\:h-3\.5{height:calc(var(--hx-spacing) * 3.5)}.hx\:h-4{height:calc(var(--hx-spacing) * 4)}.hx\:h-5{height:calc(var(--hx-spacing) * 5)}.hx\:h-7{height:calc(var(--hx-spacing) * 7)}.hx\:h-10{height:calc(var(--hx-spacing) * 10)}.hx\:h-16{height:calc(var(--hx-spacing) * 16)}.hx\:h-\[18px\]{height:18px}.hx\:h-full{height:100%}.hx\:h-px{height:1px}.hx\:max-h-\(--menu-height\){max-height:var(--menu-height)}.hx\:max-h-64{max-height:calc(var(--hx-spacing) * 64)}.hx\:max-h-\[calc\(100vh-var\(--navbar-height\)-env\(safe-area-inset-bottom\)\)\]{max-height:calc(100vh - var(--navbar-height) - env(safe-area-inset-bottom))}.hx\:max-h-\[min\(calc\(50vh-11rem-env\(safe-area-inset-bottom\)\)\,400px\)\]{max-height:min(calc(50vh - 11rem - env(safe-area-inset-bottom)), 400px)}.hx\:min-h-\[100px\]{min-height:100px}.hx\:min-h-\[calc\(100vh-var\(--navbar-height\)\)\]{min-height:calc(100vh - var(--navbar-height))}.hx\:w-2{width:calc(var(--hx-spacing) * 2)}.hx\:w-3\.5{width:calc(var(--hx-spacing) * 3.5)}.hx\:w-4{width:calc(var(--hx-spacing) * 4)}.hx\:w-10{width:calc(var(--hx-spacing) * 10)}.hx\:w-64{width:calc(var(--hx-spacing) * 64)}.hx\:w-\[110\%\]{width:110%}.hx\:w-\[180\%\]{width:180%}.hx\:w-full{width:100%}.hx\:w-max{width:max-content}.hx\:w-screen{width:100vw}.hx\:max-w-\[50\%\]{max-width:50%}.hx\:max-w-\[90rem\]{max-width:90rem}.hx\:max-w-\[min\(calc\(100vw-2rem\)\,calc\(100\%\+20rem\)\)\]{max-width:min(100vw - 2rem,100% + 20rem)}.hx\:max-w-full{max-width:100%}.hx\:max-w-none{max-width:none}.hx\:max-w-screen-xl{max-width:var(--hx-breakpoint-xl)}.hx\:min-w-0{min-width:calc(var(--hx-spacing) * 0)}.hx\:min-w-\[18px\]{min-width:18px}.hx\:min-w-\[24px\]{min-width:24px}.hx\:min-w-full{min-width:100%}.hx\:shrink-0{flex-shrink:0}.hx\:grow{flex-grow:1}.hx\:origin-center{transform-origin:50%}.hx\:-translate-y-1\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.hx\:cursor-default{cursor:default}.hx\:cursor-pointer{cursor:pointer}.hx\:scroll-my-6{scroll-margin-block:calc(var(--hx-spacing) * 6)}.hx\:scroll-py-6{scroll-padding-block:calc(var(--hx-spacing) * 6)}.hx\:list-none{list-style-type:none}.hx\:appearance-none{appearance:none}.hx\:grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.hx\:flex-col{flex-direction:column}.hx\:flex-wrap{flex-wrap:wrap}.hx\:items-baseline{align-items:baseline}.hx\:items-center{align-items:center}.hx\:items-start{align-items:flex-start}.hx\:justify-between{justify-content:space-between}.hx\:justify-center{justify-content:center}.hx\:justify-end{justify-content:flex-end}.hx\:justify-start{justify-content:flex-start}.hx\:justify-items-start{justify-items:start}.hx\:gap-1{gap:calc(var(--hx-spacing) * 1)}.hx\:gap-1\.5{gap:calc(var(--hx-spacing) * 1.5)}.hx\:gap-2{gap:calc(var(--hx-spacing) * 2)}.hx\:gap-4{gap:calc(var(--hx-spacing) * 4)}.hx\:gap-x-1\.5{column-gap:calc(var(--hx-spacing) * 1.5)}.hx\:gap-x-2{column-gap:calc(var(--hx-spacing) * 2)}.hx\:gap-y-1{row-gap:calc(var(--hx-spacing) * 1)}.hx\:gap-y-2{row-gap:calc(var(--hx-spacing) * 2)}.hx\:overflow-auto{overflow:auto}.hx\:overflow-hidden{overflow:hidden}.hx\:overflow-x-auto{overflow-x:auto}.hx\:overflow-x-hidden{overflow-x:hidden}.hx\:overflow-y-auto{overflow-y:auto}.hx\:overflow-y-hidden{overflow-y:hidden}.hx\:overscroll-contain{overscroll-behavior:contain}.hx\:overscroll-x-contain{overscroll-behavior-x:contain}.hx\:rounded-3xl{border-radius:var(--hx-radius-3xl)}.hx\:rounded-full{border-radius:3.40282e38px}.hx\:rounded-lg{border-radius:var(--hx-radius-lg)}.hx\:rounded-md{border-radius:var(--hx-radius-md)}.hx\:rounded-sm{border-radius:var(--hx-radius-sm)}.hx\:rounded-xl{border-radius:var(--hx-radius-xl)}.hx\:rounded-xs{border-radius:var(--hx-radius-xs)}.hx\:rounded-t{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.hx\:border{border-style:var(--tw-border-style);border-width:1px}.hx\:border-0{border-style:var(--tw-border-style);border-width:0}.hx\:border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.hx\:border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.hx\:border-b-2{border-bottom-style:var(--tw-border-style);border-bottom-width:2px}.hx\:border-amber-200{border-color:var(--hx-color-amber-200)}.hx\:border-black\/5{border-color:var(--hx-color-black)}@supports (color:color-mix(in lab, red, red)){.hx\:border-black\/5{border-color:color-mix(in oklab, var(--hx-color-black) 5%, transparent)}}.hx\:border-blue-200{border-color:var(--hx-color-blue-200)}.hx\:border-gray-200{border-color:var(--hx-color-gray-200)}.hx\:border-gray-500{border-color:var(--hx-color-gray-500)}.hx\:border-green-200{border-color:var(--hx-color-green-200)}.hx\:border-indigo-200{border-color:var(--hx-color-indigo-200)}.hx\:border-orange-100{border-color:var(--hx-color-orange-100)}.hx\:border-purple-200{border-color:var(--hx-color-purple-200)}.hx\:border-red-200{border-color:var(--hx-color-red-200)}.hx\:border-transparent{border-color:#0000}.hx\:border-yellow-100{border-color:var(--hx-color-yellow-100)}.hx\:bg-amber-100{background-color:var(--hx-color-amber-100)}.hx\:bg-black\/\[\.05\]{background-color:var(--hx-color-black)}@supports (color:color-mix(in lab, red, red)){.hx\:bg-black\/\[\.05\]{background-color:color-mix(in oklab, var(--hx-color-black) 5%, transparent)}}.hx\:bg-blue-100{background-color:var(--hx-color-blue-100)}.hx\:bg-gray-100{background-color:var(--hx-color-gray-100)}.hx\:bg-gray-200{background-color:var(--hx-color-gray-200)}.hx\:bg-green-100{background-color:var(--hx-color-green-100)}.hx\:bg-indigo-100{background-color:var(--hx-color-indigo-100)}.hx\:bg-neutral-50{background-color:var(--hx-color-neutral-50)}.hx\:bg-neutral-900{background-color:var(--hx-color-neutral-900)}.hx\:bg-orange-50{background-color:var(--hx-color-orange-50)}.hx\:bg-primary-100{background-color:var(--hx-color-primary-100)}.hx\:bg-primary-400{background-color:var(--hx-color-primary-400)}.hx\:bg-primary-600{background-color:var(--hx-color-primary-600)}.hx\:bg-primary-700\/5{background-color:var(--hx-color-primary-700)}@supports (color:color-mix(in lab, red, red)){.hx\:bg-primary-700\/5{background-color:color-mix(in oklab, var(--hx-color-primary-700) 5%, transparent)}}.hx\:bg-purple-100{background-color:var(--hx-color-purple-100)}.hx\:bg-red-100{background-color:var(--hx-color-red-100)}.hx\:bg-transparent{background-color:#0000}.hx\:bg-white{background-color:var(--hx-color-white)}.hx\:bg-yellow-50{background-color:var(--hx-color-yellow-50)}.hx\:bg-gradient-to-r{--tw-gradient-position:to right in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.hx\:from-gray-900{--tw-gradient-from:var(--hx-color-gray-900);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.hx\:to-gray-600{--tw-gradient-to:var(--hx-color-gray-600);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.hx\:bg-clip-text{-webkit-background-clip:text;background-clip:text}.hx\:p-0{padding:calc(var(--hx-spacing) * 0)}.hx\:p-0\.5{padding:calc(var(--hx-spacing) * .5)}.hx\:p-1{padding:calc(var(--hx-spacing) * 1)}.hx\:p-1\.5{padding:calc(var(--hx-spacing) * 1.5)}.hx\:p-2{padding:calc(var(--hx-spacing) * 2)}.hx\:p-4{padding:calc(var(--hx-spacing) * 4)}.hx\:p-6{padding:calc(var(--hx-spacing) * 6)}.hx\:px-1\.5{padding-inline:calc(var(--hx-spacing) * 1.5)}.hx\:px-2{padding-inline:calc(var(--hx-spacing) * 2)}.hx\:px-2\.5{padding-inline:calc(var(--hx-spacing) * 2.5)}.hx\:px-3{padding-inline:calc(var(--hx-spacing) * 3)}.hx\:px-4{padding-inline:calc(var(--hx-spacing) * 4)}.hx\:px-6{padding-inline:calc(var(--hx-spacing) * 6)}.hx\:px-8{padding-inline:calc(var(--hx-spacing) * 8)}.hx\:py-1{padding-block:calc(var(--hx-spacing) * 1)}.hx\:py-1\.5{padding-block:calc(var(--hx-spacing) * 1.5)}.hx\:py-2{padding-block:calc(var(--hx-spacing) * 2)}.hx\:py-2\.5{padding-block:calc(var(--hx-spacing) * 2.5)}.hx\:py-3{padding-block:calc(var(--hx-spacing) * 3)}.hx\:py-4{padding-block:calc(var(--hx-spacing) * 4)}.hx\:py-12{padding-block:calc(var(--hx-spacing) * 12)}.hx\:pt-4{padding-top:calc(var(--hx-spacing) * 4)}.hx\:pt-6{padding-top:calc(var(--hx-spacing) * 6)}.hx\:pt-8{padding-top:calc(var(--hx-spacing) * 8)}.hx\:pr-2{padding-right:calc(var(--hx-spacing) * 2)}.hx\:pr-4{padding-right:calc(var(--hx-spacing) * 4)}.hx\:pr-\[calc\(env\(safe-area-inset-right\)-1\.5rem\)\]{padding-right:calc(env(safe-area-inset-right) - 1.5rem)}.hx\:pr-\[max\(env\(safe-area-inset-left\)\,1\.5rem\)\]{padding-right:max(env(safe-area-inset-left), 1.5rem)}.hx\:pr-\[max\(env\(safe-area-inset-right\)\,1\.5rem\)\]{padding-right:max(env(safe-area-inset-right), 1.5rem)}.hx\:pb-8{padding-bottom:calc(var(--hx-spacing) * 8)}.hx\:pb-\[env\(safe-area-inset-bottom\)\]{padding-bottom:env(safe-area-inset-bottom)}.hx\:pb-px{padding-bottom:1px}.hx\:pl-6{padding-left:calc(var(--hx-spacing) * 6)}.hx\:pl-\[max\(env\(safe-area-inset-left\)\,1\.5rem\)\]{padding-left:max(env(safe-area-inset-left), 1.5rem)}.hx\:text-center{text-align:center}.hx\:text-left{text-align:left}.hx\:align-\[-2\.5px\]{vertical-align:-2.5px}.hx\:align-baseline{vertical-align:baseline}.hx\:align-middle{vertical-align:middle}.hx\:align-text-bottom{vertical-align:text-bottom}.hx\:font-mono{font-family:var(--hx-font-mono)}.hx\:text-2xl{font-size:var(--hx-text-2xl);line-height:var(--tw-leading,var(--hx-text-2xl--line-height))}.hx\:text-4xl{font-size:var(--hx-text-4xl);line-height:var(--tw-leading,var(--hx-text-4xl--line-height))}.hx\:text-base{font-size:var(--hx-text-base);line-height:var(--tw-leading,var(--hx-text-base--line-height))}.hx\:text-lg{font-size:var(--hx-text-lg);line-height:var(--tw-leading,var(--hx-text-lg--line-height))}.hx\:text-sm{font-size:var(--hx-text-sm);line-height:var(--tw-leading,var(--hx-text-sm--line-height))}.hx\:text-xl{font-size:var(--hx-text-xl);line-height:var(--tw-leading,var(--hx-text-xl--line-height))}.hx\:text-xs{font-size:var(--hx-text-xs);line-height:var(--tw-leading,var(--hx-text-xs--line-height))}.hx\:text-\[\.65rem\]{font-size:.65rem}.hx\:text-\[10px\]{font-size:10px}.hx\:leading-5{--tw-leading:calc(var(--hx-spacing) * 5);line-height:calc(var(--hx-spacing) * 5)}.hx\:leading-6{--tw-leading:calc(var(--hx-spacing) * 6);line-height:calc(var(--hx-spacing) * 6)}.hx\:leading-7{--tw-leading:calc(var(--hx-spacing) * 7);line-height:calc(var(--hx-spacing) * 7)}.hx\:leading-none{--tw-leading:1;line-height:1}.hx\:leading-tight{--tw-leading:var(--hx-leading-tight);line-height:var(--hx-leading-tight)}.hx\:font-bold{--tw-font-weight:var(--hx-font-weight-bold);font-weight:var(--hx-font-weight-bold)}.hx\:font-extrabold{--tw-font-weight:var(--hx-font-weight-extrabold);font-weight:var(--hx-font-weight-extrabold)}.hx\:font-medium{--tw-font-weight:var(--hx-font-weight-medium);font-weight:var(--hx-font-weight-medium)}.hx\:font-normal{--tw-font-weight:var(--hx-font-weight-normal);font-weight:var(--hx-font-weight-normal)}.hx\:font-semibold{--tw-font-weight:var(--hx-font-weight-semibold);font-weight:var(--hx-font-weight-semibold)}.hx\:tracking-tight{--tw-tracking:var(--hx-tracking-tight);letter-spacing:var(--hx-tracking-tight)}.hx\:tracking-tighter{--tw-tracking:var(--hx-tracking-tighter);letter-spacing:var(--hx-tracking-tighter)}.hx\:break-words,.hx\:wrap-break-word{overflow-wrap:break-word}.hx\:text-ellipsis{text-overflow:ellipsis}.hx\:whitespace-nowrap{white-space:nowrap}.hx\:text-\[color\:hsl\(var\(--primary-hue\)\,100\%\,50\%\)\]{color:hsl(var(--primary-hue),100%,50%)}.hx\:text-amber-900{color:var(--hx-color-amber-900)}.hx\:text-blue-900{color:var(--hx-color-blue-900)}.hx\:text-current{color:currentColor}.hx\:text-gray-100{color:var(--hx-color-gray-100)}.hx\:text-gray-500{color:var(--hx-color-gray-500)}.hx\:text-gray-600{color:var(--hx-color-gray-600)}.hx\:text-gray-700{color:var(--hx-color-gray-700)}.hx\:text-gray-800{color:var(--hx-color-gray-800)}.hx\:text-gray-900{color:var(--hx-color-gray-900)}.hx\:text-green-900{color:var(--hx-color-green-900)}.hx\:text-indigo-900{color:var(--hx-color-indigo-900)}.hx\:text-orange-800{color:var(--hx-color-orange-800)}.hx\:text-primary-800{color:var(--hx-color-primary-800)}.hx\:text-purple-900{color:var(--hx-color-purple-900)}.hx\:text-red-900{color:var(--hx-color-red-900)}.hx\:text-slate-50{color:var(--hx-color-slate-50)}.hx\:text-slate-900{color:var(--hx-color-slate-900)}.hx\:text-transparent{color:#0000}.hx\:text-white{color:var(--hx-color-white)}.hx\:text-yellow-900{color:var(--hx-color-yellow-900)}.hx\:capitalize{text-transform:capitalize}.hx\:tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.hx\:no-underline{text-decoration-line:none}.hx\:underline{text-decoration-line:underline}.hx\:decoration-from-font{text-decoration-thickness:from-font}.hx\:underline-offset-2{text-underline-offset:2px}.hx\:opacity-0{opacity:0}.hx\:opacity-50{opacity:.5}.hx\:opacity-80{opacity:.8}.hx\:shadow-\[0_-12px_16px_\#fff\]{--tw-shadow:0 -12px 16px var(--tw-shadow-color,#fff);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.hx\:shadow-\[0_-12px_16px_white\]{--tw-shadow:0 -12px 16px var(--tw-shadow-color,white);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.hx\:shadow-\[0_2px_4px_rgba\(0\,0\,0\,\.02\)\,0_1px_0_rgba\(0\,0\,0\,\.06\)\]{--tw-shadow:0 2px 4px var(--tw-shadow-color,#00000005), 0 1px 0 var(--tw-shadow-color,#0000000f);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.hx\:shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.hx\:shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.hx\:shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a), 0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.hx\:shadow-xs{--tw-shadow:0 1px 2px 0 var(--tw-shadow-color,#0000000d);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.hx\:hextra-focus-visible:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--hx-color-primary-200);--tw-ring-offset-width:1px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-offset-color:var(--hx-color-primary-300);--tw-outline-style:none;outline-style:none}.hx\:hextra-focus-visible:where(.dark,.dark *):focus-visible{--tw-ring-color:var(--hx-color-primary-800);--tw-ring-offset-color:var(--hx-color-primary-700)}.hx\:hextra-focus-visible-inset:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--hx-color-primary-200);--tw-ring-offset-width:0px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-outline-style:none;--tw-ring-inset:inset;outline-style:none}.hx\:hextra-focus-visible-inset:where(.dark,.dark *):focus-visible{--tw-ring-color:var(--hx-color-primary-800)}.hx\:shadow-gray-100{--tw-shadow-color:var(--hx-color-gray-100)}@supports (color:color-mix(in lab, red, red)){.hx\:shadow-gray-100{--tw-shadow-color:color-mix(in oklab, var(--hx-color-gray-100) var(--tw-shadow-alpha), transparent)}}.hx\:transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--hx-default-transition-timing-function));transition-duration:var(--tw-duration,var(--hx-default-transition-duration))}.hx\:transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--hx-default-transition-timing-function));transition-duration:var(--tw-duration,var(--hx-default-transition-duration))}.hx\:transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--hx-default-transition-timing-function));transition-duration:var(--tw-duration,var(--hx-default-transition-duration))}.hx\:transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--hx-default-transition-timing-function));transition-duration:var(--tw-duration,var(--hx-default-transition-duration))}.hx\:transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--hx-default-transition-timing-function));transition-duration:var(--tw-duration,var(--hx-default-transition-duration))}.hx\:duration-75{--tw-duration:75ms;transition-duration:75ms}.hx\:duration-150{--tw-duration:.15s;transition-duration:.15s}.hx\:duration-200{--tw-duration:.2s;transition-duration:.2s}.hx\:ease-in{--tw-ease:var(--hx-ease-in);transition-timing-function:var(--hx-ease-in)}.hx\:ease-in-out{--tw-ease:var(--hx-ease-in-out);transition-timing-function:var(--hx-ease-in-out)}.hx\:outline-none{--tw-outline-style:none;outline-style:none}.hx\:select-none{-webkit-user-select:none;user-select:none}@media (hover:hover){.hx\:group-hover\:text-gray-900:is(:where(.hx\:group):hover *){color:var(--hx-color-gray-900)}.hx\:group-hover\:underline:is(:where(.hx\:group):hover *){text-decoration-line:underline}.hx\:group-hover\/code\:opacity-100:is(:where(.hx\:group\/code):hover *){opacity:1}}.hx\:group-data-\[active\=true\]\:text-primary-800:is(:where(.hx\:group)[data-active=true] *){color:var(--hx-color-primary-800)}.hx\:group-data-\[theme\=dark\]\:hidden:is(:where(.hx\:group)[data-theme=dark] *),.hx\:group-data-\[theme\=light\]\:hidden:is(:where(.hx\:group)[data-theme=light] *),.hx\:group-data-\[theme\=system\]\:hidden:is(:where(.hx\:group)[data-theme=system] *){display:none}.hx\:group-\[\.copied\]\/copybtn\:block:is(:where(.hx\:group\/copybtn).copied *){display:block}.hx\:group-\[\.copied\]\/copybtn\:hidden:is(:where(.hx\:group\/copybtn).copied *){display:none}.hx\:placeholder\:text-gray-500::placeholder{color:var(--hx-color-gray-500)}.hx\:before\:pointer-events-none:before{content:var(--tw-content);pointer-events:none}.hx\:before\:absolute:before{content:var(--tw-content);position:absolute}.hx\:before\:inset-0:before{content:var(--tw-content);inset:calc(var(--hx-spacing) * 0)}.hx\:before\:inset-y-1:before{content:var(--tw-content);inset-block:calc(var(--hx-spacing) * 1)}.hx\:before\:mr-1:before{content:var(--tw-content);margin-right:calc(var(--hx-spacing) * 1)}.hx\:before\:inline-block:before{content:var(--tw-content);display:inline-block}.hx\:before\:w-px:before{content:var(--tw-content);width:1px}.hx\:before\:bg-gray-200:before{content:var(--tw-content);background-color:var(--hx-color-gray-200)}.hx\:before\:opacity-25:before{content:var(--tw-content);opacity:.25}.hx\:before\:transition-transform:before{content:var(--tw-content);transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--hx-default-transition-timing-function));transition-duration:var(--tw-duration,var(--hx-default-transition-duration))}.hx\:before\:content-\[\"\"\]:before{--tw-content:"";content:var(--tw-content)}.hx\:before\:content-\[\'\#\'\]:before{--tw-content:"#";content:var(--tw-content)}.hx\:before\:content-\[\'\'\]:before{--tw-content:"";content:var(--tw-content)}.hx\:before\:content-\[\\\"\\\"\]:before{--tw-content:\"\";content:var(--tw-content)}.hx\:group-open\:before\:rotate-90:is(:where(.hx\:group):is([open],:popover-open,:open) *):before{content:var(--tw-content);rotate:90deg}.hx\:first\:mt-0:first-child{margin-top:calc(var(--hx-spacing) * 0)}.hx\:last-of-type\:mb-0:last-of-type{margin-bottom:calc(var(--hx-spacing) * 0)}@media (hover:hover){.hx\:hover\:border-gray-200:hover{border-color:var(--hx-color-gray-200)}.hx\:hover\:border-gray-300:hover{border-color:var(--hx-color-gray-300)}.hx\:hover\:border-gray-400:hover{border-color:var(--hx-color-gray-400)}.hx\:hover\:border-gray-900:hover{border-color:var(--hx-color-gray-900)}.hx\:hover\:bg-gray-100:hover{background-color:var(--hx-color-gray-100)}.hx\:hover\:bg-gray-800\/5:hover{background-color:var(--hx-color-gray-800)}@supports (color:color-mix(in lab, red, red)){.hx\:hover\:bg-gray-800\/5:hover{background-color:color-mix(in oklab, var(--hx-color-gray-800) 5%, transparent)}}.hx\:hover\:bg-primary-700:hover{background-color:var(--hx-color-primary-700)}.hx\:hover\:bg-slate-50:hover{background-color:var(--hx-color-slate-50)}.hx\:hover\:text-black:hover{color:var(--hx-color-black)}.hx\:hover\:text-gray-700:hover{color:var(--hx-color-gray-700)}.hx\:hover\:text-gray-800:hover{color:var(--hx-color-gray-800)}.hx\:hover\:text-gray-900:hover{color:var(--hx-color-gray-900)}.hx\:hover\:text-primary-600:hover{color:var(--hx-color-primary-600)}.hx\:hover\:opacity-60:hover{opacity:.6}.hx\:hover\:opacity-75:hover{opacity:.75}.hx\:hover\:shadow-lg:hover{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.hx\:hover\:shadow-md:hover{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a), 0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.hx\:hover\:shadow-gray-100:hover{--tw-shadow-color:var(--hx-color-gray-100)}@supports (color:color-mix(in lab, red, red)){.hx\:hover\:shadow-gray-100:hover{--tw-shadow-color:color-mix(in oklab, var(--hx-color-gray-100) var(--tw-shadow-alpha), transparent)}}}.hx\:focus-visible\:not-sr-only:focus-visible{clip-path:none;white-space:normal;width:auto;height:auto;margin:0;padding:0;position:static;overflow:visible}.hx\:focus-visible\:fixed:focus-visible{position:fixed}.hx\:focus-visible\:top-2:focus-visible{top:calc(var(--hx-spacing) * 2)}.hx\:focus-visible\:left-2:focus-visible{left:calc(var(--hx-spacing) * 2)}.hx\:focus-visible\:z-50:focus-visible{z-index:50}.hx\:focus-visible\:rounded-md:focus-visible{border-radius:var(--hx-radius-md)}.hx\:focus-visible\:bg-primary-500:focus-visible{background-color:var(--hx-color-primary-500)}.hx\:focus-visible\:bg-white:focus-visible{background-color:var(--hx-color-white)}.hx\:focus-visible\:px-4:focus-visible{padding-inline:calc(var(--hx-spacing) * 4)}.hx\:focus-visible\:py-2:focus-visible{padding-block:calc(var(--hx-spacing) * 2)}.hx\:focus-visible\:text-sm:focus-visible{font-size:var(--hx-text-sm);line-height:var(--tw-leading,var(--hx-text-sm--line-height))}.hx\:focus-visible\:font-medium:focus-visible{--tw-font-weight:var(--hx-font-weight-medium);font-weight:var(--hx-font-weight-medium)}.hx\:focus-visible\:text-white:focus-visible{color:var(--hx-color-white)}.hx\:active\:bg-gray-400\/20:active{background-color:var(--hx-color-gray-400)}@supports (color:color-mix(in lab, red, red)){.hx\:active\:bg-gray-400\/20:active{background-color:color-mix(in oklab, var(--hx-color-gray-400) 20%, transparent)}}.hx\:active\:opacity-50:active{opacity:.5}.hx\:active\:shadow-sm:active{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.hx\:active\:shadow-gray-200:active{--tw-shadow-color:var(--hx-color-gray-200)}@supports (color:color-mix(in lab, red, red)){.hx\:active\:shadow-gray-200:active{--tw-shadow-color:color-mix(in oklab, var(--hx-color-gray-200) var(--tw-shadow-alpha), transparent)}}.hx\:data-\[state\=closed\]\:hidden[data-state=closed],.hx\:data-\[state\=open\]\:hidden[data-state=open]{display:none}.hx\:data-\[state\=selected\]\:block[data-state=selected]{display:block}.hx\:data-\[state\=selected\]\:border-primary-500[data-state=selected]{border-color:var(--hx-color-primary-500)}.hx\:data-\[state\=selected\]\:text-primary-600[data-state=selected]{color:var(--hx-color-primary-600)}@media (prefers-contrast:more){.hx\:contrast-more\:border{border-style:var(--tw-border-style);border-width:1px}.hx\:contrast-more\:border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.hx\:contrast-more\:border-current{border-color:currentColor}.hx\:contrast-more\:border-gray-800{border-color:var(--hx-color-gray-800)}.hx\:contrast-more\:border-gray-900{border-color:var(--hx-color-gray-900)}.hx\:contrast-more\:border-neutral-400{border-color:var(--hx-color-neutral-400)}.hx\:contrast-more\:border-primary-500{border-color:var(--hx-color-primary-500)}.hx\:contrast-more\:border-transparent{border-color:#0000}.hx\:contrast-more\:font-bold{--tw-font-weight:var(--hx-font-weight-bold);font-weight:var(--hx-font-weight-bold)}.hx\:contrast-more\:text-current{color:currentColor}.hx\:contrast-more\:text-gray-700{color:var(--hx-color-gray-700)}.hx\:contrast-more\:text-gray-800{color:var(--hx-color-gray-800)}.hx\:contrast-more\:text-gray-900{color:var(--hx-color-gray-900)}.hx\:contrast-more\:underline{text-decoration-line:underline}.hx\:contrast-more\:shadow-\[0_0_0_1px_\#000\]{--tw-shadow:0 0 0 1px var(--tw-shadow-color,#000);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.hx\:contrast-more\:shadow-none{--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}@media (hover:hover){.hx\:contrast-more\:hover\:border-gray-900:hover{border-color:var(--hx-color-gray-900)}}}@media not all and (min-width:80rem){.hx\:max-xl\:hidden{display:none}}@media not all and (min-width:64rem){.hx\:max-lg\:min-h-\[340px\]{min-height:340px}}@media not all and (min-width:48rem){.hx\:max-md\:sticky{position:sticky}.hx\:max-md\:hidden{display:none}.hx\:max-md\:min-h-\[340px\]{min-height:340px}.hx\:max-md\:\[transform\:translate3d\(0\,-100\%\,0\)\]{transform:translateY(-100%)}.hx\:max-md\:\[transform\:translate3d\(0\,0\,0\)\]{transform:translate(0)}}@media not all and (min-width:40rem){.hx\:max-sm\:grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}}@media (min-width:40rem){.hx\:sm\:right-0{right:calc(var(--hx-spacing) * 0)}.hx\:sm\:left-auto{left:auto}.hx\:sm\:block{display:block}.hx\:sm\:flex{display:flex}.hx\:sm\:w-\[110\%\]{width:110%}.hx\:sm\:flex-row{flex-direction:row}.hx\:sm\:items-center{align-items:center}.hx\:sm\:items-start{align-items:flex-start}.hx\:sm\:justify-between{justify-content:space-between}.hx\:sm\:text-xl{font-size:var(--hx-text-xl);line-height:var(--tw-leading,var(--hx-text-xl--line-height))}@media not all and (min-width:64rem){.hx\:sm\:max-lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}}@media (min-width:48rem){.hx\:md\:sticky{position:sticky}.hx\:md\:top-16{top:calc(var(--hx-spacing) * 16)}.hx\:md\:mr-0{margin-right:calc(var(--hx-spacing) * 0)}.hx\:md\:hidden{display:none}.hx\:md\:inline-block{display:inline-block}.hx\:md\:inline-flex{display:inline-flex}.hx\:md\:aspect-\[1\.1\/1\]{aspect-ratio:1.1}.hx\:md\:h-\[calc\(100vh-var\(--navbar-height\)-var\(--menu-height\)\)\]{height:calc(100vh - var(--navbar-height) - var(--menu-height))}.hx\:md\:max-h-\[min\(calc\(100vh-5rem-env\(safe-area-inset-bottom\)\)\,400px\)\]{max-height:min(calc(100vh - 5rem - env(safe-area-inset-bottom)), 400px)}.hx\:md\:w-64{width:calc(var(--hx-spacing) * 64)}.hx\:md\:shrink-0{flex-shrink:0}.hx\:md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.hx\:md\:justify-start{justify-content:flex-start}.hx\:md\:self-start{align-self:flex-start}.hx\:md\:overflow-auto{overflow:auto}.hx\:md\:px-12{padding-inline:calc(var(--hx-spacing) * 12)}.hx\:md\:pt-12{padding-top:calc(var(--hx-spacing) * 12)}.hx\:md\:text-3xl{font-size:var(--hx-text-3xl);line-height:var(--tw-leading,var(--hx-text-3xl--line-height))}.hx\:md\:text-5xl{font-size:var(--hx-text-5xl);line-height:var(--tw-leading,var(--hx-text-5xl--line-height))}.hx\:md\:text-lg{font-size:var(--hx-text-lg);line-height:var(--tw-leading,var(--hx-text-lg--line-height))}.hx\:md\:text-sm{font-size:var(--hx-text-sm);line-height:var(--tw-leading,var(--hx-text-sm--line-height))}}@media (min-width:64rem){.hx\:lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media (min-width:80rem){.hx\:xl\:block{display:block}.hx\:xl\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}.hx\:ltr\:right-1\.5:where(:dir(ltr),[dir=ltr],[dir=ltr] *){right:calc(var(--hx-spacing) * 1.5)}.hx\:ltr\:right-2:where(:dir(ltr),[dir=ltr],[dir=ltr] *){right:calc(var(--hx-spacing) * 2)}.hx\:ltr\:right-3:where(:dir(ltr),[dir=ltr],[dir=ltr] *){right:calc(var(--hx-spacing) * 3)}.hx\:ltr\:-mr-4:where(:dir(ltr),[dir=ltr],[dir=ltr] *){margin-right:calc(var(--hx-spacing) * -4)}.hx\:ltr\:mr-auto:where(:dir(ltr),[dir=ltr],[dir=ltr] *){margin-right:auto}.hx\:ltr\:ml-1:where(:dir(ltr),[dir=ltr],[dir=ltr] *){margin-left:calc(var(--hx-spacing) * 1)}.hx\:ltr\:ml-3:where(:dir(ltr),[dir=ltr],[dir=ltr] *){margin-left:calc(var(--hx-spacing) * 3)}.hx\:ltr\:ml-auto:where(:dir(ltr),[dir=ltr],[dir=ltr] *){margin-left:auto}.hx\:ltr\:rotate-180:where(:dir(ltr),[dir=ltr],[dir=ltr] *){rotate:180deg}.hx\:ltr\:rounded-l-lg:where(:dir(ltr),[dir=ltr],[dir=ltr] *){border-top-left-radius:var(--hx-radius-lg);border-bottom-left-radius:var(--hx-radius-lg)}.hx\:ltr\:rounded-r-lg:where(:dir(ltr),[dir=ltr],[dir=ltr] *){border-top-right-radius:var(--hx-radius-lg);border-bottom-right-radius:var(--hx-radius-lg)}.hx\:ltr\:border-l:where(:dir(ltr),[dir=ltr],[dir=ltr] *){border-left-style:var(--tw-border-style);border-left-width:1px}.hx\:ltr\:pr-0:where(:dir(ltr),[dir=ltr],[dir=ltr] *){padding-right:calc(var(--hx-spacing) * 0)}.hx\:ltr\:pr-2:where(:dir(ltr),[dir=ltr],[dir=ltr] *){padding-right:calc(var(--hx-spacing) * 2)}.hx\:ltr\:pr-4:where(:dir(ltr),[dir=ltr],[dir=ltr] *){padding-right:calc(var(--hx-spacing) * 4)}.hx\:ltr\:pr-8:where(:dir(ltr),[dir=ltr],[dir=ltr] *){padding-right:calc(var(--hx-spacing) * 8)}.hx\:ltr\:pr-9:where(:dir(ltr),[dir=ltr],[dir=ltr] *){padding-right:calc(var(--hx-spacing) * 9)}.hx\:ltr\:pl-3:where(:dir(ltr),[dir=ltr],[dir=ltr] *){padding-left:calc(var(--hx-spacing) * 3)}.hx\:ltr\:pl-4:where(:dir(ltr),[dir=ltr],[dir=ltr] *){padding-left:calc(var(--hx-spacing) * 4)}.hx\:ltr\:pl-5:where(:dir(ltr),[dir=ltr],[dir=ltr] *){padding-left:calc(var(--hx-spacing) * 5)}.hx\:ltr\:pl-6:where(:dir(ltr),[dir=ltr],[dir=ltr] *){padding-left:calc(var(--hx-spacing) * 6)}.hx\:ltr\:pl-8:where(:dir(ltr),[dir=ltr],[dir=ltr] *){padding-left:calc(var(--hx-spacing) * 8)}.hx\:ltr\:pl-12:where(:dir(ltr),[dir=ltr],[dir=ltr] *){padding-left:calc(var(--hx-spacing) * 12)}.hx\:ltr\:pl-16:where(:dir(ltr),[dir=ltr],[dir=ltr] *){padding-left:calc(var(--hx-spacing) * 16)}.hx\:ltr\:text-right:where(:dir(ltr),[dir=ltr],[dir=ltr] *){text-align:right}.hx\:ltr\:before\:left-0:where(:dir(ltr),[dir=ltr],[dir=ltr] *):before{content:var(--tw-content);left:calc(var(--hx-spacing) * 0)}@media (min-width:48rem){.hx\:ltr\:md\:left-auto:where(:dir(ltr),[dir=ltr],[dir=ltr] *){left:auto}}.hx\:rtl\:left-1\.5:where(:dir(rtl),[dir=rtl],[dir=rtl] *){left:calc(var(--hx-spacing) * 1.5)}.hx\:rtl\:left-2:where(:dir(rtl),[dir=rtl],[dir=rtl] *){left:calc(var(--hx-spacing) * 2)}.hx\:rtl\:left-3:where(:dir(rtl),[dir=rtl],[dir=rtl] *){left:calc(var(--hx-spacing) * 3)}.hx\:rtl\:mr-1:where(:dir(rtl),[dir=rtl],[dir=rtl] *){margin-right:calc(var(--hx-spacing) * 1)}.hx\:rtl\:mr-3:where(:dir(rtl),[dir=rtl],[dir=rtl] *){margin-right:calc(var(--hx-spacing) * 3)}.hx\:rtl\:mr-auto:where(:dir(rtl),[dir=rtl],[dir=rtl] *){margin-right:auto}.hx\:rtl\:-ml-4:where(:dir(rtl),[dir=rtl],[dir=rtl] *){margin-left:calc(var(--hx-spacing) * -4)}.hx\:rtl\:ml-auto:where(:dir(rtl),[dir=rtl],[dir=rtl] *){margin-left:auto}.hx\:rtl\:-rotate-180:where(:dir(rtl),[dir=rtl],[dir=rtl] *){rotate:-180deg}.hx\:rtl\:rotate-270:where(:dir(rtl),[dir=rtl],[dir=rtl] *){rotate:270deg}.hx\:rtl\:rounded-l-lg:where(:dir(rtl),[dir=rtl],[dir=rtl] *){border-top-left-radius:var(--hx-radius-lg);border-bottom-left-radius:var(--hx-radius-lg)}.hx\:rtl\:rounded-r-lg:where(:dir(rtl),[dir=rtl],[dir=rtl] *){border-top-right-radius:var(--hx-radius-lg);border-bottom-right-radius:var(--hx-radius-lg)}.hx\:rtl\:border-r:where(:dir(rtl),[dir=rtl],[dir=rtl] *){border-right-style:var(--tw-border-style);border-right-width:1px}.hx\:rtl\:pr-3:where(:dir(rtl),[dir=rtl],[dir=rtl] *){padding-right:calc(var(--hx-spacing) * 3)}.hx\:rtl\:pr-4:where(:dir(rtl),[dir=rtl],[dir=rtl] *){padding-right:calc(var(--hx-spacing) * 4)}.hx\:rtl\:pr-5:where(:dir(rtl),[dir=rtl],[dir=rtl] *){padding-right:calc(var(--hx-spacing) * 5)}.hx\:rtl\:pr-6:where(:dir(rtl),[dir=rtl],[dir=rtl] *){padding-right:calc(var(--hx-spacing) * 6)}.hx\:rtl\:pr-8:where(:dir(rtl),[dir=rtl],[dir=rtl] *){padding-right:calc(var(--hx-spacing) * 8)}.hx\:rtl\:pr-12:where(:dir(rtl),[dir=rtl],[dir=rtl] *){padding-right:calc(var(--hx-spacing) * 12)}.hx\:rtl\:pr-16:where(:dir(rtl),[dir=rtl],[dir=rtl] *){padding-right:calc(var(--hx-spacing) * 16)}.hx\:rtl\:pl-0:where(:dir(rtl),[dir=rtl],[dir=rtl] *){padding-left:calc(var(--hx-spacing) * 0)}.hx\:rtl\:pl-2:where(:dir(rtl),[dir=rtl],[dir=rtl] *){padding-left:calc(var(--hx-spacing) * 2)}.hx\:rtl\:pl-4:where(:dir(rtl),[dir=rtl],[dir=rtl] *){padding-left:calc(var(--hx-spacing) * 4)}.hx\:rtl\:pl-8:where(:dir(rtl),[dir=rtl],[dir=rtl] *){padding-left:calc(var(--hx-spacing) * 8)}.hx\:rtl\:pl-9:where(:dir(rtl),[dir=rtl],[dir=rtl] *){padding-left:calc(var(--hx-spacing) * 9)}.hx\:rtl\:text-left:where(:dir(rtl),[dir=rtl],[dir=rtl] *){text-align:left}.hx\:rtl\:before\:right-0:where(:dir(rtl),[dir=rtl],[dir=rtl] *):before{content:var(--tw-content);right:calc(var(--hx-spacing) * 0)}.hx\:rtl\:before\:rotate-180:where(:dir(rtl),[dir=rtl],[dir=rtl] *):before{content:var(--tw-content);rotate:180deg}@media (min-width:48rem){.hx\:rtl\:md\:right-auto:where(:dir(rtl),[dir=rtl],[dir=rtl] *){right:auto}}.hx\:dark\:block:where(.dark,.dark *){display:block}.hx\:dark\:hidden:where(.dark,.dark *){display:none}.hx\:dark\:border-amber-200\/30:where(.dark,.dark *){border-color:var(--hx-color-amber-200)}@supports (color:color-mix(in lab, red, red)){.hx\:dark\:border-amber-200\/30:where(.dark,.dark *){border-color:color-mix(in oklab, var(--hx-color-amber-200) 30%, transparent)}}.hx\:dark\:border-blue-200\/30:where(.dark,.dark *){border-color:var(--hx-color-blue-200)}@supports (color:color-mix(in lab, red, red)){.hx\:dark\:border-blue-200\/30:where(.dark,.dark *){border-color:color-mix(in oklab, var(--hx-color-blue-200) 30%, transparent)}}.hx\:dark\:border-gray-100\/20:where(.dark,.dark *){border-color:var(--hx-color-gray-100)}@supports (color:color-mix(in lab, red, red)){.hx\:dark\:border-gray-100\/20:where(.dark,.dark *){border-color:color-mix(in oklab, var(--hx-color-gray-100) 20%, transparent)}}.hx\:dark\:border-gray-400:where(.dark,.dark *){border-color:var(--hx-color-gray-400)}.hx\:dark\:border-green-200\/30:where(.dark,.dark *){border-color:var(--hx-color-green-200)}@supports (color:color-mix(in lab, red, red)){.hx\:dark\:border-green-200\/30:where(.dark,.dark *){border-color:color-mix(in oklab, var(--hx-color-green-200) 30%, transparent)}}.hx\:dark\:border-indigo-200\/30:where(.dark,.dark *){border-color:var(--hx-color-indigo-200)}@supports (color:color-mix(in lab, red, red)){.hx\:dark\:border-indigo-200\/30:where(.dark,.dark *){border-color:color-mix(in oklab, var(--hx-color-indigo-200) 30%, transparent)}}.hx\:dark\:border-neutral-700:where(.dark,.dark *){border-color:var(--hx-color-neutral-700)}.hx\:dark\:border-neutral-800:where(.dark,.dark *){border-color:var(--hx-color-neutral-800)}.hx\:dark\:border-orange-400\/30:where(.dark,.dark *){border-color:var(--hx-color-orange-400)}@supports (color:color-mix(in lab, red, red)){.hx\:dark\:border-orange-400\/30:where(.dark,.dark *){border-color:color-mix(in oklab, var(--hx-color-orange-400) 30%, transparent)}}.hx\:dark\:border-purple-200\/30:where(.dark,.dark *){border-color:var(--hx-color-purple-200)}@supports (color:color-mix(in lab, red, red)){.hx\:dark\:border-purple-200\/30:where(.dark,.dark *){border-color:color-mix(in oklab, var(--hx-color-purple-200) 30%, transparent)}}.hx\:dark\:border-red-200\/30:where(.dark,.dark *){border-color:var(--hx-color-red-200)}@supports (color:color-mix(in lab, red, red)){.hx\:dark\:border-red-200\/30:where(.dark,.dark *){border-color:color-mix(in oklab, var(--hx-color-red-200) 30%, transparent)}}.hx\:dark\:border-white\/10:where(.dark,.dark *){border-color:var(--hx-color-white)}@supports (color:color-mix(in lab, red, red)){.hx\:dark\:border-white\/10:where(.dark,.dark *){border-color:color-mix(in oklab, var(--hx-color-white) 10%, transparent)}}.hx\:dark\:border-yellow-200\/30:where(.dark,.dark *){border-color:var(--hx-color-yellow-200)}@supports (color:color-mix(in lab, red, red)){.hx\:dark\:border-yellow-200\/30:where(.dark,.dark *){border-color:color-mix(in oklab, var(--hx-color-yellow-200) 30%, transparent)}}.hx\:dark\:bg-amber-900\/30:where(.dark,.dark *){background-color:var(--hx-color-amber-900)}@supports (color:color-mix(in lab, red, red)){.hx\:dark\:bg-amber-900\/30:where(.dark,.dark *){background-color:color-mix(in oklab, var(--hx-color-amber-900) 30%, transparent)}}.hx\:dark\:bg-blue-900\/30:where(.dark,.dark *){background-color:var(--hx-color-blue-900)}@supports (color:color-mix(in lab, red, red)){.hx\:dark\:bg-blue-900\/30:where(.dark,.dark *){background-color:color-mix(in oklab, var(--hx-color-blue-900) 30%, transparent)}}.hx\:dark\:bg-dark:where(.dark,.dark *),.hx\:dark\:bg-dark\/50:where(.dark,.dark *){background-color:var(--hx-color-dark)}@supports (color:color-mix(in lab, red, red)){.hx\:dark\:bg-dark\/50:where(.dark,.dark *){background-color:color-mix(in oklab, var(--hx-color-dark) 50%, transparent)}}.hx\:dark\:bg-gray-50\/10:where(.dark,.dark *){background-color:var(--hx-color-gray-50)}@supports (color:color-mix(in lab, red, red)){.hx\:dark\:bg-gray-50\/10:where(.dark,.dark *){background-color:color-mix(in oklab, var(--hx-color-gray-50) 10%, transparent)}}.hx\:dark\:bg-green-900\/30:where(.dark,.dark *){background-color:var(--hx-color-green-900)}@supports (color:color-mix(in lab, red, red)){.hx\:dark\:bg-green-900\/30:where(.dark,.dark *){background-color:color-mix(in oklab, var(--hx-color-green-900) 30%, transparent)}}.hx\:dark\:bg-indigo-900\/30:where(.dark,.dark *){background-color:var(--hx-color-indigo-900)}@supports (color:color-mix(in lab, red, red)){.hx\:dark\:bg-indigo-900\/30:where(.dark,.dark *){background-color:color-mix(in oklab, var(--hx-color-indigo-900) 30%, transparent)}}.hx\:dark\:bg-neutral-700:where(.dark,.dark *){background-color:var(--hx-color-neutral-700)}.hx\:dark\:bg-neutral-800:where(.dark,.dark *){background-color:var(--hx-color-neutral-800)}.hx\:dark\:bg-neutral-900:where(.dark,.dark *){background-color:var(--hx-color-neutral-900)}.hx\:dark\:bg-orange-400\/20:where(.dark,.dark *){background-color:var(--hx-color-orange-400)}@supports (color:color-mix(in lab, red, red)){.hx\:dark\:bg-orange-400\/20:where(.dark,.dark *){background-color:color-mix(in oklab, var(--hx-color-orange-400) 20%, transparent)}}.hx\:dark\:bg-primary-300\/10:where(.dark,.dark *){background-color:var(--hx-color-primary-300)}@supports (color:color-mix(in lab, red, red)){.hx\:dark\:bg-primary-300\/10:where(.dark,.dark *){background-color:color-mix(in oklab, var(--hx-color-primary-300) 10%, transparent)}}.hx\:dark\:bg-primary-400\/10:where(.dark,.dark *){background-color:var(--hx-color-primary-400)}@supports (color:color-mix(in lab, red, red)){.hx\:dark\:bg-primary-400\/10:where(.dark,.dark *){background-color:color-mix(in oklab, var(--hx-color-primary-400) 10%, transparent)}}.hx\:dark\:bg-primary-600:where(.dark,.dark *){background-color:var(--hx-color-primary-600)}.hx\:dark\:bg-purple-900\/30:where(.dark,.dark *){background-color:var(--hx-color-purple-900)}@supports (color:color-mix(in lab, red, red)){.hx\:dark\:bg-purple-900\/30:where(.dark,.dark *){background-color:color-mix(in oklab, var(--hx-color-purple-900) 30%, transparent)}}.hx\:dark\:bg-red-900\/30:where(.dark,.dark *){background-color:var(--hx-color-red-900)}@supports (color:color-mix(in lab, red, red)){.hx\:dark\:bg-red-900\/30:where(.dark,.dark *){background-color:color-mix(in oklab, var(--hx-color-red-900) 30%, transparent)}}.hx\:dark\:bg-yellow-700\/30:where(.dark,.dark *){background-color:var(--hx-color-yellow-700)}@supports (color:color-mix(in lab, red, red)){.hx\:dark\:bg-yellow-700\/30:where(.dark,.dark *){background-color:color-mix(in oklab, var(--hx-color-yellow-700) 30%, transparent)}}.hx\:dark\:from-gray-100:where(.dark,.dark *){--tw-gradient-from:var(--hx-color-gray-100);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.hx\:dark\:to-gray-400:where(.dark,.dark *){--tw-gradient-to:var(--hx-color-gray-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.hx\:dark\:text-amber-200:where(.dark,.dark *){color:var(--hx-color-amber-200)}.hx\:dark\:text-blue-200:where(.dark,.dark *){color:var(--hx-color-blue-200)}.hx\:dark\:text-gray-50:where(.dark,.dark *){color:var(--hx-color-gray-50)}.hx\:dark\:text-gray-100:where(.dark,.dark *){color:var(--hx-color-gray-100)}.hx\:dark\:text-gray-200:where(.dark,.dark *){color:var(--hx-color-gray-200)}.hx\:dark\:text-gray-300:where(.dark,.dark *){color:var(--hx-color-gray-300)}.hx\:dark\:text-gray-400:where(.dark,.dark *){color:var(--hx-color-gray-400)}.hx\:dark\:text-green-200:where(.dark,.dark *){color:var(--hx-color-green-200)}.hx\:dark\:text-indigo-200:where(.dark,.dark *){color:var(--hx-color-indigo-200)}.hx\:dark\:text-neutral-200:where(.dark,.dark *){color:var(--hx-color-neutral-200)}.hx\:dark\:text-neutral-400:where(.dark,.dark *){color:var(--hx-color-neutral-400)}.hx\:dark\:text-orange-300:where(.dark,.dark *){color:var(--hx-color-orange-300)}.hx\:dark\:text-primary-600:where(.dark,.dark *){color:var(--hx-color-primary-600)}.hx\:dark\:text-purple-200:where(.dark,.dark *){color:var(--hx-color-purple-200)}.hx\:dark\:text-red-200:where(.dark,.dark *){color:var(--hx-color-red-200)}.hx\:dark\:text-slate-100:where(.dark,.dark *){color:var(--hx-color-slate-100)}.hx\:dark\:text-white:where(.dark,.dark *){color:var(--hx-color-white)}.hx\:dark\:text-yellow-200:where(.dark,.dark *){color:var(--hx-color-yellow-200)}.hx\:dark\:opacity-80:where(.dark,.dark *){opacity:.8}.hx\:dark\:shadow-\[0_-1px_0_rgba\(255\,255\,255\,\.1\)_inset\]:where(.dark,.dark *){--tw-shadow:0 -1px 0 var(--tw-shadow-color,#ffffff1a) inset;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.hx\:dark\:shadow-\[0_-12px_16px_\#111\]:where(.dark,.dark *){--tw-shadow:0 -12px 16px var(--tw-shadow-color,#111);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.hx\:dark\:shadow-none:where(.dark,.dark *){--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}@media (hover:hover){.hx\:dark\:group-hover\:text-gray-50:where(.dark,.dark *):is(:where(.hx\:group):hover *){color:var(--hx-color-gray-50)}}.hx\:group-data-\[active\=true\]\:dark\:text-primary-600:is(:where(.hx\:group)[data-active=true] *):where(.dark,.dark *){color:var(--hx-color-primary-600)}.hx\:dark\:placeholder\:text-gray-400:where(.dark,.dark *)::placeholder{color:var(--hx-color-gray-400)}.hx\:dark\:before\:bg-neutral-800:where(.dark,.dark *):before{content:var(--tw-content);background-color:var(--hx-color-neutral-800)}.hx\:dark\:before\:invert:where(.dark,.dark *):before{content:var(--tw-content);--tw-invert:invert(100%);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}@media (hover:hover){.hx\:dark\:hover\:border-gray-100:where(.dark,.dark *):hover{border-color:var(--hx-color-gray-100)}.hx\:dark\:hover\:border-gray-600:where(.dark,.dark *):hover{border-color:var(--hx-color-gray-600)}.hx\:dark\:hover\:border-neutral-500:where(.dark,.dark *):hover{border-color:var(--hx-color-neutral-500)}.hx\:dark\:hover\:border-neutral-700:where(.dark,.dark *):hover{border-color:var(--hx-color-neutral-700)}.hx\:dark\:hover\:border-neutral-800:where(.dark,.dark *):hover{border-color:var(--hx-color-neutral-800)}.hx\:dark\:hover\:bg-gray-100\/5:where(.dark,.dark *):hover{background-color:var(--hx-color-gray-100)}@supports (color:color-mix(in lab, red, red)){.hx\:dark\:hover\:bg-gray-100\/5:where(.dark,.dark *):hover{background-color:color-mix(in oklab, var(--hx-color-gray-100) 5%, transparent)}}.hx\:dark\:hover\:bg-neutral-700:where(.dark,.dark *):hover{background-color:var(--hx-color-neutral-700)}.hx\:dark\:hover\:bg-neutral-800:where(.dark,.dark *):hover{background-color:var(--hx-color-neutral-800)}.hx\:dark\:hover\:bg-neutral-900:where(.dark,.dark *):hover{background-color:var(--hx-color-neutral-900)}.hx\:dark\:hover\:bg-primary-100\/5:where(.dark,.dark *):hover{background-color:var(--hx-color-primary-100)}@supports (color:color-mix(in lab, red, red)){.hx\:dark\:hover\:bg-primary-100\/5:where(.dark,.dark *):hover{background-color:color-mix(in oklab, var(--hx-color-primary-100) 5%, transparent)}}.hx\:dark\:hover\:bg-primary-700:where(.dark,.dark *):hover{background-color:var(--hx-color-primary-700)}.hx\:dark\:hover\:text-gray-50:where(.dark,.dark *):hover{color:var(--hx-color-gray-50)}.hx\:dark\:hover\:text-gray-100:where(.dark,.dark *):hover{color:var(--hx-color-gray-100)}.hx\:dark\:hover\:text-gray-200:where(.dark,.dark *):hover{color:var(--hx-color-gray-200)}.hx\:dark\:hover\:text-gray-300:where(.dark,.dark *):hover{color:var(--hx-color-gray-300)}.hx\:dark\:hover\:text-neutral-50:where(.dark,.dark *):hover{color:var(--hx-color-neutral-50)}.hx\:dark\:hover\:text-primary-400:where(.dark,.dark *):hover{color:var(--hx-color-primary-400)}.hx\:dark\:hover\:text-white:where(.dark,.dark *):hover{color:var(--hx-color-white)}.hx\:dark\:hover\:shadow-none:where(.dark,.dark *):hover{--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}}.hx\:dark\:focus-visible\:bg-dark:where(.dark,.dark *):focus-visible{background-color:var(--hx-color-dark)}.hx\:data-\[state\=selected\]\:dark\:border-primary-500[data-state=selected]:where(.dark,.dark *){border-color:var(--hx-color-primary-500)}.hx\:data-\[state\=selected\]\:dark\:text-primary-600[data-state=selected]:where(.dark,.dark *){color:var(--hx-color-primary-600)}@media (prefers-contrast:more){.hx\:contrast-more\:dark\:border-current:where(.dark,.dark *){border-color:currentColor}.hx\:contrast-more\:dark\:border-gray-50:where(.dark,.dark *){border-color:var(--hx-color-gray-50)}.hx\:contrast-more\:dark\:border-neutral-400:where(.dark,.dark *){border-color:var(--hx-color-neutral-400)}.hx\:contrast-more\:dark\:border-primary-500:where(.dark,.dark *){border-color:var(--hx-color-primary-500)}.hx\:dark\:contrast-more\:border-neutral-400:where(.dark,.dark *){border-color:var(--hx-color-neutral-400)}.hx\:contrast-more\:dark\:text-current:where(.dark,.dark *){color:currentColor}.hx\:contrast-more\:dark\:text-gray-50:where(.dark,.dark *){color:var(--hx-color-gray-50)}.hx\:contrast-more\:dark\:text-gray-100:where(.dark,.dark *){color:var(--hx-color-gray-100)}.hx\:contrast-more\:dark\:text-gray-300:where(.dark,.dark *){color:var(--hx-color-gray-300)}.hx\:contrast-more\:dark\:shadow-\[0_0_0_1px_\#fff\]:where(.dark,.dark *){--tw-shadow:0 0 0 1px var(--tw-shadow-color,#fff);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.hx\:contrast-more\:dark\:shadow-none:where(.dark,.dark *){--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}@media (hover:hover){.hx\:contrast-more\:dark\:hover\:border-gray-50:where(.dark,.dark *):hover{border-color:var(--hx-color-gray-50)}}}@media print{.hx\:print\:\[display\:none\],.hx\:print\:hidden{display:none}.hx\:print\:bg-transparent{background-color:#0000}}}html{font-size:var(--hx-text-base);line-height:var(--tw-leading,var(--hx-text-base--line-height));-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}body{background-color:var(--hx-color-white);width:100%}body:where(.dark,.dark *){background-color:var(--hx-color-dark);color:var(--hx-color-gray-100)}:root{--primary-hue:212deg;--primary-saturation:100%;--primary-lightness:50%;--navbar-height:4rem;--hextra-banner-height:2rem;--menu-height:3.75rem}.dark{--primary-hue:204deg;--primary-saturation:100%;--primary-lightness:50%}@media (prefers-reduced-motion:reduce){*,:before,:after{scroll-behavior:auto!important;transition-duration:.01ms!important;animation-duration:.01ms!important;animation-iteration-count:1!important}}.content :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:calc(var(--hx-spacing) * 2);font-size:var(--hx-text-4xl);line-height:var(--tw-leading,var(--hx-text-4xl--line-height));--tw-font-weight:var(--hx-font-weight-bold);font-weight:var(--hx-font-weight-bold);--tw-tracking:var(--hx-tracking-tight);letter-spacing:var(--hx-tracking-tight);color:var(--hx-color-slate-900)}.content :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)):where(.dark,.dark *){color:var(--hx-color-slate-100)}.content :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:calc(var(--hx-spacing) * 10);border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--hx-color-neutral-200)}@supports (color:color-mix(in lab, red, red)){.content :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){border-color:color-mix(in oklab, var(--hx-color-neutral-200) 70%, transparent)}}.content :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){padding-bottom:calc(var(--hx-spacing) * 1);font-size:var(--hx-text-3xl);line-height:var(--tw-leading,var(--hx-text-3xl--line-height));--tw-font-weight:var(--hx-font-weight-semibold);font-weight:var(--hx-font-weight-semibold);--tw-tracking:var(--hx-tracking-tight);letter-spacing:var(--hx-tracking-tight);color:var(--hx-color-slate-900)}@media (prefers-contrast:more){.content :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){border-color:var(--hx-color-neutral-400)}}.content :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)):where(.dark,.dark *){border-color:var(--hx-color-primary-100)}@supports (color:color-mix(in lab, red, red)){.content :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)):where(.dark,.dark *){border-color:color-mix(in oklab, var(--hx-color-primary-100) 10%, transparent)}}.content :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)):where(.dark,.dark *){color:var(--hx-color-slate-100)}@media (prefers-contrast:more){.content :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)):where(.dark,.dark *){border-color:var(--hx-color-neutral-400)}}.content :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:calc(var(--hx-spacing) * 8);font-size:var(--hx-text-2xl);line-height:var(--tw-leading,var(--hx-text-2xl--line-height));--tw-font-weight:var(--hx-font-weight-semibold);font-weight:var(--hx-font-weight-semibold);--tw-tracking:var(--hx-tracking-tight);letter-spacing:var(--hx-tracking-tight);color:var(--hx-color-slate-900)}.content :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)):where(.dark,.dark *){color:var(--hx-color-slate-100)}.content :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:calc(var(--hx-spacing) * 8);font-size:var(--hx-text-xl);line-height:var(--tw-leading,var(--hx-text-xl--line-height));--tw-font-weight:var(--hx-font-weight-semibold);font-weight:var(--hx-font-weight-semibold);--tw-tracking:var(--hx-tracking-tight);letter-spacing:var(--hx-tracking-tight);color:var(--hx-color-slate-900)}.content :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)):where(.dark,.dark *){color:var(--hx-color-slate-100)}.content :where(h5):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:calc(var(--hx-spacing) * 8);font-size:var(--hx-text-lg);line-height:var(--tw-leading,var(--hx-text-lg--line-height));--tw-font-weight:var(--hx-font-weight-semibold);font-weight:var(--hx-font-weight-semibold);--tw-tracking:var(--hx-tracking-tight);letter-spacing:var(--hx-tracking-tight);color:var(--hx-color-slate-900)}.content :where(h5):not(:where([class~=not-prose],[class~=not-prose] *)):where(.dark,.dark *){color:var(--hx-color-slate-100)}.content :where(h6):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:calc(var(--hx-spacing) * 8);font-size:var(--hx-text-base);line-height:var(--tw-leading,var(--hx-text-base--line-height));--tw-font-weight:var(--hx-font-weight-semibold);font-weight:var(--hx-font-weight-semibold);--tw-tracking:var(--hx-tracking-tight);letter-spacing:var(--hx-tracking-tight);color:var(--hx-color-slate-900)}.content :where(h6):not(:where([class~=not-prose],[class~=not-prose] *)):where(.dark,.dark *){color:var(--hx-color-slate-100)}.content :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:calc(var(--hx-spacing) * 6);--tw-leading:calc(var(--hx-spacing) * 7);line-height:calc(var(--hx-spacing) * 7)}.content :where(p):not(:where([class~=not-prose],[class~=not-prose] *)):first-child{margin-top:calc(var(--hx-spacing) * 0)}.content :where(a):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--hx-color-primary-600);text-decoration-line:underline;text-decoration-thickness:from-font}.content :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:calc(var(--hx-spacing) * 6);border-color:var(--hx-color-gray-300);color:var(--hx-color-gray-700);font-style:italic}.content :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)):first-child{margin-top:calc(var(--hx-spacing) * 0)}.content :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)):where(:dir(ltr),[dir=ltr],[dir=ltr] *){border-left-style:var(--tw-border-style);padding-left:calc(var(--hx-spacing) * 6);border-left-width:2px}.content :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)):where(:dir(rtl),[dir=rtl],[dir=rtl] *){border-right-style:var(--tw-border-style);padding-right:calc(var(--hx-spacing) * 6);border-right-width:2px}.content :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)):where(.dark,.dark *){border-color:var(--hx-color-gray-700);color:var(--hx-color-gray-400)}.content :where(pre):not(:where(.hextra-code-block pre,[class~=not-prose],[class~=not-prose] *)){margin-bottom:calc(var(--hx-spacing) * 4);border-radius:var(--hx-radius-xl);background-color:var(--hx-color-primary-700);overflow-x:auto}@supports (color:color-mix(in lab, red, red)){.content :where(pre):not(:where(.hextra-code-block pre,[class~=not-prose],[class~=not-prose] *)){background-color:color-mix(in oklab, var(--hx-color-primary-700) 5%, transparent)}}.content :where(pre):not(:where(.hextra-code-block pre,[class~=not-prose],[class~=not-prose] *)){padding-block:calc(var(--hx-spacing) * 4);--tw-font-weight:var(--hx-font-weight-medium);font-size:.9em;font-weight:var(--hx-font-weight-medium);-webkit-font-smoothing:auto;-moz-osx-font-smoothing:auto}@media (prefers-contrast:more){.content :where(pre):not(:where(.hextra-code-block pre,[class~=not-prose],[class~=not-prose] *)){border-style:var(--tw-border-style);border-width:1px;border-color:var(--hx-color-primary-900)}@supports (color:color-mix(in lab, red, red)){.content :where(pre):not(:where(.hextra-code-block pre,[class~=not-prose],[class~=not-prose] *)){border-color:color-mix(in oklab, var(--hx-color-primary-900) 20%, transparent)}}.content :where(pre):not(:where(.hextra-code-block pre,[class~=not-prose],[class~=not-prose] *)){--tw-contrast:contrast(150%);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}}.content :where(pre):not(:where(.hextra-code-block pre,[class~=not-prose],[class~=not-prose] *)):where(.dark,.dark *){background-color:var(--hx-color-primary-300)}@supports (color:color-mix(in lab, red, red)){.content :where(pre):not(:where(.hextra-code-block pre,[class~=not-prose],[class~=not-prose] *)):where(.dark,.dark *){background-color:color-mix(in oklab, var(--hx-color-primary-300) 10%, transparent)}}@media (prefers-contrast:more){.content :where(pre):not(:where(.hextra-code-block pre,[class~=not-prose],[class~=not-prose] *)):where(.dark,.dark *){border-color:var(--hx-color-primary-100)}@supports (color:color-mix(in lab, red, red)){.content :where(pre):not(:where(.hextra-code-block pre,[class~=not-prose],[class~=not-prose] *)):where(.dark,.dark *){border-color:color-mix(in oklab, var(--hx-color-primary-100) 40%, transparent)}}}.content :where(code):not(:where(.hextra-code-block code,[class~=not-prose],[class~=not-prose] *)){border-radius:var(--hx-radius-md);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hx-color-black)}@supports (color:color-mix(in lab, red, red)){.content :where(code):not(:where(.hextra-code-block code,[class~=not-prose],[class~=not-prose] *)){border-color:color-mix(in oklab, var(--hx-color-black) 4%, transparent)}}.content :where(code):not(:where(.hextra-code-block code,[class~=not-prose],[class~=not-prose] *)){background-color:var(--hx-color-black)}@supports (color:color-mix(in lab, red, red)){.content :where(code):not(:where(.hextra-code-block code,[class~=not-prose],[class~=not-prose] *)){background-color:color-mix(in oklab, var(--hx-color-black) 3%, transparent)}}.content :where(code):not(:where(.hextra-code-block code,[class~=not-prose],[class~=not-prose] *)){padding-inline:.25em;padding-block:calc(var(--hx-spacing) * .5);overflow-wrap:break-word;font-size:.9em}.content :where(code):not(:where(.hextra-code-block code,[class~=not-prose],[class~=not-prose] *)):where(.dark,.dark *){border-color:var(--hx-color-white)}@supports (color:color-mix(in lab, red, red)){.content :where(code):not(:where(.hextra-code-block code,[class~=not-prose],[class~=not-prose] *)):where(.dark,.dark *){border-color:color-mix(in oklab, var(--hx-color-white) 10%, transparent)}}.content :where(code):not(:where(.hextra-code-block code,[class~=not-prose],[class~=not-prose] *)):where(.dark,.dark *){background-color:var(--hx-color-white)}@supports (color:color-mix(in lab, red, red)){.content :where(code):not(:where(.hextra-code-block code,[class~=not-prose],[class~=not-prose] *)):where(.dark,.dark *){background-color:color-mix(in oklab, var(--hx-color-white) 10%, transparent)}}.content :where(table):not(:where(.hextra-code-block table,[class~=not-prose],[class~=not-prose] *)){margin-block:calc(var(--hx-spacing) * 6);border-collapse:collapse;width:100%;padding:calc(var(--hx-spacing) * 0);font-size:var(--hx-text-sm);line-height:var(--tw-leading,var(--hx-text-sm--line-height));--tw-leading:calc(var(--hx-spacing) * 5);line-height:calc(var(--hx-spacing) * 5);display:block;overflow-x:auto}.content :where(table):not(:where(.hextra-code-block table,[class~=not-prose],[class~=not-prose] *)):first-child{margin-top:calc(var(--hx-spacing) * 0)}.content :where(table):not(:where(.hextra-code-block table,[class~=not-prose],[class~=not-prose] *)) thead{background-color:var(--hx-color-gray-50)}.content :where(table):not(:where(.hextra-code-block table,[class~=not-prose],[class~=not-prose] *)) thead:where(.dark,.dark *){background-color:var(--hx-color-gray-600)}@supports (color:color-mix(in lab, red, red)){.content :where(table):not(:where(.hextra-code-block table,[class~=not-prose],[class~=not-prose] *)) thead:where(.dark,.dark *){background-color:color-mix(in oklab, var(--hx-color-gray-600) 20%, transparent)}}.content :where(table):not(:where(.hextra-code-block table,[class~=not-prose],[class~=not-prose] *)) tr{margin:calc(var(--hx-spacing) * 0);border-top-style:var(--tw-border-style);border-top-width:1px;border-color:var(--hx-color-gray-300);padding:calc(var(--hx-spacing) * 0)}.content :where(table):not(:where(.hextra-code-block table,[class~=not-prose],[class~=not-prose] *)) tr:where(.dark,.dark *){border-color:var(--hx-color-gray-600)}.content :where(table):not(:where(.hextra-code-block table,[class~=not-prose],[class~=not-prose] *)) th{margin:calc(var(--hx-spacing) * 0);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hx-color-gray-300);padding:calc(var(--hx-spacing) * 2);--tw-font-weight:var(--hx-font-weight-semibold);font-weight:var(--hx-font-weight-semibold)}.content :where(table):not(:where(.hextra-code-block table,[class~=not-prose],[class~=not-prose] *)) th:where(.dark,.dark *){border-color:var(--hx-color-gray-600)}.content :where(table):not(:where(.hextra-code-block table,[class~=not-prose],[class~=not-prose] *)) td{margin:calc(var(--hx-spacing) * 0);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hx-color-gray-300);padding:calc(var(--hx-spacing) * 2)}.content :where(table):not(:where(.hextra-code-block table,[class~=not-prose],[class~=not-prose] *)) td:where(.dark,.dark *){border-color:var(--hx-color-gray-600)}.content :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:calc(var(--hx-spacing) * 6);list-style-type:decimal}.content :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)):first-child{margin-top:calc(var(--hx-spacing) * 0)}.content :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)):where(:dir(ltr),[dir=ltr],[dir=ltr] *){margin-left:calc(var(--hx-spacing) * 6)}.content :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)):where(:dir(rtl),[dir=rtl],[dir=rtl] *){margin-right:calc(var(--hx-spacing) * 6)}.content :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)) li{margin-block:calc(var(--hx-spacing) * 2)}.content :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:calc(var(--hx-spacing) * 6);list-style-type:disc}.content :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)):first-child{margin-top:calc(var(--hx-spacing) * 0)}.content :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)):where(:dir(ltr),[dir=ltr],[dir=ltr] *){margin-left:calc(var(--hx-spacing) * 6)}.content :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)):where(:dir(rtl),[dir=rtl],[dir=rtl] *){margin-right:calc(var(--hx-spacing) * 6)}.content :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)) li{margin-block:calc(var(--hx-spacing) * 2)}.content :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)):has(li input[type=checkbox]){list-style-type:none}.content :where(ul,ol)>li>:where(ul,ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:calc(var(--hx-spacing) * 0)}.content :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){border-radius:var(--hx-radius-md);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hx-color-black)}@supports (color:color-mix(in lab, red, red)){.content :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){border-color:color-mix(in oklab, var(--hx-color-black) 4%, transparent)}}.content :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:var(--hx-color-black)}@supports (color:color-mix(in lab, red, red)){.content :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:color-mix(in oklab, var(--hx-color-black) 3%, transparent)}}.content :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline:.25em;padding-block:calc(var(--hx-spacing) * .5);overflow-wrap:break-word;font-size:.9em}.content :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)):where(.dark,.dark *){border-color:var(--hx-color-white)}@supports (color:color-mix(in lab, red, red)){.content :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)):where(.dark,.dark *){border-color:color-mix(in oklab, var(--hx-color-white) 10%, transparent)}}.content :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)):where(.dark,.dark *){background-color:var(--hx-color-white)}@supports (color:color-mix(in lab, red, red)){.content :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)):where(.dark,.dark *){background-color:color-mix(in oklab, var(--hx-color-white) 10%, transparent)}}.content :where(pre.mermaid):not(:where(.hextra-code-block pre,[class~=not-prose],[class~=not-prose] *)){background-color:#0000;border-radius:0}.content :where(pre.mermaid):not(:where(.hextra-code-block pre,[class~=not-prose],[class~=not-prose] *)):where(.dark,.dark *){background-color:#0000}.content :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-inline:auto;margin-block:calc(var(--hx-spacing) * 4);border-radius:var(--hx-radius-md)}.content :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)) figcaption{margin-top:calc(var(--hx-spacing) * 2);text-align:center;font-size:var(--hx-text-sm);line-height:var(--tw-leading,var(--hx-text-sm--line-height));color:var(--hx-color-gray-500);display:block}.content :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)) figcaption:where(.dark,.dark *){color:var(--hx-color-gray-400)}.content :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)) dt{margin-top:calc(var(--hx-spacing) * 6);--tw-font-weight:var(--hx-font-weight-semibold);font-weight:var(--hx-font-weight-semibold)}.content :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)) dd{margin-block:calc(var(--hx-spacing) * 2);padding-inline-start:calc(var(--hx-spacing) * 6)}.content :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){margin-block:calc(var(--hx-spacing) * 10);border-color:var(--hx-color-gray-200)}.content :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)):first-child{margin-top:calc(var(--hx-spacing) * 0)}.content :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)):last-child{margin-bottom:calc(var(--hx-spacing) * 0)}.content :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)):where(.dark,.dark *){border-color:var(--hx-color-neutral-800)}.content .footnotes{margin-top:calc(var(--hx-spacing) * 12);font-size:var(--hx-text-sm);line-height:var(--tw-leading,var(--hx-text-sm--line-height))}.content .footnotes hr{border-color:var(--hx-color-gray-200)}.content .footnotes hr:where(.dark,.dark *){border-color:var(--hx-color-neutral-800)}.content .subheading-anchor{opacity:0;transition-property:opacity;transition-timing-function:var(--tw-ease,var(--hx-default-transition-timing-function));transition-duration:var(--tw-duration,var(--hx-default-transition-duration))}.content .subheading-anchor:where(:dir(ltr),[dir=ltr],[dir=ltr] *){margin-left:calc(var(--hx-spacing) * 1)}.content .subheading-anchor:where(:dir(rtl),[dir=rtl],[dir=rtl] *){margin-right:calc(var(--hx-spacing) * 1)}span:target+:is(.content .subheading-anchor),:hover>:is(.content .subheading-anchor),.content .subheading-anchor:focus-visible{opacity:1}span+:is(.content .subheading-anchor),:hover>:is(.content .subheading-anchor){text-decoration-line:none!important}.content .subheading-anchor:after{content:var(--tw-content);color:var(--hx-color-gray-300)}.content .subheading-anchor:where(.dark,.dark *):after{content:var(--tw-content);color:var(--hx-color-neutral-700)}.content .subheading-anchor:after{padding-inline:calc(var(--hx-spacing) * 1);--tw-content:"#";content:var(--tw-content)}span:target+:is(){color:var(--hx-color-gray-400)}span:target+:is():where(.dark,.dark *){color:var(--hx-color-neutral-500)}article details>summary::-webkit-details-marker{display:none}article details>summary:before{vertical-align:-4px;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' class='hx:h-5 hx:w-5' viewBox='0 0 20 20' fill='currentColor'%3E%3Cpath fill-rule='evenodd' d='M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z' clip-rule='evenodd' /%3E%3C/svg%3E");width:1.2em;height:1.2em;padding:0 .6em}:lang(fa) ol{list-style-type:persian}.highlight .chroma .err{color:#a61717;background-color:#e3d2d2}.highlight .chroma .lnlinks{color:inherit;outline:none;text-decoration:none}.highlight .chroma .line{display:flex}.highlight .chroma .k,.highlight .chroma .kc,.highlight .chroma .kd,.highlight .chroma .kn,.highlight .chroma .kp,.highlight .chroma .kr{color:#000;font-weight:700}.highlight .chroma .kt{color:#458;font-weight:700}.highlight .chroma .na{color:teal}.highlight .chroma .nb{color:#0086b3}.highlight .chroma .bp{color:#999}.highlight .chroma .nc{color:#458;font-weight:700}.highlight .chroma .no{color:teal}.highlight .chroma .nd{color:#3c5d5d;font-weight:700}.highlight .chroma .ni{color:purple}.highlight .chroma .ne,.highlight .chroma .nf,.highlight .chroma .nl{color:#900;font-weight:700}.highlight .chroma .nn{color:#555}.highlight .chroma .nt{color:navy}.highlight .chroma .nv,.highlight .chroma .vc,.highlight .chroma .vg,.highlight .chroma .vi{color:teal}.highlight .chroma .s,.highlight .chroma .sa,.highlight .chroma .sb,.highlight .chroma .sc,.highlight .chroma .dl,.highlight .chroma .sd,.highlight .chroma .s2,.highlight .chroma .se,.highlight .chroma .sh,.highlight .chroma .si,.highlight .chroma .sx{color:#d14}.highlight .chroma .sr{color:#009926}.highlight .chroma .s1{color:#d14}.highlight .chroma .ss{color:#990073}.highlight .chroma .m,.highlight .chroma .mb,.highlight .chroma .mf,.highlight .chroma .mh,.highlight .chroma .mi,.highlight .chroma .il,.highlight .chroma .mo{color:#099}.highlight .chroma .o,.highlight .chroma .ow{color:#000;font-weight:700}.highlight .chroma .c,.highlight .chroma .ch,.highlight .chroma .cm,.highlight .chroma .c1{color:#998;font-style:italic}.highlight .chroma .cs,.highlight .chroma .cp,.highlight .chroma .cpf{color:#999;font-style:italic;font-weight:700}.highlight .chroma .gd{color:#000;background-color:#fdd}.highlight .chroma .ge{color:#000;font-style:italic}.highlight .chroma .gr{color:#a00}.highlight .chroma .gh{color:#999}.highlight .chroma .gi{color:#000;background-color:#dfd}.highlight .chroma .go{color:#888}.highlight .chroma .gp{color:#555}.highlight .chroma .gs{font-weight:700}.highlight .chroma .gu{color:#aaa}.highlight .chroma .gt{color:#a00}.highlight .chroma .gl{text-decoration:underline}.highlight .chroma .w{color:#bbb}.dark .highlight .chroma .err{color:#f85149}.dark .highlight .chroma .lnlinks{color:inherit;outline:none;text-decoration:none}.dark .highlight .chroma .line{display:flex}.dark .highlight .chroma .k{color:#ff7b72}.dark .highlight .chroma .kc{color:#79c0ff}.dark .highlight .chroma .kd,.dark .highlight .chroma .kn{color:#ff7b72}.dark .highlight .chroma .kp{color:#79c0ff}.dark .highlight .chroma .kr,.dark .highlight .chroma .kt{color:#ff7b72}.dark .highlight .chroma .nc{color:#f0883e;font-weight:700}.dark .highlight .chroma .no{color:#79c0ff;font-weight:700}.dark .highlight .chroma .nd{color:#d2a8ff;font-weight:700}.dark .highlight .chroma .ni{color:#ffa657}.dark .highlight .chroma .ne{color:#f0883e;font-weight:700}.dark .highlight .chroma .nf{color:#d2a8ff;font-weight:700}.dark .highlight .chroma .nl{color:#79c0ff;font-weight:700}.dark .highlight .chroma .nn{color:#ff7b72}.dark .highlight .chroma .py{color:#79c0ff}.dark .highlight .chroma .nt{color:#7ee787}.dark .highlight .chroma .nv{color:#79c0ff}.dark .highlight .chroma .l{color:#a5d6ff}.dark .highlight .chroma .ld{color:#79c0ff}.dark .highlight .chroma .s{color:#a5d6ff}.dark .highlight .chroma .sa{color:#79c0ff}.dark .highlight .chroma .sb,.dark .highlight .chroma .sc{color:#a5d6ff}.dark .highlight .chroma .dl{color:#79c0ff}.dark .highlight .chroma .sd,.dark .highlight .chroma .s2{color:#a5d6ff}.dark .highlight .chroma .se,.dark .highlight .chroma .sh{color:#79c0ff}.dark .highlight .chroma .si,.dark .highlight .chroma .sx{color:#a5d6ff}.dark .highlight .chroma .sr{color:#79c0ff}.dark .highlight .chroma .s1,.dark .highlight .chroma .ss,.dark .highlight .chroma .m,.dark .highlight .chroma .mb,.dark .highlight .chroma .mf,.dark .highlight .chroma .mh,.dark .highlight .chroma .mi,.dark .highlight .chroma .il,.dark .highlight .chroma .mo{color:#a5d6ff}.dark .highlight .chroma .o,.dark .highlight .chroma .ow{color:#ff7b72;font-weight:700}.dark .highlight .chroma .c,.dark .highlight .chroma .ch,.dark .highlight .chroma .cm,.dark .highlight .chroma .c1{color:#8b949e;font-style:italic}.dark .highlight .chroma .cs,.dark .highlight .chroma .cp,.dark .highlight .chroma .cpf{color:#8b949e;font-style:italic;font-weight:700}.dark .highlight .chroma .gd{color:#ffa198;background-color:#490202}.dark .highlight .chroma .ge{color:inherit;font-style:italic}.dark .highlight .chroma .gr{color:#ffa198}.dark .highlight .chroma .gh{color:#79c0ff;font-weight:700}.dark .highlight .chroma .gi{color:#56d364;background-color:#0f5323}.dark .highlight .chroma .go,.dark .highlight .chroma .gp{color:#8b949e}.dark .highlight .chroma .gs{font-weight:700}.dark .highlight .chroma .gu{color:#79c0ff}.dark .highlight .chroma .gt{color:#ff7b72}.dark .highlight .chroma .gl{text-decoration:underline}.dark .highlight .chroma .w{color:#6e7681}.hextra-code-block{--tw-leading:calc(var(--hx-spacing) * 5);font-size:.9em;line-height:calc(var(--hx-spacing) * 5)}.hextra-code-block pre{background-color:var(--hx-color-primary-700);overflow-x:auto}@supports (color:color-mix(in lab, red, red)){.hextra-code-block pre{background-color:color-mix(in oklab, var(--hx-color-primary-700) 5%, transparent)}}.hextra-code-block pre{--tw-font-weight:var(--hx-font-weight-medium);font-size:.9em;font-weight:var(--hx-font-weight-medium);-webkit-font-smoothing:auto;-moz-osx-font-smoothing:auto}@media (prefers-contrast:more){.hextra-code-block pre{border-style:var(--tw-border-style);border-width:1px;border-color:var(--hx-color-primary-900)}@supports (color:color-mix(in lab, red, red)){.hextra-code-block pre{border-color:color-mix(in oklab, var(--hx-color-primary-900) 20%, transparent)}}.hextra-code-block pre{--tw-contrast:contrast(150%);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}}.hextra-code-block pre:where(.dark,.dark *){background-color:var(--hx-color-primary-300)}@supports (color:color-mix(in lab, red, red)){.hextra-code-block pre:where(.dark,.dark *){background-color:color-mix(in oklab, var(--hx-color-primary-300) 10%, transparent)}}@media (prefers-contrast:more){.hextra-code-block pre:where(.dark,.dark *){border-color:var(--hx-color-primary-100)}@supports (color:color-mix(in lab, red, red)){.hextra-code-block pre:where(.dark,.dark *){border-color:color-mix(in oklab, var(--hx-color-primary-100) 40%, transparent)}}}.hextra-code-block .hextra-code-filename{top:calc(var(--hx-spacing) * 0);z-index:1;text-overflow:ellipsis;white-space:nowrap;border-top-left-radius:var(--hx-radius-xl);border-top-right-radius:var(--hx-radius-xl);background-color:var(--hx-color-primary-700);width:100%;position:absolute;overflow:hidden}@supports (color:color-mix(in lab, red, red)){.hextra-code-block .hextra-code-filename{background-color:color-mix(in oklab, var(--hx-color-primary-700) 5%, transparent)}}.hextra-code-block .hextra-code-filename{padding-inline:calc(var(--hx-spacing) * 4);padding-block:calc(var(--hx-spacing) * 2);font-size:var(--hx-text-xs);line-height:var(--tw-leading,var(--hx-text-xs--line-height));color:var(--hx-color-gray-700)}.hextra-code-block .hextra-code-filename:where(.dark,.dark *){background-color:var(--hx-color-primary-300)}@supports (color:color-mix(in lab, red, red)){.hextra-code-block .hextra-code-filename:where(.dark,.dark *){background-color:color-mix(in oklab, var(--hx-color-primary-300) 10%, transparent)}}.hextra-code-block .hextra-code-filename:where(.dark,.dark *){color:var(--hx-color-gray-200)}.hextra-code-block .hextra-code-filename+pre:not(.lntable pre){padding-top:calc(var(--hx-spacing) * 12)}.hextra-code-block pre:not(.lntable pre){margin-bottom:calc(var(--hx-spacing) * 4);border-radius:var(--hx-radius-xl);padding-inline:calc(var(--hx-spacing) * 4);padding-block:calc(var(--hx-spacing) * 4)}.hextra-code-block div:nth-of-type(2) pre{padding-top:calc(var(--hx-spacing) * 12);padding-bottom:calc(var(--hx-spacing) * 4)}.chroma .lntable{margin:calc(var(--hx-spacing) * 0);border-radius:var(--hx-radius-xl);width:auto;display:block;overflow:auto}.chroma .lntable pre{padding-top:calc(var(--hx-spacing) * 4);padding-bottom:calc(var(--hx-spacing) * 4)}.chroma .ln,.chroma .lnt:not(.hl>.lnt),.chroma .hl:not(.line){min-width:2.6rem;padding-right:calc(var(--hx-spacing) * 4);padding-left:calc(var(--hx-spacing) * 4);color:var(--hx-color-neutral-600)}:is(.chroma .ln,.chroma .lnt:not(.hl>.lnt),.chroma .hl:not(.line)):where(.dark,.dark *){color:var(--hx-color-neutral-300)}.chroma .lntd{padding:calc(var(--hx-spacing) * 0);vertical-align:top}.chroma .lntd:last-of-type{width:100%}.chroma .hl{background-color:var(--hx-color-primary-800);width:100%;display:block}@supports (color:color-mix(in lab, red, red)){.chroma .hl{background-color:color-mix(in oklab, var(--hx-color-primary-800) 10%, transparent)}}.hextra-cards{grid-template-columns:repeat(auto-fill, minmax(max(250px, calc((100% - 1rem * 2) / var(--hextra-cards-grid-cols))), 1fr))}.hextra-card{position:relative}.hextra-card img{-webkit-user-select:none;user-select:none}.hextra-card:hover .hextra-card-icon svg{color:currentColor}.hextra-card .hextra-card-icon svg{color:#0003;width:1.5rem;transition:color .3s}.hextra-card p{margin-top:.5rem;position:relative}.dark .hextra-card .hextra-card-icon svg{color:#fff6}.dark .hextra-card:hover .hextra-card-icon svg{color:currentColor}.hextra-card-tag{z-index:10;position:absolute;top:5px}.hextra-card-tag:where(:dir(ltr)){right:5px}.hextra-card-tag:where(:dir(rtl)){left:5px}.hextra-steps :where(h2,h3,h4,h5,h6):not(.no-step-marker){counter-increment:step}.hextra-steps :where(h2,h3,h4,h5,h6):not(.no-step-marker):where(:dir(ltr),[dir=ltr],[dir=ltr] *):before{content:var(--tw-content);margin-left:-41px}.hextra-steps :where(h2,h3,h4,h5,h6):not(.no-step-marker):where(:dir(rtl),[dir=rtl],[dir=rtl] *):before{content:var(--tw-content);margin-right:-44px}.hextra-steps :where(h2,h3,h4,h5,h6):not(.no-step-marker):before{content:var(--tw-content);background-color:var(--hx-color-gray-100)}.hextra-steps :where(h2,h3,h4,h5,h6):not(.no-step-marker):where(.dark,.dark *):before{content:var(--tw-content);background-color:var(--hx-color-neutral-800)}.hextra-steps :where(h2,h3,h4,h5,h6):not(.no-step-marker):before{content:var(--tw-content);border-style:var(--tw-border-style);content:var(--tw-content);border-width:4px;border-color:var(--hx-color-white)}.hextra-steps :where(h2,h3,h4,h5,h6):not(.no-step-marker):where(.dark,.dark *):before{content:var(--tw-content);border-color:var(--hx-color-dark)}.hextra-steps :where(h2,h3,h4,h5,h6):not(.no-step-marker):before{content:counter(step);text-align:center;text-indent:-1px;width:33px;height:33px;font-size:var(--hx-text-base);line-height:var(--tw-leading,var(--hx-text-base--line-height));--tw-font-weight:var(--hx-font-weight-normal);font-weight:var(--hx-font-weight-normal);color:var(--hx-color-neutral-400);border-radius:3.40282e38px;position:absolute}:lang(fa) .hextra-steps :where(h2,h3,h4,h5,h6):not(.no-step-marker):before{content:counter(step, persian)}.hextra-search-wrapper li{margin-inline:calc(var(--hx-spacing) * 2.5);border-radius:var(--hx-radius-md);overflow-wrap:break-word;color:var(--hx-color-gray-800)}@media (prefers-contrast:more){.hextra-search-wrapper li{border-style:var(--tw-border-style);border-width:1px;border-color:#0000}}.hextra-search-wrapper li:where(.dark,.dark *){color:var(--hx-color-gray-300)}.hextra-search-wrapper li a{scroll-margin:calc(var(--hx-spacing) * 12);padding-inline:calc(var(--hx-spacing) * 2.5);padding-block:calc(var(--hx-spacing) * 2);display:block}.hextra-search-wrapper li a:focus-visible{--tw-outline-style:none;outline-style:none}.hextra-search-wrapper li .hextra-search-title{font-size:var(--hx-text-base);line-height:var(--tw-leading,var(--hx-text-base--line-height));--tw-leading:calc(var(--hx-spacing) * 5);line-height:calc(var(--hx-spacing) * 5);--tw-font-weight:var(--hx-font-weight-semibold);font-weight:var(--hx-font-weight-semibold)}.hextra-search-wrapper li .hextra-search-active{border-radius:var(--hx-radius-md);background-color:var(--hx-color-primary-500)}@supports (color:color-mix(in lab, red, red)){.hextra-search-wrapper li .hextra-search-active{background-color:color-mix(in oklab, var(--hx-color-primary-500) 10%, transparent)}}@media (prefers-contrast:more){.hextra-search-wrapper li .hextra-search-active{border-color:var(--hx-color-primary-500)}}.hextra-search-wrapper .hextra-search-no-result{padding:calc(var(--hx-spacing) * 8);text-align:center;font-size:var(--hx-text-sm);line-height:var(--tw-leading,var(--hx-text-sm--line-height));color:var(--hx-color-gray-400);-webkit-user-select:none;user-select:none;display:block}.hextra-search-wrapper .hextra-search-prefix{margin-inline:calc(var(--hx-spacing) * 2.5);margin-top:calc(var(--hx-spacing) * 6);margin-bottom:calc(var(--hx-spacing) * 2);border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--hx-color-black)}@supports (color:color-mix(in lab, red, red)){.hextra-search-wrapper .hextra-search-prefix{border-color:color-mix(in oklab, var(--hx-color-black) 10%, transparent)}}.hextra-search-wrapper .hextra-search-prefix{padding-inline:calc(var(--hx-spacing) * 2.5);padding-bottom:calc(var(--hx-spacing) * 1.5);font-size:var(--hx-text-xs);line-height:var(--tw-leading,var(--hx-text-xs--line-height));--tw-font-weight:var(--hx-font-weight-semibold);font-weight:var(--hx-font-weight-semibold);color:var(--hx-color-gray-500);text-transform:uppercase;-webkit-user-select:none;user-select:none}.hextra-search-wrapper .hextra-search-prefix:first-child{margin-top:calc(var(--hx-spacing) * 0)}@media (prefers-contrast:more){.hextra-search-wrapper .hextra-search-prefix{border-color:var(--hx-color-gray-600);color:var(--hx-color-gray-900)}}.hextra-search-wrapper .hextra-search-prefix:where(.dark,.dark *){border-color:var(--hx-color-white)}@supports (color:color-mix(in lab, red, red)){.hextra-search-wrapper .hextra-search-prefix:where(.dark,.dark *){border-color:color-mix(in oklab, var(--hx-color-white) 20%, transparent)}}.hextra-search-wrapper .hextra-search-prefix:where(.dark,.dark *){color:var(--hx-color-gray-300)}@media (prefers-contrast:more){.hextra-search-wrapper .hextra-search-prefix:where(.dark,.dark *){border-color:var(--hx-color-gray-50);color:var(--hx-color-gray-50)}}.hextra-search-wrapper .hextra-search-excerpt{margin-top:calc(var(--hx-spacing) * 1);font-size:var(--hx-text-sm);line-height:var(--tw-leading,var(--hx-text-sm--line-height));--tw-leading:1.35rem;text-overflow:ellipsis;color:var(--hx-color-gray-600);line-height:1.35rem;overflow:hidden}.hextra-search-wrapper .hextra-search-excerpt:where(.dark,.dark *){color:var(--hx-color-gray-400)}@media (prefers-contrast:more){.hextra-search-wrapper .hextra-search-excerpt:where(.dark,.dark *){color:var(--hx-color-gray-50)}}.hextra-search-wrapper .hextra-search-excerpt{line-clamp:1;-webkit-line-clamp:1;-webkit-box-orient:vertical;display:-webkit-box}.hextra-search-wrapper .hextra-search-match{color:var(--hx-color-primary-600)}@media (max-width:48rem){.hextra-sidebar-container{top:calc(var(--hx-spacing) * 0);bottom:calc(var(--hx-spacing) * 0);z-index:15;overscroll-behavior:contain;background-color:var(--hx-color-white);width:100%;padding-top:calc(var(--navbar-height) + var(--hextra-banner-height));position:fixed}.hextra-sidebar-container:where(.dark,.dark *){background-color:var(--hx-color-dark)}.hextra-sidebar-container{will-change:transform, opacity;contain:layout style;backface-visibility:hidden;transition:transform .4s cubic-bezier(.52,.16,.04,1)}}.hextra-sidebar-container li>.hextra-sidebar-children{height:calc(var(--hx-spacing) * 0)}.hextra-sidebar-container li.open>.hextra-sidebar-children{height:auto;padding-top:calc(var(--hx-spacing) * 1)}.hextra-sidebar-container li.open>.hextra-sidebar-item>.hextra-sidebar-collapsible-button>svg>path{rotate:90deg}.hextra-banner-hidden .hextra-banner{display:none}.hextra-banner :where(a):not(:where([class~=not-prose],[class~=not-prose] *)){text-decoration-line:underline;text-decoration-thickness:from-font}.hextra-banner :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){--tw-leading:calc(var(--hx-spacing) * 7);line-height:calc(var(--hx-spacing) * 7)}.hextra-banner :where(p):not(:where([class~=not-prose],[class~=not-prose] *)):first-child{margin-top:calc(var(--hx-spacing) * 0)}nav .hextra-search-wrapper{display:none}@media (min-width:48rem){nav .hextra-search-wrapper{display:inline-block}}@supports ((-webkit-backdrop-filter:blur(1px)) or (backdrop-filter:blur(1px))){.hextra-nav-container-blur{background-color:var(--hx-color-white)}@supports (color:color-mix(in lab, red, red)){.hextra-nav-container-blur{background-color:color-mix(in oklab, var(--hx-color-white) 85%, transparent)}}.hextra-nav-container-blur{--tw-backdrop-blur:blur(var(--hx-blur-md));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.hextra-nav-container-blur:where(.dark,.dark *){background-color:var(--hx-color-dark)!important}@supports (color:color-mix(in lab, red, red)){.hextra-nav-container-blur:where(.dark,.dark *){background-color:color-mix(in oklab, var(--hx-color-dark) 80%, transparent)!important}}}.hextra-hamburger-menu svg g{transform-origin:50%;transition-property:all;transition-timing-function:var(--tw-ease,var(--hx-default-transition-timing-function));transition-duration:var(--tw-duration,var(--hx-default-transition-duration));--tw-duration:.1s;--tw-ease:var(--hx-ease-out);transition-duration:.1s;transition-timing-function:var(--hx-ease-out)}.hextra-hamburger-menu svg path{opacity:1;transition-property:all;transition-timing-function:var(--tw-ease,var(--hx-default-transition-timing-function));transition-duration:var(--tw-duration,var(--hx-default-transition-duration));--tw-duration:.1s;--tw-ease:var(--hx-ease-out);transition-duration:.1s;transition-delay:.1s;transition-timing-function:var(--hx-ease-out)}.hextra-hamburger-menu svg.open path{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--hx-default-transition-timing-function));transition-duration:var(--tw-duration,var(--hx-default-transition-duration));--tw-duration:.1s;--tw-ease:var(--hx-ease-out);transition-duration:.1s;transition-delay:0s;transition-timing-function:var(--hx-ease-out)}.hextra-hamburger-menu svg.open g{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--hx-default-transition-timing-function));transition-duration:var(--tw-duration,var(--hx-default-transition-duration));--tw-duration:.1s;--tw-ease:var(--hx-ease-out);transition-duration:.1s;transition-delay:.1s;transition-timing-function:var(--hx-ease-out)}.hextra-hamburger-menu svg.open>path{opacity:0}.hextra-hamburger-menu svg.open>g:first-of-type{rotate:45deg}.hextra-hamburger-menu svg.open>g:first-of-type path{--tw-translate-y:calc(var(--hx-spacing) * 1);translate:var(--tw-translate-x) var(--tw-translate-y)}.hextra-hamburger-menu svg.open>g:nth-of-type(2){rotate:-45deg}.hextra-hamburger-menu svg.open>g:nth-of-type(2) path{--tw-translate-y:calc(var(--hx-spacing) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.hextra-scrollbar,.hextra-scrollbar *{scrollbar-width:thin;scrollbar-color:oklch(55.55% 0 0/.4) transparent;scrollbar-gutter:stable}:is(.hextra-scrollbar,.hextra-scrollbar *)::-webkit-scrollbar{height:calc(var(--hx-spacing) * 3);width:calc(var(--hx-spacing) * 3)}:is(.hextra-scrollbar,.hextra-scrollbar *)::-webkit-scrollbar-track{background-color:#0000}:is(.hextra-scrollbar,.hextra-scrollbar *)::-webkit-scrollbar-thumb{border-radius:10px}:is(.hextra-scrollbar,.hextra-scrollbar *):hover::-webkit-scrollbar-thumb{background-color:var(--tw-shadow-color);--tw-shadow-color:var(--hx-color-neutral-500);background-clip:content-box;border:3px solid #0000}@supports (color:color-mix(in lab, red, red)){:is(.hextra-scrollbar,.hextra-scrollbar *):hover::-webkit-scrollbar-thumb{--tw-shadow-color:color-mix(in oklab, color-mix(in oklab, var(--hx-color-neutral-500) 20%, transparent) var(--tw-shadow-alpha), transparent)}}@media (hover:hover){:is(.hextra-scrollbar,.hextra-scrollbar *):hover::-webkit-scrollbar-thumb:hover{--tw-shadow-color:var(--hx-color-neutral-500)}@supports (color:color-mix(in lab, red, red)){:is(.hextra-scrollbar,.hextra-scrollbar *):hover::-webkit-scrollbar-thumb:hover{--tw-shadow-color:color-mix(in oklab, color-mix(in oklab, var(--hx-color-neutral-500) 40%, transparent) var(--tw-shadow-alpha), transparent)}}}@supports ((-webkit-backdrop-filter:blur(1px)) or (backdrop-filter:blur(1px))){.hextra-code-copy-btn{opacity:.85;--tw-backdrop-blur:blur(var(--hx-blur-md));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.hextra-code-copy-btn:where(.dark,.dark *){opacity:.8}}@media (min-width:1024px){.hextra-feature-grid{grid-template-columns:repeat(var(--hextra-feature-grid-cols), minmax(0, 1fr))}}.hextra-jupyter-code-cell{scrollbar-gutter:auto;margin-top:calc(var(--hx-spacing) * 6)}.hextra-jupyter-code-cell .hextra-jupyter-code-cell-outputs-container{font-size:var(--hx-text-xs);line-height:var(--tw-leading,var(--hx-text-xs--line-height));overflow:hidden}.hextra-jupyter-code-cell .hextra-jupyter-code-cell-outputs-container .hextra-jupyter-code-cell-outputs{max-height:50vh;overflow:auto}.hextra-jupyter-code-cell .hextra-jupyter-code-cell-outputs-container .hextra-jupyter-code-cell-outputs pre{max-width:100%;font-size:var(--hx-text-xs);line-height:var(--tw-leading,var(--hx-text-xs--line-height));overflow:auto}.hextra-badge{align-items:center;display:inline-flex}.hextra-toc a.hextra-toc-active{transition-property:all;transition-timing-function:var(--tw-ease,var(--hx-default-transition-timing-function));transition-duration:var(--tw-duration,var(--hx-default-transition-duration));--tw-duration:.2s;transition-duration:.2s;color:var(--hx-color-gray-900)!important}.hextra-toc a.hextra-toc-active:where(.dark,.dark *){color:var(--hx-color-gray-50)!important}.hextra-archive-timeline{border-left-style:var(--tw-border-style);border-left-width:2px;border-color:var(--hx-color-black)}@supports (color:color-mix(in lab, red, red)){.hextra-archive-timeline{border-color:color-mix(in oklab, var(--hx-color-black) 15%, transparent)}}.hextra-archive-timeline:where(.dark,.dark *){border-color:var(--hx-color-white)}@supports (color:color-mix(in lab, red, red)){.hextra-archive-timeline:where(.dark,.dark *){border-color:color-mix(in oklab, var(--hx-color-white) 15%, transparent)}}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"";inherits:false;initial-value:100%}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@property --tw-content{syntax:"*";inherits:false;initial-value:""}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false} diff --git a/public/css/custom.css b/public/css/custom.css deleted file mode 100644 index 7f50625..0000000 --- a/public/css/custom.css +++ /dev/null @@ -1,756 +0,0 @@ -/* ───────────────────────────────────────────────────────────── - RAPPORT — Theme-Overrides für Hextra - Warmes Sand/Tan auf hellem Grund (Architektur-Büro-Ästhetik) - ───────────────────────────────────────────────────────────── */ - -@import url('https://fonts.googleapis.com/css2?family=Archivo+Black&family=Inter:wght@300;400;500;600;700&family=Playfair+Display:ital,wght@0,400;0,700;1,400&display=swap'); - -/* Krungthep — RAPPORT-Display-Font (Mac-System-Font lokal gebundelt) */ -@font-face { - font-family: 'Krungthep'; - src: url('/fonts/Krungthep.ttf') format('truetype'); - font-weight: 400; - font-style: normal; - font-display: swap; -} - -/* — Primary-HSL: Tan #b07848 — */ -:root { - --primary-hue: 26deg; - --primary-saturation: 42%; - --primary-lightness: 49%; - - /* RAPPORT-Palette (Light) */ - --rapport-bg: #f7f5f2; - --rapport-surface: #ffffff; - --rapport-surface2: #fbf9f5; - --rapport-dark: #1a1a18; - --rapport-dark2: #2d2d28; - --rapport-accent: #b07848; - --rapport-accent-2: #9a673b; - --rapport-accent-3: #7d5430; - --rapport-text: #1a1a18; - --rapport-text-2: #555550; - --rapport-text-3: #888880; - --rapport-text-4: #aaaaaa; - --rapport-border: #e8e3dc; - --rapport-border-2: #d8d2ca; -} - -.dark { - --primary-hue: 26deg; - --primary-saturation: 42%; - --primary-lightness: 56%; - --color-dark: var(--rapport-dark); -} - -/* — Body & Backgrounds — */ -body { - background: var(--rapport-bg); - color: var(--rapport-text); - font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Helvetica Neue', sans-serif; -} - -.dark body { - background: #181614; - color: #ece9e3; -} - -::selection { - background: rgba(176, 120, 72, 0.25); - color: var(--rapport-dark); -} - -.dark ::selection { - background: rgba(176, 120, 72, 0.35); - color: #fff; -} - -/* — Typografie — Headings serifig, Body monospaced — */ -.hextra-toc, -.content, -.prose { - font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Helvetica Neue', sans-serif; -} - -h1, h2, h3, h4, -.hextra-home h1, .hextra-home h2, .hextra-home h3, -.hx\:text-2xl, .hx\:text-3xl, .hx\:text-4xl, .hx\:text-5xl, .hx\:text-6xl { - font-family: 'Playfair Display', Georgia, serif !important; - font-weight: 700 !important; - letter-spacing: -0.01em; -} - -/* Navbar-Logo: RAPPORT in Krungthep/Archivo Black — nur navbar! */ -.hextra-navbar-title, -nav .hextra-navbar-title, -nav .hextra-max-navbar-width .hx\:font-bold { - font-family: Krungthep, 'Archivo Black', sans-serif !important; - letter-spacing: -0.02em !important; - font-weight: 900 !important; -} - -/* — Navbar mit hellem Hintergrund & dezenter Border — */ -.nav-container { - background: rgba(247, 245, 242, 0.85) !important; - backdrop-filter: blur(12px); - -webkit-backdrop-filter: blur(12px); - border-bottom: 1px solid var(--rapport-border) !important; -} - -.dark .nav-container { - background: rgba(24, 22, 20, 0.85) !important; - border-bottom: 1px solid #2d2926 !important; -} - -.nav-container-blur, -.dark .nav-container-blur { - background: transparent !important; -} - -/* — Sidebar — */ -aside.sidebar-container, -.sidebar-container { - background: var(--rapport-bg) !important; - border-right: 1px solid var(--rapport-border); -} - -.sidebar-container a { - color: var(--rapport-text-2); -} - -.sidebar-container a:hover { - color: var(--rapport-accent); - background: var(--rapport-surface); -} - -.sidebar-active-item, -.sidebar-container .sidebar-active-item { - background: rgba(176, 120, 72, 0.10) !important; - color: var(--rapport-accent) !important; - border-color: rgba(176, 120, 72, 0.20) !important; -} - -.dark aside.sidebar-container, -.dark .sidebar-container { - background: #181614 !important; - border-right: 1px solid #2d2926; -} - - -/* — Links — */ -a { - transition: color 0.15s; -} - -.content a, -.prose a { - color: var(--rapport-accent); - text-decoration: none; -} - -.content a:hover, -.prose a:hover { - color: var(--rapport-accent-2); - text-decoration: underline; -} - -/* Hextra-Card-Links (-Shortcode) sollen NIE unterstrichen werden */ -.hextra-card, -.hextra-card:hover, -.hextra-card:focus, -.hextra-card:active, -.hextra-card *, -.hextra-card:hover * { - text-decoration: none !important; -} - -/* Card-Hover-Effekt sauber: nur Border + leichte Schatten, kein Underline */ -a.hextra-card:hover, -a.hextra-card:focus { - outline: none; - text-decoration: none !important; -} - -/* — RAPPORT Hero-Buttons — eigene Pills, nicht von Hextra abhängig — */ -.rapport-hero-actions { - display: flex; - gap: 18px; - align-items: center; - justify-content: center; - flex-wrap: wrap; - margin-top: 8px; - margin-bottom: 8px; -} - -.rapport-btn { - display: inline-flex; - align-items: center; - gap: 9px; - border-radius: 999px; - padding: 14px 30px; - font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Helvetica Neue', sans-serif; - font-size: 12px; - font-weight: 500; - letter-spacing: 0.07em; - text-transform: uppercase; - text-decoration: none !important; - cursor: pointer; - transition: transform 0.18s ease, box-shadow 0.18s ease, background 0.18s ease, border-color 0.18s ease; - user-select: none; - white-space: nowrap; -} - -/* Primary (Download) — Weiss mit Tiefe */ -.rapport-btn-primary { - background: #ffffff; - color: var(--rapport-text) !important; - border: 1px solid var(--rapport-border); - box-shadow: - 0 1px 0 rgba(255,255,255,0.9) inset, - 0 2px 4px rgba(0,0,0,0.04), - 0 8px 20px rgba(0,0,0,0.10), - 0 16px 40px rgba(0,0,0,0.08); -} - -.rapport-btn-primary:hover { - background: #ffffff; - border-color: var(--rapport-border-2); - color: var(--rapport-accent-2) !important; - transform: translateY(-2px); - box-shadow: - 0 1px 0 rgba(255,255,255,0.9) inset, - 0 4px 8px rgba(0,0,0,0.06), - 0 14px 28px rgba(0,0,0,0.12), - 0 24px 56px rgba(176,120,72,0.18); -} - -.rapport-btn-primary:active { - transform: translateY(0); - box-shadow: - 0 1px 0 rgba(255,255,255,0.9) inset, - 0 2px 4px rgba(0,0,0,0.06), - 0 4px 12px rgba(0,0,0,0.08); -} - -/* Secondary (Quellcode) — Outline */ -.rapport-btn-secondary { - background: transparent; - color: var(--rapport-text-2) !important; - border: 1.5px solid var(--rapport-border-2); - box-shadow: 0 2px 6px rgba(0,0,0,0.03); -} - -.rapport-btn-secondary:hover { - background: rgba(255,255,255,0.5); - border-color: var(--rapport-text-3); - color: var(--rapport-text) !important; - transform: translateY(-2px); - box-shadow: - 0 6px 14px rgba(0,0,0,0.06), - 0 12px 28px rgba(0,0,0,0.04); -} - -.rapport-btn-secondary:active { - transform: translateY(0); -} - -/* Dark-Mode-Varianten */ -.dark .rapport-btn-primary { - background: #2a2722; - color: #ece9e3 !important; - border-color: #3a3530; - box-shadow: - 0 1px 0 rgba(255,255,255,0.04) inset, - 0 2px 4px rgba(0,0,0,0.30), - 0 10px 24px rgba(0,0,0,0.45); -} - -.dark .rapport-btn-primary:hover { - background: #322e28; - color: var(--rapport-accent) !important; - box-shadow: - 0 1px 0 rgba(255,255,255,0.04) inset, - 0 4px 8px rgba(0,0,0,0.40), - 0 16px 32px rgba(0,0,0,0.50), - 0 24px 56px rgba(176,120,72,0.22); -} - -.dark .rapport-btn-secondary { - border-color: #3a3530; - color: #b8b2a8 !important; -} - -.dark .rapport-btn-secondary:hover { - background: rgba(255,255,255,0.04); - border-color: #6a6258; - color: #ece9e3 !important; -} - -/* — Hero-Badge — */ -.hextra-badge { - background: var(--rapport-surface) !important; - border: 1px solid var(--rapport-border) !important; - border-radius: 20px !important; - padding: 5px 14px !important; - font-size: 10px !important; - letter-spacing: 0.12em !important; - color: var(--rapport-text-4) !important; - text-transform: uppercase !important; - font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Helvetica Neue', sans-serif !important; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06), 0 1px 3px rgba(0, 0, 0, 0.04); -} - -/* — Feature-Cards — */ -.hextra-feature-card { - background: var(--rapport-surface) !important; - border: 1px solid var(--rapport-border) !important; - border-radius: 14px !important; - transition: box-shadow 0.2s, transform 0.2s, border-color 0.2s !important; -} - -.hextra-feature-card:hover { - border-color: var(--rapport-border-2) !important; - transform: translateY(-2px); - box-shadow: 0 8px 32px rgba(0, 0, 0, 0.09), 0 2px 8px rgba(0, 0, 0, 0.05) !important; -} - -.hextra-feature-card h3 { - font-family: 'Playfair Display', serif !important; - color: var(--rapport-text) !important; - font-weight: 700 !important; -} - -.hextra-feature-card p { - color: var(--rapport-text-2) !important; - font-size: 12px !important; - line-height: 1.8 !important; -} - -.dark .hextra-feature-card { - background: #211e1a !important; - border-color: #2d2926 !important; -} - -.dark .hextra-feature-card h3 { - color: #ece9e3 !important; -} - -.dark .hextra-feature-card p { - color: #b8b2a8 !important; -} - -/* — Generic Cards (Hextra shortcode) — */ -.hextra-card { - background: var(--rapport-surface); - border: 1px solid var(--rapport-border); - border-radius: 12px; - transition: border-color 0.2s, transform 0.2s; -} - -.hextra-card:hover { - border-color: var(--rapport-accent-2); - transform: translateY(-1px); -} - -/* — Code-Blocks — */ -.hextra-code-block { - background: #ffffff !important; - border: 1px solid var(--rapport-border) !important; - border-radius: 12px !important; - overflow: hidden; -} - -.hextra-code-block pre, -.hextra-code-block .highlight, -.hextra-code-block .chroma { - background: transparent !important; - border: none !important; - border-radius: 0 !important; - margin: 0 !important; -} - -pre { - background: var(--rapport-surface2); - border: none; -} - -code, pre, pre code, kbd, samp, tt { - font-family: ui-monospace, 'SF Mono', Menlo, Monaco, Consolas, 'Liberation Mono', monospace !important; -} - -code { - color: var(--rapport-accent-3) !important; - background: rgba(176, 120, 72, 0.10) !important; - padding: 2px 6px; - border-radius: 4px; - font-size: 0.9em; -} - -pre code { - color: var(--rapport-text) !important; - background: transparent !important; - padding: 0; - font-size: 0.9em; -} - -.dark .hextra-code-block { - background: #1f1c19 !important; - border-color: #2d2926 !important; -} - -.dark .hextra-code-block pre, -.dark .hextra-code-block .highlight, -.dark .hextra-code-block .chroma { - background: transparent !important; - border: none !important; -} - -.dark code { - color: var(--rapport-accent) !important; - background: rgba(176, 120, 72, 0.15) !important; -} - -.dark pre code { - color: #ece9e3 !important; -} - -/* — Callouts — */ -.hextra-callout { - background: var(--rapport-surface) !important; - border-color: var(--rapport-border-2) !important; -} - -/* — Footer — */ -.hextra-footer, -footer { - background: var(--rapport-surface2); - border-top: 1px solid var(--rapport-border); - color: var(--rapport-text-3); -} - -.hextra-footer a { - color: var(--rapport-text-2); -} - -.hextra-footer a:hover { - color: var(--rapport-accent); -} - -.dark .hextra-footer, -.dark footer { - background: #15130f; - border-top: 1px solid #2d2926; - color: #888880; -} - -/* — TOC — */ -.hextra-toc a { - color: var(--rapport-text-3); -} - -.hextra-toc a:hover, -.hextra-toc .active { - color: var(--rapport-accent) !important; -} - -/* Hextra-Sticky-Bottom-Fades (TOC "Nach oben" + Sidebar-Footer) — */ -/* der hardcoded weisse Fade passt nicht zum cremefarbenen RAPPORT-Bg */ -.hextra-toc div:has(> #backToTop), -[data-toggle-animation] { - background: var(--rapport-bg) !important; - box-shadow: none !important; - border-top-color: var(--rapport-border) !important; -} - -.dark .hextra-toc div:has(> #backToTop), -.dark [data-toggle-animation] { - background: #181614 !important; - border-top-color: #2d2926 !important; - box-shadow: none !important; -} - -/* — Search — */ -.hextra-search-wrapper input { - background: var(--rapport-surface) !important; - border: 1px solid var(--rapport-border) !important; - color: var(--rapport-text) !important; -} - -.hextra-search-wrapper input:focus { - border-color: var(--rapport-accent-2) !important; -} - -/* — Tabellen — */ -table { - border-color: var(--rapport-border) !important; -} - -thead { - background: var(--rapport-surface) !important; -} - -th, td { - border-color: var(--rapport-border) !important; -} - -/* ───────────────────────────────────────────────────────────── - RAPPORT-LOGO-KARTE (Hero) — Dark Card auf hellem Grund - ───────────────────────────────────────────────────────────── */ -.rapport-logo-card { - background: var(--rapport-dark); - border: 1px solid var(--rapport-dark2); - border-radius: 999px; - padding: 28px 64px 26px; - display: inline-block; - box-shadow: 6px 0 20px rgba(0, 0, 0, 0.18), 0 6px 16px rgba(0, 0, 0, 0.12); - text-align: center; - margin: 0 auto 32px; -} - -.rapport-logo-text { - font-family: 'Krungthep', 'Archivo Black', sans-serif !important; - font-size: 48px; - letter-spacing: -0.02em; - color: #f0ede8; - line-height: 0.95; - font-weight: 400; -} - -.rapport-logo-sub { - font-size: 9px; - letter-spacing: 0.15em; - color: #f0ede8; - text-transform: uppercase; - margin-top: 8px; - font-weight: 500; -} - -/* — Hero-Meta-Pillen — */ -.rapport-meta { - display: flex; - gap: 6px; - align-items: center; - justify-content: center; - flex-wrap: wrap; - margin-top: 32px; - font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Helvetica Neue', sans-serif; -} - -.rapport-meta-item { - font-size: 10px; - letter-spacing: 0.08em; - color: var(--rapport-text-4); - text-transform: uppercase; - padding: 0 10px; - border-right: 1px solid var(--rapport-border); -} - -.rapport-meta-item:last-child { - border-right: none; -} - -/* — Status-Badges (in Arbeit / Geplant / Stabil / Neu) — */ -/* Einheitlich: weisse Pill mit dunklem Text — wie Download-Button */ -.rapport-status, -.rapport-status.active, -.rapport-status.planned, -.rapport-status.stable, -.rapport-status.new { - display: inline-block; - font-size: 10px; - letter-spacing: 0.12em; - text-transform: uppercase; - padding: 5px 14px; - border-radius: 999px; - margin-bottom: 12px; - font-weight: 600; - font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Helvetica Neue', sans-serif; - background: #ffffff; - color: var(--rapport-text); - border: 1px solid var(--rapport-border); - box-shadow: - 0 1px 0 rgba(255,255,255,0.9) inset, - 0 1px 2px rgba(0,0,0,0.04), - 0 3px 8px rgba(0,0,0,0.06); -} - -.dark .rapport-status, -.dark .rapport-status.active, -.dark .rapport-status.planned, -.dark .rapport-status.stable, -.dark .rapport-status.new { - background: #2a2722; - color: #ece9e3; - border-color: #3a3530; - box-shadow: - 0 1px 0 rgba(255,255,255,0.04) inset, - 0 1px 2px rgba(0,0,0,0.30), - 0 4px 10px rgba(0,0,0,0.35); -} - -/* — Stack-Bar (am Footer) — */ -.rapport-stack-bar { - padding: 20px 0; - border-top: 1px solid var(--rapport-border); - display: flex; - align-items: center; - gap: 20px; - flex-wrap: wrap; - margin-top: 32px; - font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Helvetica Neue', sans-serif; -} - -.rapport-stack-label { - font-size: 10px; - letter-spacing: 0.12em; - text-transform: uppercase; - color: var(--rapport-text-4); - flex-shrink: 0; -} - -.rapport-stack-items { - display: flex; - gap: 8px; - flex-wrap: wrap; -} - -.rapport-stack-item { - font-size: 10px; - letter-spacing: 0.06em; - color: var(--rapport-text-3); - background: var(--rapport-surface); - border: 1px solid var(--rapport-border); - border-radius: 6px; - padding: 4px 10px; -} - -/* — Reduce default content max-width slightly for monospace lines — */ -.content article { - max-width: 100%; -} - -/* ───────────────────────────────────────────────────────────── - HOME-HERO — zentriertes Layout wie auf der alten Website - ───────────────────────────────────────────────────────────── */ - -/* Inhalt der home Page zentrieren */ -.hextra-home { - align-items: center !important; - text-align: center; - max-width: 100%; -} - -/* Subtitle zentriert, schmaler max-width, Playfair Display */ -.hextra-home > p, -.hextra-home .not-prose.hx\:text-xl { - font-family: 'Playfair Display', serif !important; - font-size: clamp(16px, 2.2vw, 24px) !important; - font-weight: 400 !important; - color: var(--rapport-text-3) !important; - max-width: 560px !important; - margin-left: auto !important; - margin-right: auto !important; - line-height: 1.55 !important; - text-align: center; -} - -/* Buttons immer in einer zentrierten Zeile */ -.hextra-home > div.hx\:flex, -.hextra-home > .hx\:flex { - justify-content: center; - align-items: center; -} - -/* Hero-Button matches RAPPORT design (dark on cream) */ -.hextra-home .hextra-hero-button, -a.hextra-hero-button { - background: var(--rapport-dark); - color: #f0ede8 !important; - border-radius: 20px; - padding: 13px 28px; - font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Helvetica Neue', sans-serif !important; - font-size: 11px !important; - font-weight: 500 !important; - letter-spacing: 0.07em !important; - text-transform: uppercase !important; - box-shadow: 0 4px 14px rgba(0, 0, 0, 0.20); - transition: all 0.18s; - display: inline-flex; - align-items: center; - gap: 9px; -} - -/* Feature-Grid linksbündig (Text in Cards) */ -.hextra-home .hextra-feature-grid, -.hextra-home .rapport-stack-bar { - text-align: left; - width: 100%; -} - -.hextra-home .hextra-feature-card * { - text-align: left; -} - -.rapport-stack-bar { - justify-content: flex-start; - text-align: left; -} - -/* Section-Heading & Eyebrow vor dem Feature-Grid zentrieren */ -.hextra-home h2, -.hextra-home > div > h2 { - text-align: center; - margin-left: auto; - margin-right: auto; -} - -/* RAPPORT-Logo bleibt zentriert */ -.hextra-home .rapport-logo-card { - margin-left: auto; - margin-right: auto; - display: block; -} - -/* Hero-Badge zentrieren */ -.hextra-home .hextra-badge, -.hextra-home > p:has(.hextra-badge) { - margin-left: auto; - margin-right: auto; - display: inline-flex !important; -} - -/* Hero-Background-Glow — sanfter Tan-Halo */ -body:has(.hextra-home)::before { - content: ""; - position: fixed; - top: 5%; - left: 50%; - transform: translateX(-50%); - width: 720px; - height: 720px; - background: radial-gradient(circle, rgba(176, 120, 72, 0.08) 0%, transparent 60%); - pointer-events: none; - z-index: 0; -} - -.dark body:has(.hextra-home)::before { - background: radial-gradient(circle, rgba(176, 120, 72, 0.12) 0%, transparent 60%); -} - -/* Navbar-Logo — RAPPORT-Schriftzug in Krungthep, etwas grösser */ -.hextra-navbar-title, -nav a[href="/"] span, -nav [class*="font-bold"] { - font-family: 'Krungthep', 'Archivo Black', sans-serif !important; - letter-spacing: -0.02em !important; - font-weight: 400 !important; - font-size: 23px !important; - line-height: 1 !important; -} - -/* RAPPORT-Meta-Pillen zentriert */ -.rapport-meta { - justify-content: center; - text-align: center; -} diff --git a/public/css/variables.css b/public/css/variables.css deleted file mode 100644 index f4f9ef7..0000000 --- a/public/css/variables.css +++ /dev/null @@ -1,26 +0,0 @@ -/* Hugo template to derive CSS variables from site and page parameters */ - -/* Do not remove the following comment. It is used by Hugo to render CSS variables.*/ - -:root { - --hextra-max-page-width: 80rem; - --hextra-max-content-width: 72rem; - --hextra-max-navbar-width: 80rem; - --hextra-max-footer-width: 80rem; -} - -.hextra-max-page-width { - max-width: var(--hextra-max-page-width); -} - -.hextra-max-content-width { - max-width: var(--hextra-max-content-width); -} - -.hextra-max-navbar-width { - max-width: var(--hextra-max-navbar-width); -} - -.hextra-max-footer-width { - max-width: var(--hextra-max-footer-width); -} diff --git a/public/de.search-data.json b/public/de.search-data.json index 98a9343..c94b91f 100644 --- a/public/de.search-data.json +++ b/public/de.search-data.json @@ -1 +1 @@ -{"/docs/":{"data":{"":"Vollständige Anleitung zu RAPPORT — von der Installation über den täglichen Arbeitsablauf bis zur Cloud-Variante und Eigen-Builds.","erste-schritte#Erste Schritte":"Quick-StartIn sechs Schritten von Null zur ersten Rechnung. InstallationmacOS, Gatekeeper, Signatur, geplante Plattformen. EinrichtungBürodaten, Mitarbeiter, Kunden, Projekte initial anlegen.","für-fortgeschrittene#Für Fortgeschrittene":"Web-Modus (Multi-User)Rapport im Browser via Supabase — für Studios mit mehreren Nutzern. Entwicklung \u0026 BuildAus dem Quellcode kompilieren, beitragen, eigenes Release. ChangelogVersionsgeschichte und Breaking Changes.","hilfe--support#Hilfe \u0026amp; Support":"Bei Bugs oder weiteren Fragen → Issue auf Gitea . Siehe auch die FAQ für häufige Fragen.","im-alltag#Im Alltag":"Typischer ArbeitsablaufKunde → Offerte → Projekt → Zeit → Rechnung. Datenhaltung \u0026 BackupWo die Daten liegen, wie du sie sicherst und wiederherstellst. TroubleshootingApp startet nicht, Daten weg, Update hängt."},"title":"Dokumentation"},"/docs/arbeitsablauf/":{"data":{"":"Vom Erstkontakt mit dem Kunden bis zur Schlussrechnung — der typische Weg eines Projekts durch Rapport.","1--kunde-anlegen#1 · Kunde anlegen":"Kunden → Neu — siehe Einrichtung § 3.\nFalls der Kunde später bestellt, lassen sich alle gesammelten Daten (Adresse, Honorartyp) direkt übernehmen.","2--offerte-erstellen#2 · Offerte erstellen":"Offerten → Neu\nFeld Inhalt Kunde aus Kundendatenbank wählen Bezeichnung Projekttitel (z. B. “Einfamilienhaus Müller, Bern”) Honorartyp Stundensatz / SIA 102 / Pauschal Bauschätzwert bei SIA — Bruttowert in CHF Phasen bei SIA — anzuklickende Phasen Positionen bei Stundensatz/Pauschal — Position, Beschreibung, Betrag Mit PDF exportieren — fertige Offerte für den Kunden.","3--offerte--projekt#3 · Offerte → Projekt":"Bei Status “Angenommen”: Knopf “In Projekt konvertieren”.\nDas erzeugt:\nEin neues Projekt mit den Daten der Offerte (Kunde, Bezeichnung, Honorar, Phasen) Eine Verknüpfung zwischen Offerte und Projekt Die Offerte selbst bleibt im Archiv erhalten Siehe auch Projekt-Feature.","4--zeit-erfassen#4 · Zeit erfassen":"Zeit → Mitarbeiter wählen → Woche navigieren\nKlick auf einen Halbstunden-Slot → Eintrag erstellen Drag über mehrere Slots → längerer Eintrag Projekt zuweisen (Pflichtfeld) — aus aktiven Projekten SIA-Phase zuweisen (optional, für detaillierte Auswertung)","5--akonto-rechnung#5 · Akonto-Rechnung":"Während der Projektlaufzeit — typisch nach jeder abgeschlossenen SIA-Phase oder monatlich.\nRechnungen → Neu → Akonto\nFeld Inhalt Projekt aus aktiven Projekten Bezug “Akonto für Phase 31 — Vorprojekt” Betrag Stundensatz × Stunden, oder Phasenanteil × Bausumme Fälligkeit i. d. R. 30 Tage Rapport zieht automatisch die geleisteten Stunden aus der Zeiterfassung — die kannst du als Basis nehmen oder überschreiben.\nPDF inkl. QR-Einzahlungsschein — siehe Rechnungen-Feature.","6--schlussrechnung#6 · Schlussrechnung":"Nach Projektabschluss — Differenz aus Gesamthonorar minus aller Akonto-Beträge.\nRechnungen → Neu → Schlussrechnung\nRapport rechnet die bisherigen Akonto-Rechnungen automatisch ab:\nGesamthonorar (SIA / Pauschal / Stundensatz) − Akonto-Rechnung 1 − Akonto-Rechnung 2 − Akonto-Rechnung 3 = Schlussrechnung","7--projektabschluss#7 · Projektabschluss":"Im Projekt → Status auf “Abgeschlossen”.\nDas Projekt bleibt für historische Auswertungen sichtbar, taucht aber nicht mehr in der Zeiterfassungs-Auswahl auf.","auswertungen#Auswertungen":"Wöchentlich / monatlich / am Jahresende:\nZeit → Auswertungen — Stunden pro Mitarbeiter, pro Projekt, pro Phase Rechnungen → Übersicht — offene Beträge, bezahlt, Mahnungen Buchhaltung → Erfolgsrechnung — Einnahmen vs. Ausgaben Mitarbeiter → Lohnabrechnung — monatlich","offerten-status#Offerten-Status":"Status Bedeutung Entwurf noch nicht versandt Versandt beim Kunden, wartet auf Antwort Angenommen Kunde hat zugesagt — bereit zur Konvertierung Abgelehnt Kunde hat abgelehnt — Archiv","spezialfälle#Spezialfälle":"Ferien — eigener “Projekt”-Typ “Ferien”, in der Auswertung separat Krankheit/Absenz — eigener “Projekt”-Typ, ebenfalls separat Interne Stunden — z. B. Verwaltung, Marketing, IT — eigene interne Projekte","tipps-aus-dem-alltag#Tipps aus dem Alltag":"Zeit jeden Tag erfassen statt rückwirkend — sonst gehen Details verloren Akonto regelmässig statt einmal am Schluss — Liquidität Backups vor Jahresabschluss — siehe Datenhaltung Briefbogen-Logo in hoher Auflösung — sieht im PDF besser aus","übersicht#Übersicht":"Kunde → Offerte → Projekt → Zeit → Akonto → Schluss anlegen erstellen (aus Offerte) erfassen -Rechnung -Rechnung ↓ QR-Schein"},"title":"Arbeitsablauf"},"/docs/changelog/":{"data":{"":"Versionsgeschichte von RAPPORT. Aktuelle Releases: Gitea .","01x--initial#0.1.x — Initial":"Neu\nErste Setup-Routine (Bürodaten, Mitarbeiter, Kunden) Briefe und Lieferscheine Tauri-2-Bundle für macOS","02x--zeiterfassung#0.2.x — Zeiterfassung":"Neu\nWochenraster mit Halbstunden-Slots Drag \u0026 Drop zur Slot-Erfassung Projekt-Zuweisung pro Eintrag Auswertungen pro Mitarbeiter und Projekt","03x--rechnungen--qr#0.3.x — Rechnungen \u0026amp; QR":"Neu\nRechnungsmodul mit QR-Einzahlungsschein (via swissqrbill) Akonto-, Teil- und Schlussrechnungen PDF-Export mit Bürobriefbogen Stundensatz-Rechnungen ziehen direkt aus der Zeiterfassung","04x--projekte--sia-102#0.4.x — Projekte \u0026amp; SIA 102":"Neu\nProjektverwaltung nach SIA 102 Vorgeschlagene Phasen-Anteile am Gesamthonorar Bauschätzwert-basiertes Honorar Verbessert\nZeit-Auswertung pro SIA-Phase Akonto- und Schlussrechnungen mit automatischer Differenzberechnung","05x--mitarbeiter--lohn#0.5.x — Mitarbeiter \u0026amp; Lohn":"Neu\nMitarbeiterverwaltung mit Pensum, Stundensatz, Ferienanspruch Lohnabrechnung mit AHV/IV/EO, ALV, BVG, NBU Jahresabschluss mit Überstundenausgleich Ferien-Prorata bei Eintritt unter Jahr","06x--spesen--buchhaltung#0.6.x — Spesen \u0026amp; Buchhaltung":"Neu\nSpesenerfassung mit Beleg-Upload (Base64 in localStorage) Jahresbudget mit Einnahmen-/Ausgaben-Übersicht Vereinfachte Erfolgsrechnung pro Geschäftsjahr Verbessert\nLohnabrechnung integriert Spesen-Erstattungen CSV-Export aus der Zeiterfassung","070--auto-updater--system-tray#0.7.0 — Auto-Updater \u0026amp; System-Tray":"Neu\nAuto-Updater — Rapport prüft beim Start auf neue Versionen und installiert Updates signiert über Tauri. Einzelne Versionen können übersprungen werden. (Doku) System-Tray — Schnellzugriff über die Menüleiste mit Hide-on-Close. Beim Schliessen läuft Rapport im Hintergrund weiter, Cmd+Q beendet die App vollständig. (Doku) Quick-Open der letzten 5 Projekte direkt aus dem Tray-Menü Verbessert\nSchnellerer App-Start durch lazy-geladene Views Klarere Statusbadges in der Projekt-Übersicht","080082--patch-releases#0.8.0–0.8.2 — Patch-Releases":"Patch-Reihe mit kleineren Verbesserungen und Bugfixes. Details siehe Releases auf Gitea .","083--aktuelle-version-aktuell#0.8.3 — Aktuelle Version \u003cspan class=\"rapport-status new\"\u003eAktuell\u003c/span\u003e":"Veröffentlicht am 2026-05-24.\nNeu / Verbessert\nDiverse Verbesserungen und Bugfixes (Details werden im Release auf Gitea gepflegt) Bekannte Einschränkungen\nBuilds sind Tauri-signiert, aber noch nicht Apple-notarisiert — siehe Installation § Gatekeeper Linux- und Windows-Builds noch nicht verfügbar","roadmap#Roadmap":"Geplant — keine konkreten Termine:\nLinux-Build (Tauri 2 unterstützt es, Bedarf nötig) Windows-Build (analog) Cloud-Modus Stable (Supabase) — derzeit in Web-Modus verfügbar, aber experimentell Französische / Italienische Übersetzung PostgreSQL-Migration aus localStorage (Knopf in der App) Mobile App (iOS Companion zur Zeiterfassung) — offen Wünsche oder Prioritäten → Issue auf Gitea ."},"title":"Changelog"},"/docs/datenhaltung/":{"data":{"":"Wo Rapport seine Daten speichert, wie du sie sicherst und wiederherstellst.\nDiese Seite beschreibt die Desktop-App (Single-User). Wer im Team arbeitet und Rapport gegen einen Rapport Server betreibt, sichert stattdessen die Postgres-Datenbank — siehe Rapport Server § Backup.","a--einfach-manuell#A · Einfach (manuell)":"Den ganzen Ordner kopieren:\ncp -R \"~/Library/Application Support/com.rapport.app\" \\ \"~/Documents/Rapport-Backup-$(date +%Y%m%d)\" → Auf USB-Stick, externen Datenträger oder in die Cloud.","b--time-machine#B · Time Machine":"Wenn Time Machine läuft, ist der Ordner automatisch dabei. Versionierung inbegriffen.\nEinschränkung: Time Machine sichert nur lokal/USB. Für off-site-Backup separat sorgen.","backup-strategien#Backup-Strategien":"","c--cron-job-täglich-automatisch#C · Cron-Job (täglich automatisch)":"# In ~/Library/LaunchAgents/com.rapport.backup.plist hinterlegen # oder als crontab-Eintrag: 0 22 * * * rsync -a \"$HOME/Library/Application Support/com.rapport.app/\" \\ \"$HOME/Backups/rapport/$(date +\\%Y\\%m\\%d)/\"","d--icloud-drive-off-site#D · iCloud Drive (off-site)":"Application-Support liegt nicht automatisch in iCloud. Wer das will:\n# Symlink anlegen mkdir -p \"~/iCloud Drive/Rapport\" ln -s \"~/Library/Application Support/com.rapport.app\" \"~/iCloud Drive/Rapport/data\" Achtung: iCloud-Sync mit aktiver App kann zu Race-Conditions führen. Besser den Sync zeitversetzt (z. B. nachts via Cron).","datenmenge#Datenmenge":"Typische Grössen pro Bürojahr:\nInhalt Grösse Logo (PNG/SVG) 50 KB – 1 MB 1 Jahr Zeiterfassung (1 MA) ~ 80 KB 1 Jahr Zeiterfassung (5 MA) ~ 400 KB 50 Projekte mit je 5 Rechnungen ~ 800 KB Total typisches Solo-Büro / Jahr ~ 1–2 MB localStorage hat Limits (i. d. R. ~10 MB pro Origin). Für Solo-Büros reicht das problemlos für viele Jahre. Wer das Limit erreicht oder im Team arbeitet → Rapport Server.","export-funktionen-in-der-app#Export-Funktionen (in der App)":"Aus Rapport selbst:\nWas Wo Format Zeit-Auswertung Zeit → Export CSV Rechnung Rechnung → PDF PDF (inkl. QR) Offerte Offerte → PDF PDF Lohnabrechnung Mitarbeiter → PDF PDF Jahres-Buchhaltung Buchhaltung → Export CSV Die Exports sind für externe Verwendung (Buchhalter, Treuhänder, Archiv) gedacht — kein Full-Backup.","macos#macOS":"~/Library/Application Support/com.rapport.app/ Dort liegt eine einzelne localStorage-Datenbank des WebView, in der alle Rapport-Daten als JSON unter dem Key studio_data_v1 gespeichert sind:\nBürodaten, Logo, IBAN Mitarbeiter, Kunden, Projekte, Offerten Zeit-Einträge, Rechnungen Spesen, Lohnabrechnungen, Protokolle App-Einstellungen Konsequenz: Wer den Application-Support-Ordner kopiert, hat ein vollständiges Backup. Wer ihn löscht, verliert alle Daten.","schema-migrationen#Schema-Migrationen":"Bei Updates kann sich das Datenformat ändern. Rapport hat einen Migrations-Mechanismus: beim Start prüft die App, ob das gespeicherte Format dem aktuellen entspricht, und migriert es automatisch.\nCode: src/storage/migrations.js .\nEmpfehlung: Vor jedem grösseren Update ein Backup machen — Migrationen sind getestet, aber 100%-Sicherheit gibt es nicht.","selektiv-nur-einzelne-daten#Selektiv (nur einzelne Daten)":"Da alle Daten in einem JSON unter studio_data_v1 liegen, ist selektive Wiederherstellung manuell:\nBackup-localStorage-Datei öffnen (WebKit-Format → mit Tool wie [WebKit Storage Inspector] lesen, oder via Rapport DevTools) Gewünschte Felder in die aktuelle Instanz übertragen In der Praxis: meistens lohnt sich die vollständige Wiederherstellung mehr.","speicherort-desktop-app#Speicherort (Desktop-App)":"Die Desktop-App speichert alles lokal — keine Cloud, kein Server.","vollständig-rapport-komplett-tot#Vollständig (Rapport komplett tot)":"Rapport beenden (Cmd+Q, nicht nur Fenster zu) Aktuellen Ordner umbenennen (falls noch da): mv \"~/Library/Application Support/com.rapport.app\" \\ \"~/Library/Application Support/com.rapport.app.bak\" Backup-Ordner zurück kopieren: cp -R \"~/Documents/Rapport-Backup-20260523\" \\ \"~/Library/Application Support/com.rapport.app\" Rapport starten","warum-localstorage#Warum localStorage?":"In der Desktop-App ist Rapport eine Single-User-Anwendung. localStorage ist dafür:\nSchnell — keine Datenbank-Roundtrips Einfach — keine Migration nötig, JSON-Schema im Code Portabel — eine Datei → ein Backup Für Multi-User-Betrieb existiert Rapport Server — Postgres + Auth + Realtime in einem Docker-Compose. Wechsel zwischen Desktop- und Server-Modus erfolgt im Login-Bildschirm der App.","was-wird-nicht-gespeichert#Was wird \u003cstrong\u003enicht\u003c/strong\u003e gespeichert?":"WebView-Cache — ~/Library/Caches/com.rapport.app/ und ~/Library/WebKit/com.rapport.app/ sind sicher zu löschen (UI-Caches, regenerieren sich) App-Updates — werden bei Bedarf erneut runtergeladen Logs — ~/Library/Logs/com.rapport.app/ (geplant, derzeit nicht geschrieben)","wiederherstellung#Wiederherstellung":""},"title":"Datenhaltung"},"/docs/einrichtung/":{"data":{"":"Nach der Installation: Bürodaten, Mitarbeiter, Kunden und Projekte initial anlegen.","1--bürodaten#1 · Bürodaten":"Einstellungen → Bürodaten\nFeld Beschreibung Verwendung Name Bürobezeichnung Briefbogen, Login-Screen Adresse Strasse, PLZ, Ort Briefbogen, QR-Rechnung (Empfänger) Telefon, E-Mail Kontaktdaten Briefbogen, Rechnung-Footer IBAN CH-IBAN (Format CH XX XXXX …) QR-Einzahlungsschein — Pflicht Logo PNG/SVG-Upload Briefbogen, Rechnung, Brief MwSt.-Nr. optional Rechnung-Footer Tipp: Das Logo wird hochauflösend gespeichert (Base64 im localStorage). Bei sehr grossen Dateien (\u003e1 MB) vorher in Vorschau verkleinern.","2--mitarbeiter#2 · Mitarbeiter":"Einstellungen → Mitarbeiter → Neu\nFeld Beschreibung Name, Vorname wird in Zeiterfassung \u0026 Lohn verwendet Initialen Kürzel für Auswertungen (z. B. “KGE”) Eintrittsdatum für Prorata der Ferien Pensum (%) 100 = Vollzeit Stundensatz (CHF) für Stundensatz-Rechnungen Ferienanspruch (Tage/Jahr) i. d. R. 25–30 Lohn (brutto, monatlich) optional, für Lohnabrechnung Mindestens ein Mitarbeiter (z. B. der Inhaber selbst) muss angelegt sein, sonst lässt sich keine Zeit erfassen.","3--kunden#3 · Kunden":"Kunden → Neu\nFeld Beschreibung Typ Privatperson / Firma Anrede, Name für Brief / Rechnung Adresse Strasse, PLZ, Ort, Land Ansprechperson bei Firmen Telefon, E-Mail Kontakt Honorartyp Default Stundensatz / SIA / Pauschal Stundensatz falls vom Bürostandard abweichend MwSt.-pflichtig ja/nein","4--projekte#4 · Projekte":"Projekte → Neu\nFeld Beschreibung Projekt-Nr. freie Form, oder generiert (2026-001) Bezeichnung Kurztitel Standort Adresse Kunde aus Kundendatenbank Bauschätzwert für SIA-Phasen-Honorar SIA-Phasen Vorprojekt / Bauprojekt / … — alle anwählbar Honorartyp Stundensatz / SIA 102 / Pauschal Status aktiv / pausiert / abgeschlossen","checkliste#Checkliste":"Nach diesen vier Schritten ist Rapport einsatzbereit:\nBürodaten inkl. IBAN erfasst Mindestens ein Mitarbeiter angelegt Erster Kunde angelegt Erstes Projekt angelegt Eine Test-Zeitbuchung erfasst — wird das Projekt korrekt zugewiesen? Eine Test-Rechnung erstellt — kommt der QR-Schein sauber raus? Wenn alles funktioniert: Typischer Arbeitsablauf.","reihenfolge#Reihenfolge":"Die Reihenfolge ist wichtig — jede Stufe baut auf der vorherigen auf:\n1. Bürodaten → 2. Mitarbeiter → 3. Kunden → 4. Projekte ▼ ▼ ▼ ▼ Briefbogen, Zeiterfassung, Adressen, Zeiterfassung, QR-Schein, Lohn Rechnungen Rechnungen Login","sia-102-phasen#SIA-102-Phasen":"Wenn als Honorartyp SIA 102 gewählt ist, werden die Phasen-Anteile am Gesamthonorar vorgeschlagen — siehe Projekt-Feature.","sozialabzüge-optional#Sozialabzüge (optional)":"In Einstellungen → Lohn:\nAbzug Standardwert (CH) AHV / IV / EO 5,3 % ALV 1,1 % BVG (Pensionskasse) variabel — je Mitarbeiter NBU je nach Versicherung Die Standardsätze sind hinterlegt, können aber überschrieben werden."},"title":"Einrichtung"},"/docs/entwicklung/":{"data":{"":"Aus dem Quellcode kompilieren, beitragen, eigenes Release erzeugen.","architektur-in-einem-absatz#Architektur in einem Absatz":"RAPPORT ist eine monolithische SPA: ein React-Root in App.jsx hält den gesamten App-State in einem useState({...}), persistiert ihn synchron in localStorage unter studio_data_v1, und übergibt ihn als Props an lazy-geladene Views. Kein Routing-Framework, kein State-Library, kein TypeScript, kein CSS-Framework. Der Rust-Teil ist 109 Zeilen und macht nur drei Dinge: System-Tray, Window-Hide-on-Close, Plugin-Registrierung (Updater, Process, Log). Keine #[tauri::command] — Frontend ↔ Backend kommuniziert nur über das Event rapport:navigate (Tray → Frontend).\nDetaillierte Karte: ARCHITECTURE.md .","beitragen#Beitragen":"Issues \u0026 Pull Requests sind willkommen. Wertvoll sind:\nBug-Reports mit Reproduktionsschritten Workflow-Verbesserungen aus dem realen Büroalltag Vorlagen (Briefe, Protokolle, Lieferscheine) für andere Büros Übersetzungen / Internationalisierung (FR, IT) Linux-/Windows-Builds und plattformspezifische Fixes Vor grösseren Änderungen → Issue zum Diskutieren.","build#Build":"","desktop-tauri-dmg#Desktop (Tauri DMG)":"npm run build # erst Vite-Build (dist/) npx tauri build # dann Tauri-Bundle (DMG) Output: src-tauri/target/release/bundle/dmg/Rapport__aarch64.dmg","entwicklung#Entwicklung":"","konventionen#Konventionen":"JavaScript statt TypeScript — bewusste Entscheidung für Solo-Dev-Velocity Inline-Styles statt CSS-Framework kein Routing-Framework — view-State in App.jsx triggert Komponente JSON-Schema implizit — definiert durch defaultData in constants.js Migrationen als reine Funktionen in storage/migrations.js","lizenz#Lizenz":"GNU AGPL-3.0-or-later — eigene Builds erlaubt, Modifikationen müssen unter derselben Lizenz veröffentlicht werden, wenn die Software als Service angeboten wird.","native-window-tauri-fenster-mit-desktop-integration#Native Window (Tauri-Fenster mit Desktop-Integration)":"npx tauri dev Echtes Tauri-Fenster System-Tray, Updater, native APIs verfügbar Erster Start dauert lange (Rust-Compile)","release-workflow#Release-Workflow":"# 1 · Version bumpen in package.json + Cargo.toml + tauri.conf.json ./scripts/release.sh 0.7.1 # 2 · Build mit Signatur TAURI_SIGNING_PRIVATE_KEY=$(cat ~/.tauri/rapport-key) \\ TAURI_SIGNING_PRIVATE_KEY_PASSWORD=… \\ npx tauri build # 3 · latest.json aktualisieren mit neuer Signatur # 4 · DMG + latest.json auf Gitea Releases hochladen","setup#Setup":"git clone https://git.kgva.ch/karim/RAPPORT.git cd RAPPORT/APP npm install","verzeichnis-karte#Verzeichnis-Karte":"APP/ ├── src/ React 19 (kein TS, nur .jsx) │ ├── App.jsx Root: State, Navigation, Sidebar, Modals │ ├── constants.js STORAGE_KEY, NAV_ITEMS, defaultData, SIA-Phasen │ ├── utils.js Business-Logik: Kalkulation, QR-Bill, CSV, Lohn │ ├── storage/adapter.js LocalStorageAdapter (Phase 1), SupabaseAdapter (Phase 2) │ ├── storage/migrations.js Schema-Migrationen │ ├── views/ 20 Top-Level-Screens, lazy-geladen │ ├── components/UI.jsx StatusBadge, Modal, FormField, … │ ├── components/Update* Auto-Update-UI │ ├── print/ PrintComponents.jsx — alle Druckansichten │ └── utils/updater.js @tauri-apps/plugin-updater Wrapper │ ├── supabase/migrations/ Postgres-Schema für Cloud-Variante │ ├── src-tauri/ Rust-Backend (Tauri 2.10.3) │ ├── src/lib.rs ~103 Z. — Tray, Window-Events, Plugins │ ├── tauri.conf.json Updater-URL, Public-Key, CSP, Bundle-Targets │ └── capabilities/ Tauri Permissions │ ├── scripts/release.sh Build + Sign + latest.json erzeugen ├── latest.json Updater-Manifest └── deploy/ Docker-Compose für Web-Modus","voraussetzungen#Voraussetzungen":"Tool Version Node.js ≥ 20 (für Vite 8) npm ≥ 10 Rust toolchain ≥ 1.77.2 (via rustup) Plattform-Tools siehe Tauri Prerequisites Plattform-spezifisch:\nmacOS: Xcode Command Line Tools (xcode-select --install) Windows: Microsoft C++ Build Tools + WebView2 Linux: webkit2gtk-4.1, librsvg2-dev, libayatana-appindicator3-dev, build-essential","web-modus-hmr-schnellster-loop#Web-Modus (HMR, schnellster Loop)":"npm run dev # http://localhost:3000 Hot-Module-Replacement Schnellster Iteration-Loop für UI-Arbeit Datenpersistierung: Browser-localStorage","web-statisches-bundle#Web (statisches Bundle)":"npm run build # Output: dist/ (~500 KB) Für Hosting auf einem Static-Server (z. B. Nginx, Caddy, GitHub Pages). Siehe Web-Modus."},"title":"Entwicklung"},"/docs/erste-schritte/":{"data":{"":"Von der Installation bis zur ersten Rechnung — in sechs Schritten.","01--installation#01 · Installation":"DMG von Gitea Releases herunterladen. Rapport in den Programme-Ordner ziehen. Beim ersten Start: Systemeinstellungen → Datenschutz \u0026 Sicherheit öffnen und Rapport zulassen.\nDie Pre-Release-Builds sind signiert über Tauri, aber (noch) nicht über die Apple-Notarisierung gegangen — daher der manuelle Freigabe-Schritt.","02--einrichtung#02 · Einrichtung":"In den Einstellungen hinterlegen:\nBürodaten — Name, Adresse, IBAN, Logo Mitarbeiter — Namen, Pensum, Stundensatz, Ferienanspruch Kunden — Adresse, Ansprechperson, Honorartyp Projekte — SIA-102-Phasen, Budget, Beteiligte Danach ist die Zeiterfassung bereit.","03--zeiterfassung#03 · Zeiterfassung":"Im Modul Zeit:\nMitarbeiter wählen Woche navigieren Stunden per Klick oder Drag erfassen Jedem Eintrag ein Projekt zuweisen Auswertungen pro Mitarbeiter und pro Projekt sind unter Zeit → Auswertungen abrufbar. Halbe Tage und Mehrfacheinträge pro Slot werden unterstützt.","04--rechnungen#04 · Rechnungen":"Aus einer Offerte oder direkt erstellen:\nSIA-Phasen, Stundensatz oder Pauschal wählen Akonto-, Teil- oder Schlussrechnung Mit PDF exportieren wird die fertige Rechnung inkl. QR-Einzahlungsschein generiert Offerten lassen sich nahtlos in Projekte und Rechnungen konvertieren.","05--backup#05 · Backup":"In der Desktop-App liegen alle Daten als JSON im Applikationsordner:\n~/Library/Application Support/com.rapport.app/ Für ein Backup reicht es, diesen Ordner zu kopieren — z. B. auf einen externen Datenträger oder in die Cloud. Empfohlen: regelmässig (wöchentlich oder via Time Machine). Im Server-Modus läuft das Backup über Postgres-Dumps — siehe Rapport Server § Backup.","06--probleme-melden#06 · Probleme melden":"Ein Issue auf Gitea erstellen — mit kurzer Beschreibung, was passiert ist. Screenshots helfen. Bitte die Rapport-Version (links unten in der App) angeben.\nTipp: Wenn die App nicht mehr startet, hilft oft, den Cache-Ordner zu sichern und neu zu starten. Die JSON-Daten selbst bleiben unverändert."},"title":"Erste Schritte"},"/docs/installation/":{"data":{"":"Schritt-für-Schritt-Anleitung für die Installation der Desktop-App.","1--download#1 · Download":"Aktueller Build: Downloads-Seite oder direkt Releases auf Gitea .\nDatei Plattform RAPPORT__aarch64.dmg macOS Apple Silicon RAPPORT__x86_64.dmg macOS Intel (auf Anfrage)","2--dmg-öffnen--installieren#2 · DMG öffnen \u0026amp; installieren":"DMG doppelklicken Rapport.app in den Applications-Ordner ziehen DMG auswerfen","3--erster-start-macos-gatekeeper#3 · Erster Start (macOS Gatekeeper)":"Beim ersten Start verweigert macOS den Start, weil die Pre-Release-Builds Tauri-signiert, aber (noch) nicht Apple-notarisiert sind.","4--erstes-setup#4 · Erstes Setup":"Beim ersten Start zeigt Rapport den Setup-Bildschirm. Hier werden die Stammdaten erfasst — siehe Einrichtung.","5--update-strategie#5 · Update-Strategie":"Ab Version 0.7.0 prüft Rapport beim Start automatisch auf neue Versionen (siehe Auto-Updater). Updates können in den Einstellungen deaktiviert werden.\nManuelle Updates: einfach das neuere DMG installieren — die Daten bleiben erhalten, da sie unabhängig von der App liegen (siehe Datenhaltung).","alternative-terminal#Alternative (Terminal)":"Falls der GUI-Weg nicht funktioniert:\nxattr -d com.apple.quarantine /Applications/Rapport.app Das entfernt das Quarantäne-Flag und macOS akzeptiert den Start.","bekannte-probleme#Bekannte Probleme":"Problem Lösung App lässt sich nicht öffnen trotz Freigabe Terminal-Variante mit xattr “Rapport is damaged” DMG erneut von Gitea ziehen (Browser-Cache hat evtl. Müll) Schwarzer Bildschirm beim Start ~/Library/WebKit/com.rapport.app löschen, neu starten Mehr unter Troubleshooting.","deinstallation#Deinstallation":"# App entfernen rm -rf /Applications/Rapport.app # Daten entfernen (optional!) rm -rf \"~/Library/Application Support/com.rapport.app\" # Caches rm -rf \"~/Library/Caches/com.rapport.app\" rm -rf \"~/Library/WebKit/com.rapport.app\" Achtung: Schritt 2 löscht alle Rapport-Daten unwiederbringlich. Vorher Backup machen — siehe Datenhaltung.","lösung#Lösung":"Systemeinstellungen → Datenschutz \u0026 Sicherheit öffnen Bis ganz nach unten scrollen — es erscheint: “Rapport” wurde blockiert, da es nicht von einem identifizierten Entwickler stammt.\nAuf “Trotzdem öffnen” klicken Bestätigen Ab dem zweiten Start läuft Rapport ohne Rückfragen.","voraussetzungen#Voraussetzungen":"Plattform Status Versionen macOS Apple Silicon (M1 – M4) ✅ Unterstützt macOS 12+ macOS Intel ⚠ Build auf Anfrage macOS 12+ Linux 🕐 Geplant — Windows 🕐 Geplant — Eine Portierung auf Linux und Windows ist mit Tauri 2 möglich. Issue erstellen , wenn du eine Plattform brauchst."},"title":"Installation"},"/docs/troubleshooting/":{"data":{"":"Typische Probleme und Lösungen. Wenn dein Problem nicht dabei ist → Issue auf Gitea .","app-startet-nicht#App startet nicht":"","app-startet-zeigt-aber-schwarzen-bildschirm#App startet, zeigt aber schwarzen Bildschirm":"Ursache: WebView-Cache korrupt.\nLösung:\nrm -rf \"~/Library/Caches/com.rapport.app\" rm -rf \"~/Library/WebKit/com.rapport.app\" App neu starten. Daten gehen dabei nicht verloren (liegen in Application Support, nicht im Cache).","app-stürzt-sofort-beim-start-ab#App stürzt sofort beim Start ab":"Ursache: wahrscheinlich beschädigte JSON-Daten in studio_data_v1.\nDiagnose:\n# Daten ansehen (DevTools-Output) open \"~/Library/Application Support/com.rapport.app\" Lösung:\nBackup wiederherstellen (siehe Datenhaltung) Oder als letzter Ausweg: Daten zurücksetzen mv \"~/Library/Application Support/com.rapport.app\" \\ \"~/Library/Application Support/com.rapport.app.bad\" App neu starten → erstellt frische Daten. Anschliessend Setup-Screen.","auto-update-findet-nichts#Auto-Update findet nichts":"Diagnose:\ncurl -s https://git.kgva.ch/karim/RAPPORT/raw/branch/main/APP/latest.json → sollte JSON liefern. Wenn nicht: Server-/Netzwerkproblem.","daten-weg#Daten weg":"","debug-informationen-sammeln#Debug-Informationen sammeln":"Bei einem Issue helfen folgende Infos:\n# Rapport-Version defaults read /Applications/Rapport.app/Contents/Info.plist CFBundleShortVersionString # macOS-Version sw_vers # Architektur uname -m # Datenverzeichnis-Grösse du -sh \"~/Library/Application Support/com.rapport.app\" # Cache-Verzeichnis-Grösse du -sh \"~/Library/Caches/com.rapport.app\" → Bei Issue mit anhängen.","diese-version-überspringen-rückgängig-machen#\u0026ldquo;Diese Version überspringen\u0026rdquo; rückgängig machen":"In Einstellungen → Updates → Übersprungene Versionen zurücksetzen. Beim nächsten Start wird die Version wieder angeboten.","localstorage-voll#localStorage voll":"Symptom: Rapport schreibt Fehler-Toast “Speicher voll” beim Sichern.\nUrsache: macOS WebView limitiert localStorage auf ~10 MB pro Origin.\nLösung:\nSehr grosse Logos durch kleinere ersetzen (Bürodaten → Logo) Belege (Spesen) selektiv löschen oder als externe Datei archivieren Auf Web-Modus wechseln (Postgres ohne praktisches Limit)","login-screen-zeigt-keine-server-url#Login-Screen zeigt keine Server-URL":"Ursache: .env.production enthielt nicht den richtigen VITE_SUPABASE_URL zur Build-Zeit.\nLösung: .env.production prüfen, dann npm run build neu, Container restart.","nach-einem-app-update-fehlen-einträge#Nach einem App-Update fehlen Einträge":"Ursache: mögliche fehlgeschlagene Migration.\nSofortmassnahme:\nRapport beenden (Cmd+Q, nicht nur Fenster zu) Aktuelles Datenverzeichnis sichern: cp -R \"~/Library/Application Support/com.rapport.app\" \\ \"~/Documents/Rapport-Notfall-$(date +%Y%m%d-%H%M)\" Issue erstellen mit: Version vor dem Update (falls bekannt) Version nach dem Update Was fehlt Optional: gesicherter Datenordner (via Pastebin oder verschlüsselt zugesandt)","pdf--qr-schein#PDF / QR-Schein":"","pdf-export-ist-leer--weisses-blatt#PDF-Export ist leer / weisses Blatt":"Ursache: Print-View hat keine Daten (möglicherweise Race-Condition beim Laden).\nLösung: Rechnung schliessen, erneut öffnen, dann PDF.","pdf-schrift-sieht-falsch-aus#PDF-Schrift sieht falsch aus":"Ursache: Web-Schrift nicht geladen, Fallback greift.\nLösung: Vor dem Drucken warten, bis das Vorschau-Bild komplett geladen ist (3–5 Sek).","qr-schein-hat-falsche-daten#QR-Schein hat falsche Daten":"Diagnose-Checkliste:\nIBAN korrekt? (CH, 21 Zeichen, keine Leerzeichen) Empfänger-Adresse vollständig? (PLZ und Ort beide gefüllt) Schuldner-Adresse vollständig? Betrag \u003e 0? Referenz nicht zu lang? (max 27 Zeichen) QR-Bibliothek: swissqrbill — bei merkwürdigen Fehlern dort nachschauen.","rapport-ist-beschädigt-beim-ersten-start#\u0026ldquo;Rapport ist beschädigt\u0026rdquo; beim ersten Start":"Ursache: macOS Gatekeeper blockt unsignierte/nicht-notarisierte Apps.\nLösung: siehe Installation § 3. Kurz:\nxattr -d com.apple.quarantine /Applications/Rapport.app","realtime-updates-kommen-nicht-an#Realtime-Updates kommen nicht an":"Ursache: Websocket-Support fehlt im Reverse Proxy.\nLösung: In Nginx Proxy Manager für api.* Websocket Support aktivieren.\nSiehe Web-Modus § Troubleshooting.","system-tray#System-Tray":"","tray-icon-erscheint-nicht#Tray-Icon erscheint nicht":"Plattform-Hinweis: Tray-Icons unter macOS sind bei extrem voller Menüleiste oder unter “Bartender”/“Hidden Bar” eventuell unsichtbar.\nDiagnose:\nps aux | grep -i rapport → wenn Prozess läuft, aber kein Icon: in den Tray-Manager-Apps prüfen.\nKonfiguration: Einstellungen → System-Tray → Tray-Icon ausblenden (aus → Icon erzwingen).","tray-menü-reagiert-nicht--hängt#Tray-Menü reagiert nicht / hängt":"Lösung: App via Activity Monitor hart beenden und neu starten. Daten gehen nicht verloren (alle Schreibungen sind synchron in localStorage).","update-lädt-lässt-sich-aber-nicht-installieren#Update lädt, lässt sich aber nicht installieren":"Ursache: Signaturprüfung scheitert (Public-Key in App ≠ Signatur in latest.json).\nLösung: Manuelles Update — DMG direkt von Releases laden und installieren. Daten bleiben erhalten.","updates#Updates":"","web-modus#Web-Modus":"","wenn-nichts-hilft#Wenn nichts hilft":"Neues Issue auf Gitea mit:\nWas du gemacht hast Was passiert ist Was du erwartet hättest Screenshots (auch von DevTools-Konsole falls möglich) Rapport-Version und macOS-Version"},"title":"Troubleshooting"},"/docs/web-modus/":{"data":{"":"Hinweis: Der frühere Supabase-basierte Web-Modus wurde durch Rapport Server abgelöst — den vollständigen Selfhost-Stack mit eigenem Postgres, Auth, Realtime und Storage. Keine externe Cloud-Abhängigkeit mehr.\nDiese Seite bleibt als Referenz erhalten, der empfohlene Weg für Multi-User-Setups ist Rapport Server.","architektur-kurzfassung#Architektur (Kurzfassung)":"┌────────────┐ HTTPS ┌──────────────┐ SQL ┌────────────┐ │ Browser │ ──────────────│ nginx │ ─────────────│ Postgres │ │ / Desktop │ │ (Frontend) │ │ + GoTrue │ └────────────┘ └──────────────┘ │ + REST │ │ + Realtime │ │ + Storage │ └────────────┘ Frontend: dieselbe React-App, aber Vite-Build statt Tauri (npm run build) Backend: Postgres-Stack (Rapport Server) Auth: E-Mail / Passwort über GoTrue Storage: Belege, Logos in Object-Storage","migration-desktop--cloud#Migration Desktop → Cloud":"Wer mit der Desktop-App startet und später auf den Web-Modus wechseln möchte:\nAktuell: manueller Export aus Rapport (CSV/PDF) und manuelles Wiederanlegen im neuen Setup Geplant: “localStorage → Postgres”-Import-Knopf direkt in der App Status: Issue auf Gitea .","setup#Setup":"Alle Setup-Schritte (Repo klonen, .env erstellen, Migrations syncen, Docker-Compose starten, Reverse-Proxy konfigurieren) sind in Rapport Server dokumentiert.","troubleshooting#Troubleshooting":"Siehe Rapport Server § Troubleshooting oder allgemeine Troubleshooting-Seite.","wann-brauchst-du-das#Wann brauchst du das?":"Anwendungsfall Empfehlung Solo-Büro, ein Mac Desktop-App — siehe Installation 2–5 Personen, gleicher Standort Rapport Server auf einem Mac Mini im LAN Verteiltes Team / Home-Office Rapport Server mit SSL + Reverse Proxy Hosted Backend (eigener VPS) Rapport Server auf Linux-VPS"},"title":"Web-Modus"},"/downloads/":{"data":{"":"Aktuelle Builds von Rapport. Quellcode und ältere Versionen auf Gitea .\nRapport besteht aus zwei Komponenten:\nKomponente Für wen Aktuelle Version Desktop-App Solo-Büro, lokale Datenhaltung 0.8.3 Rapport Server Team / Multi-User / Selfhost 0.1.0","auto-update#Auto-Update":"Seit 0.7.0 prüft die Desktop-App beim Start automatisch auf neue Versionen — siehe Auto-Updater. Für Rapport Server: git pull \u0026\u0026 docker compose pull \u0026\u0026 docker compose up -d.","desktop-app--pre-release-083#Desktop-App — Pre-Release 0.8.3":"Aktuelle Version\nNeuerungen — siehe Changelog für Details.","docker-linux--vps--headless#Docker (Linux / VPS / Headless)":"Für Linux-Server, NAS oder VPS — der reine Docker-Compose-Stack ohne GUI.\ngit clone https://git.kgva.ch/karim/rapport-server.git cd rapport-server git checkout 0.1.0 cp .env.example .env # .env editieren (POSTGRES_PASSWORD, JWT_SECRET, SITE_URL) docker compose up -d Vollständige Anleitung mit .env-Variablen, Reverse-Proxy und Backup → Server-Seite.\nContainer-Images werden von Docker Hub / Gitea-Registry gezogen — docker compose pull aktualisiert auf die neuesten Tags.","linux--windows#Linux \u0026amp; Windows":"Geplant. Rapport basiert auf Tauri 2 — eine Portierung ist möglich, sobald der Bedarf besteht. Issue erstellen , wenn du eine Plattform brauchst.","macos#macOS":"Architektur Download Apple Silicon (M1–M4) RAPPORT_0.8.3_aarch64.dmg Intel (x86_64) auf Anfrage Erstinstallation: Systemeinstellungen → Datenschutz \u0026 Sicherheit öffnen und Rapport zulassen. Die Builds sind über Tauri signiert, aber (noch) nicht Apple-notarisiert.","quellcode#Quellcode":"Desktop-App — Tauri / React:\ngit clone https://git.kgva.ch/karim/RAPPORT.git cd RAPPORT/APP npm install npm run tauri dev Voraussetzungen: Node 20+, Rust (stable), Xcode-CLI (macOS).\nRapport Server:\ngit clone https://git.kgva.ch/karim/rapport-server.git Beide Repos auf Gitea — Issues und PRs willkommen.","rapport-server--010#Rapport Server — 0.1.0":"Erstes Release\nSelfhost-Backend für Multi-User-Setups — Postgres, Auth, Realtime-Sync, Storage. Details und Setup-Anleitung auf der Server-Seite.","server-app-macos#Server-App (macOS)":"GUI zum Starten, Stoppen und Verwalten der Server-Instanz auf einem Mac (Mac Mini, Studio-Rechner). Bündelt den Docker-Compose-Stack.\nArchitektur Download Apple Silicon (M1–M4) RAPPORT_SERVER_0.1.0_aarch64.dmg Intel (x86_64) auf Anfrage Voraussetzung: Colima oder Docker Desktop muss installiert sein. Die App verwaltet den Container-Stack darüber."},"title":"Downloads"},"/faq/":{"data":{"":"Häufige Fragen zu RAPPORT. Bei Bugs oder weiteren Fragen → Issue auf Gitea .","für-wen-ist-rapport-gedacht#Für wen ist Rapport gedacht?":"Für kleine Architekturbüros in der Schweiz. Die Strukturen folgen der SIA 102 (Phasen, Honorar). Rapport wurde für den internen Gebrauch entwickelt und wird mit diesem Projekt öffentlich geteilt.","ist-die-software-stabil-genug-für-den-betrieb#Ist die Software stabil genug für den Betrieb?":"Noch nicht. Aktuell befindet sich Rapport in aktiver Entwicklung (Pre-Release 0.8.3). Funktionen können sich ändern, Bugs sind möglich. Regelmässige Backups sind empfohlen. Testen und Feedback geben ist erwünscht.","ist-rapport-kostenlos#Ist Rapport kostenlos?":"Ja, vollständig. Quellcode unter GNU AGPL-3.0-or-later. Keine versteckten Kosten, keine Telemetrie. Die Daten bleiben lokal auf deinem Computer bzw. in deiner Instanz. Du hast die komplette Kontrolle über deine Daten.","kann-ich-zum-projekt-beitragen#Kann ich zum Projekt beitragen?":"Ja. Issues und Pull Requests sind willkommen auf Gitea . Rapport ist kein Framework — konkrete Verbesserungen für den Büroalltag sind am wertvollsten:\nBug-Reports mit Reproduktionsschritten Workflow-Verbesserungen aus dem realen Büroalltag Vorlagen (Briefe, Protokolle, Lieferscheine) für andere Büros Übersetzungen / Internationalisierung","warum-open-source#Warum Open Source?":"Bürowissen sollte nicht in proprietären Tools eingesperrt sein. Studio-Management-Workflows sind in der Branche gut etabliert — ein Tool, das die Schweizer Konventionen (SIA 102, QR-Rechnung) sauber umsetzt, gehört allen.\nAGPL-3.0 stellt sicher, dass Verbesserungen wieder ins Projekt fliessen.","was-ist-mit-dem-qr-einzahlungsschein#Was ist mit dem QR-Einzahlungsschein?":"Rapport erzeugt Schweizer QR-Rechnungen nach Norm — direkt eingebettet in das PDF der Rechnung. IBAN, Bürodaten und Empfänger werden aus den Einstellungen bzw. den Kundendaten gezogen. Akonto-, Teil- und Schlussrechnungen werden unterstützt.","welche-systeme-werden-unterstützt#Welche Systeme werden unterstützt?":"Aktuell nur macOS (Intel \u0026 Apple Silicon). Rapport basiert auf Tauri — eine Portierung auf Linux und Windows ist möglich, sobald der Bedarf seitens Community besteht.","wie-erhalte-ich-hilfe-bei-einem-problem#Wie erhalte ich Hilfe bei einem Problem?":"Ein Issue auf Gitea ist der beste Weg. Bitte beschreibe, was du gemacht hast und was passiert ist. Screenshots helfen. Die Rapport-Version (links unten in der App) bitte angeben.\nKanal Verwendung Gitea Issues Bugs, Feature-Wünsche, allgemeine Fragen gabrielevarano.ch Entwickler-Kontakt","wie-funktioniert-die-zeiterfassung#Wie funktioniert die Zeiterfassung?":"Tages- und Wochenraster mit Drag \u0026 Drop. Jeder Eintrag wird einem Projekt zugewiesen. Auswertungen pro Mitarbeiter und Projekt sind unter Zeit abrufbar. Ferienverwaltung mit Prorata und Jahresabschluss mit Überstundenausgleich.","wo-werden-die-daten-gespeichert#Wo werden die Daten gespeichert?":"Rapport unterstützt zwei Modi, beide selbst-gehostet:\nDesktop-App (Single-User) — alle Daten liegen lokal auf deinem Mac (localStorage im Applikationsordner). Kein Server nötig, kein Cloud-Account, keine Telemetrie. Server-Modus (Multi-User) — Daten in einer eigenen PostgreSQL-Datenbank über Rapport Server. Mehrere Personen, Realtime-Sync, eigene Domain. Wechsel direkt im Login-Bildschirm der App. In beiden Fällen bleibt die Kontrolle über die Daten bei dir."},"title":"FAQ"},"/features/":{"data":{"":"Die Bausteine von RAPPORT — Studio-Management für Schweizer Architekturbüros.","module#Module":"ZeiterfassungTages- \u0026 Wochenraster mit Drag \u0026 Drop. Rechnungen \u0026 OffertenQR-Einzahlungsscheine, SIA-Phasen, Akonto. Projekt- \u0026 KundenverwaltungSIA 102, Budget, Phasen, Beteiligte. MitarbeiterFerien, Absenzen, Lohnabrechnung. Spesen \u0026 BürobudgetBelegupload, Jahresbudget, Internes. Protokolle \u0026 LieferscheineSitzungsprotokolle, Briefe, Lieferscheine. Auto-UpdaterSignierte Updates via Tauri. System-TrayHide-on-Close, Quick-Open."},"title":"Features"},"/features/auto-updater/":{"data":{"":"Neu in 0.7.0\nRapport prüft beim Start automatisch auf neue Versionen und installiert Updates signiert über Tauri. Einzelne Versionen können übersprungen werden.","funktionsweise#Funktionsweise":"Beim App-Start:\nAbfrage gegen https://git.kgva.ch/karim/RAPPORT/releases/latest.json Versionsvergleich mit lokaler version im Tauri-Bundle Bei neuer Version → Update-Dialog Bei Bestätigung → Download + Signaturprüfung + Installation + Neustart","latest-endpoint#Latest-Endpoint":"{ \"version\": \"0.8.3\", \"notes\": \"Rapport 0.8.3\", \"pub_date\": \"2026-05-24T00:00:00Z\", \"platforms\": { \"darwin-aarch64\": { \"signature\": \"…\", \"url\": \"https://git.kgva.ch/karim/RAPPORT/releases/download/0.8.3/RAPPORT%20PRE-RELEASE.app.tar.gz\" } } }","optionen#Optionen":"Update installieren — Download \u0026 Neustart Diese Version überspringen — überspringt nur diese eine Version Später erinnern — beim nächsten Start erneut fragen Updates können in den Einstellungen komplett deaktiviert werden.","sicherheit#Sicherheit":"Updates werden mit dem Tauri-Updater-Schlüssel signiert Manipulierte Downloads werden abgelehnt Quellcode und Build sind reproduzierbar (Gitea CI, geplant)"},"title":"Auto-Updater"},"/features/mitarbeiter/":{"data":{"":"In Arbeit\nFerienverwaltung, interne Stunden / Absenzen und Lohnabrechnung. Jahresabschluss mit Überstundenausgleich.","absenzen#Absenzen":"Krankheit, Militär, Mutterschaft, unbezahlter Urlaub — getrennt erfasst, mit Auswertung pro Mitarbeiter.","ferienverwaltung#Ferienverwaltung":"Prorata-Berechnung bei Eintritt unter Jahr Ferien-Saldo in Tagen (live) Halbtage unterstützt Übertrag ins Folgejahr oder Auszahlung","jahresabschluss#Jahresabschluss":"Ferien-Restguthaben übertragen oder auszahlen Überstunden ausgleichen oder vergüten Lohnausweis vorbereiten (Export)","lohnabrechnung#Lohnabrechnung":"Monatliche Abrechnung mit:\nGrundlohn (basierend auf Pensum) Überstunden-Vergütung Spesen-Erstattung Sozialabzüge (AHV, ALV, Pensionskasse) PDF-Export pro Mitarbeiter.","stammdaten#Stammdaten":"Pro Mitarbeiter:\nName, Eintrittsdatum, Pensum (%) Stundensatz (intern, für Rechnungen) Ferienanspruch (Tage / Jahr) Lohn (monatlich, brutto)","verwandte-module#Verwandte Module":"Zeiterfassung — Pensum-Soll vs. Stunden-Ist Spesen — Spesen-Erstattung in der Lohnabrechnung"},"title":"Mitarbeiter"},"/features/projekte/":{"data":{"":"In Arbeit\nProjekte nach SIA 102 mit Budget, Phasen und Beteiligten. Erstellung aus einer Offerte mit Verknüpfung zu Zeiterfassung und Rechnungen.","auswertung#Auswertung":"Pro Projekt:\nGeleistete Stunden vs. Budget Honorar-Saldo (verrechnet / Akonto / offen) Phasen-Fortschritt","kundendatenbank#Kundendatenbank":"Adresse, Ansprechperson, Telefon, E-Mail Honorartyp (Stundensatz / SIA / Pauschal) Verknüpfung zu allen Projekten und Rechnungen des Kunden","projektstruktur#Projektstruktur":"Jedes Projekt besitzt:\nStammdaten — Nummer, Bezeichnung, Standort, Bauschätzwert Kunde — verknüpft mit Kundendatenbank Beteiligte — Bauleitung, Fachplaner, Behörden Phasen — SIA 102 (Vorprojekt, Bauprojekt, Ausschreibung, …) Budget — Gesamthonorar, pro Phase aufgeteilt","sia-102#SIA 102":"Standard-Phasenverteilung wird vorgeschlagen, kann pro Projekt überschrieben werden.\nPhase Anteil (Standard) 31 — Vorprojekt 9 % 32 — Bauprojekt 21 % 33 — Bewilligung 3 % 41 — Ausschreibung 18 % 51 — Ausführung 38 % 52 — Inbetriebnahme 6 % 53 — Abschluss 5 %","verwandte-module#Verwandte Module":"Rechnungen — Offerte → Projekt Zeiterfassung — Stunden-Auswertung pro Phase"},"title":"Projekte"},"/features/protokolle/":{"data":{"":"In Arbeit\nEinfache Erstellung von Sitzungsprotokollen mit Beschlüssen und Aufgaben. Briefe und Lieferscheine im gleichen Erscheinungsbild.","briefe#Briefe":"Brief-Editor mit:\nEmpfänger aus Kundendatenbank Bezugszeile, Anrede, Text, Grussformel Briefbogen-Vorlage mit Logo PDF-Export","lieferscheine#Lieferscheine":"Pro Lieferung:\nEmpfänger, Datum, Bezug Positionen (Plan-Nummer, Bezeichnung, Anzahl, Massstab) Unterschriftenfeld Konsistentes Erscheinungsbild über alle Dokumenttypen — eine Briefbogen-Vorlage, mehrere Verwendungen.","sitzungsprotokolle#Sitzungsprotokolle":"Pro Sitzung:\nDatum, Ort, Teilnehmer (aus Beteiligten-Liste) Traktanden als nummerierte Liste Pro Traktandum: Beschluss, Aufgabe, Verantwortlich, Frist Anhänge PDF-Export mit Bürobriefbogen.","verwandte-module#Verwandte Module":"Projekte — Beteiligte als Empfänger"},"title":"Protokolle"},"/features/rechnungen/":{"data":{"":"In Arbeit\nQR-Einzahlungsscheine, SIA-Phasen, Akonto-, Teil- und Schlussrechnungen. Offerten sind in Projekte und Rechnungen konvertierbar. PDF-Export.","honorarmodelle#Honorarmodelle":"Modell Berechnung Verwendung Stundensatz Aus Zeiterfassung × Mitarbeiter-Stundensatz Kleinaufträge, Beratung SIA-Phasen Bauschätzwert × Honorarsatz × Phasenanteil Reguläre Architektur-Aufträge Pauschal Fester Betrag Auf Wunsch des Kunden","pdf-export#PDF-Export":"Druckfertige Rechnung inkl. QR-Schein. Layout aus dem Büro-Briefbogen (mit Logo). Mehrsprachig DE/FR/IT (geplant).","qr-einzahlungsschein#QR-Einzahlungsschein":"Schweizer QR-Rechnung nach Norm — direkt eingebettet in die PDF.\nAusgelesen aus:\nBürodaten — IBAN, Empfänger-Adresse Kundendaten — Schuldner-Adresse Rechnungs-Daten — Betrag, Referenz, Zusatzinformation","verwandte-module#Verwandte Module":"Projekte — Honorarstruktur stammt aus dem Projekt Zeiterfassung — Stundensatz-Rechnungen","workflow#Workflow":"Offerte erstellen — auf Basis SIA 102 oder pauschal Kunde nimmt an → konvertieren in Projekt + Rechnung Akonto-Rechnungen während der Projektlaufzeit Schlussrechnung mit Differenz zum bisher Akonto-bezahlten"},"title":"Rechnungen"},"/features/spesen/":{"data":{"":"In Arbeit\nSpesenerfassung mit Belegupload. Jahresbudget mit Einnahmen und Ausgaben. Internes Rechnungswesen.","auswertung#Auswertung":"Einnahmen pro Kunde / Projekt Ausgaben pro Kategorie / Mitarbeiter Erfolgsrechnung pro Geschäftsjahr (vereinfacht)","jahresbudget#Jahresbudget":"Übersicht über:\nEinnahmen — Rechnungsbeträge, sortiert nach Eingang Ausgaben — Spesen, Bürokosten, Löhne, Sozialabzüge Saldo pro Monat / Quartal / Jahr","spesenerfassung#Spesenerfassung":"Pro Mitarbeiter:\nDatum, Betrag, Kategorie Beleg-Upload (PDF, JPG, PNG) Projekt-Zuordnung (optional) Status (offen / erstattet) Kategorien: Reise, Verpflegung, Material, Telefon, Sonstiges.","verwandte-module#Verwandte Module":"Mitarbeiter — Spesen-Erstattung in der Lohnabrechnung Rechnungen — Einnahmen-Quelle"},"title":"Spesen"},"/features/system-tray/":{"data":{"":"Neu in 0.7.0\nSchnellzugriff über die Menüleiste mit Hide-on-Close. Beim Schliessen läuft Rapport im Hintergrund weiter — Cmd+Q beendet die App vollständig.","konfiguration#Konfiguration":"In den Einstellungen:\nBeim Systemstart starten (Login-Item) — Standard: aus Beim Schliessen beenden statt ins Tray — Standard: aus Tray-Icon ausblenden — App läuft, aber kein Menüleisten-Icon","tray-menü#Tray-Menü":"Rapport zeigen — Fenster nach vorne Neue Zeiterfassung — direkt im Zeit-Modul Neue Rechnung — direkt im Rechnungs-Modul Letzte Projekte — Quick-Open der letzten 5 Projekte Einstellungen Rapport beenden","verhalten#Verhalten":"Aktion Verhalten Fenster schliessen (⌘W oder rotes X) App läuft im Tray weiter Cmd+Q App wird vollständig beendet Klick auf Tray-Icon Fenster nach vorne, oder zeigen Rechtsklick auf Tray-Icon Menü mit Schnellzugriffen","verwandte-module#Verwandte Module":"Auto-Updater — prüft Updates im Hintergrund"},"title":"System-Tray"},"/features/zeiterfassung/":{"data":{"":"In Arbeit\nTages- und Wochenraster mit Drag \u0026 Drop. Auswertungen pro Mitarbeiter und Projekt. Ferienverwaltung mit Prorata und Jahresabschluss.","auswertungen#Auswertungen":"Pro Mitarbeiter und pro Projekt:\nGeleistete Stunden vs. Soll-Pensum Ferienanspruch / -saldo (mit Prorata bei Eintritt unter Jahr) Überstunden-Saldo Stundenaufschlüsselung nach SIA-Phase pro Projekt","eingabe#Eingabe":"Wochenraster mit den 5 (oder 7) Arbeitstagen Halbstunden-Slots von 06:00 bis 22:00 Klick oder Drag über mehrere Slots Jeder Eintrag wird einem Projekt zugewiesen (Pflichtfeld) Mehrfacheinträge pro Slot möglich (z. B. parallele Telefonate)","jahresabschluss#Jahresabschluss":"Am Jahresende:\nFerien-Restguthaben übertragen oder auszahlen Überstunden ausgleichen oder vergüten Neues Jahr automatisch initialisieren","konzept#Konzept":"Die Zeiterfassung ist das Kernmodul von RAPPORT — alle anderen Module (Rechnungen, Auswertungen, Lohnabrechnung) greifen auf die hier erfassten Stunden zu.","verwandte-module#Verwandte Module":"Rechnungen — Stundensatz-Rechnungen ziehen direkt aus der Zeiterfassung Projekte — Stunden-Auswertung pro SIA-Phase Mitarbeiter — Pensum, Ferienanspruch"},"title":"Zeiterfassung"},"/glossary":{"data":{},"title":"Glossary"},"/lizenz/":{"data":{"":"Lizenz von RAPPORT, Zugehörigkeit zu OpenBureau und Attribution der verwendeten Open-Source-Software.","desktop-wrapper#Desktop-Wrapper":"Software Verwendung Lizenz Tauri 2 Cross-Platform Desktop-Wrapper MIT / Apache-2.0 WebKit WebView-Engine (macOS) LGPL-2.1 / BSD","diese-website#Diese Website":"Software Verwendung Lizenz Hugo Static-Site-Generator Apache-2.0 Hextra Hugo-Theme (von Xin) MIT Inter UI-Schrift (Rasmus Andersson) SIL OFL 1.1 Playfair Display Headings SIL OFL 1.1 Alle Logos und Marken-Namen gehören ihren jeweiligen Eigentümern.","frontend#Frontend":"Software Verwendung Lizenz React 19 UI-Bibliothek MIT Vite Build-Tool, Dev-Server MIT swissqrbill QR-Einzahlungsscheine MIT","kontakt#Kontakt":"Fragen zur Lizenz, kommerzieller Einsatz, Spezialfälle: Issue auf Gitea oder via gabrielevarano.ch .","lizenz#Lizenz":"Lizenziert unter GNU Affero General Public License v3.0 oder höher (AGPL-3.0-or-later ).\nDies bedeutet im Kern:\nFreie Nutzung für jeden Zweck (privat, kommerziell, behördlich) Freier Zugang zum Quellcode Freie Modifikation und Weitergabe — unter derselben Lizenz Netzwerk-Nutzung gilt als Weitergabe — wer eine modifizierte Version als Service anbietet, muss den Quellcode offenlegen Eigene Builds, eigene Forks, eigene Anpassungen — alles erlaubt, solange Modifikationen wieder unter AGPL-3.0 veröffentlicht werden.","lizenz-volltexte#Lizenz-Volltexte":"Die vollständigen Lizenztexte:\nAGPL-3.0 — RAPPORT MIT — React, Vite, Tauri, Hextra, swissqrbill Apache-2.0 — Tauri, Hugo, Supabase SIL OFL 1.1 — Inter, Playfair Display","mitwirkende#Mitwirkende":"RAPPORT wird derzeit als Ein-Personen-Projekt von Karim Gabriele Varano entwickelt. Beiträge — Code, Issues, Übersetzungen, Vorlagen — sind willkommen.\nWer beitragen möchte → Gitea Issues .","openbureau#OpenBureau":"RAPPORT ist Teil der OpenBureau-Initiative — einer Sammlung freier Software-Werkzeuge für den Architektur-Büro-Alltag.\nDie Idee: Bürowissen — Workflows, Konventionen, Vorlagen — sollte nicht in proprietären Tools eingesperrt sein. OpenBureau-Tools setzen die in der Branche etablierten Konventionen (SIA-Normen, QR-Rechnung, Plan-Verwaltung) sauber um und stehen unter freien Lizenzen zur Verfügung.\nTool Zweck Status RAPPORT Studio-Management Desktop-App (Zeit, Rechnungen, Projekte) Pre-Release Rapport Server Selfhost-Stack (Postgres + Auth + Realtime + Storage) Pre-Release DOSSIER Rhino-8-Plugin für Plan- und Dokumentationsausgabe Pre-Release Mehr unter gabrielevarano.ch .","rapport#RAPPORT":"RAPPORT — Studio Management Software für Architekturbüros.\nQuellcode: git.kgva.ch/karim/RAPPORT Autor: Karim Gabriele Varano","rapport-server-selfhost-stack#Rapport Server (Selfhost-Stack)":"Software Verwendung Lizenz PostgreSQL Datenbank PostgreSQL-Lizenz GoTrue Authentication-Service MIT PostgREST REST-API über Postgres-Schema MIT Realtime WebSocket-Sync Apache-2.0 Storage Object-Storage für Belege \u0026 Logos Apache-2.0 Kong API-Gateway Apache-2.0 nginx Frontend-Webserver BSD-2-Clause Docker Compose Orchestrierung Apache-2.0","verwendete-open-source-software#Verwendete Open-Source-Software":"RAPPORT baut auf freier Software auf. Diese Liste nennt die wichtigsten Komponenten und ihre jeweiligen Lizenzen."},"title":"Lizenz"},"/server/":{"data":{"":"Self-Hosting\nRapport Server — der vollständige Selfhost-Stack für Rapport. Eigene Daten, eigene Domain, eigener Server. Komplett Open-Source, Docker-Compose, AGPL-3.0.","1--repo-klonen#1 · Repo klonen":"git clone https://git.kgva.ch/karim/rapport-server.git cd rapport-server","2--env-erstellen#2 · \u003ccode\u003e.env\u003c/code\u003e erstellen":"cp .env.example .env In .env müssen mindestens diese Werte ersetzt werden:\nVariable Was POSTGRES_PASSWORD DB-Passwort (≥ 32 Zeichen, zufällig) JWT_SECRET JWT-Signatur (≥ 32 Zeichen, zufällig) ANON_KEY / SERVICE_ROLE_KEY aus JWT-Secret abgeleitet SITE_URL Public-URL der Instanz (z. B. https://app.rapport.studio.ch) Zufallswerte generieren:\nopenssl rand -hex 32 # für POSTGRES_PASSWORD und JWT_SECRET node scripts/generate-keys.mjs # ANON_KEY + SERVICE_ROLE_KEY aus JWT_SECRET","3--migrations-holen#3 · Migrations holen":"Die SQL-Migrations stammen aus dem App-Repo. Einmal initial holen:\n./scripts/sync-migrations.sh Bei späteren Rapport-Updates erneut ausführen, dann docker compose down \u0026\u0026 docker compose up -d.","4--stack-starten#4 · Stack starten":"docker compose up -d Erststart dauert ~1 Minute (Postgres initialisiert sich, Migrations laufen, Container starten).","5--health-check#5 · Health-Check":"docker compose ps Alle Container sollten healthy zeigen. Frontend ist dann erreichbar unter http://localhost:8080.","architektur#Architektur":"Rapport Server bündelt sechs Open-Source-Komponenten zu einem stimmigen Stack:\n┌──────────────────────────────────────────────────────┐ │ Browser / Desktop-App │ └──────────────┬───────────────────────┬───────────────┘ │ │ ▼ ▼ ┌──────────┐ ┌──────────┐ │ nginx │ │ Kong │ ← API-Gateway │ (app) │ │ │ └──────────┘ └──────────┘ │ ┌───────────────────┼─────────────────────┐ ▼ ▼ ▼ ┌────────┐ ┌──────────┐ ┌─────────┐ │ GoTrue │ │PostgREST │ │ Realtime│ │ (Auth) │ │ (API) │ │ (WS) │ └────────┘ └──────────┘ └─────────┘ │ │ │ └───────────────────┼─────────────────────┘ ▼ ┌─────────────────┐ │ PostgreSQL │ └─────────────────┘ │ ▼ ┌─────────────────┐ │ Storage │ ← Belege, Logos └─────────────────┘ Komponente Funktion PostgreSQL Datenbank — alle Rapport-Daten GoTrue Authentication — Email/Passwort, JWT-Tokens PostgREST REST-API direkt aus dem Postgres-Schema Realtime WebSocket-Sync für Live-Updates Storage Object-Storage für Belege \u0026 Logos Kong API-Gateway, routet alle Calls app (nginx) Liefert das Rapport-Frontend (React-Build) Alles in einem Docker-Compose. Keine Cloud-Abhängigkeit, keine Telemetrie.","backup#Backup":"","bezug-rapport--rapport-server#Bezug Rapport ↔ Rapport Server":"Komponente Wo Lizenz Rapport Desktop-App git.kgva.ch/karim/RAPPORT AGPL-3.0 Rapport Server git.kgva.ch/karim/rapport-server AGPL-3.0 Die Desktop-App kann wahlweise im Lokal-Modus (JSON, kein Server nötig) oder im Cloud-Modus (gegen Rapport Server) betrieben werden. Wechsel erfolgt im Login-Bildschirm der App.","brauche-ich-supabase-cloud#Brauche ich Supabase Cloud?":"Nein. Rapport Server ist die Selfhost-Variante derselben Komponenten (Postgres + GoTrue + PostgREST + Realtime + Storage), aber komplett auf eigener Infrastruktur. Kein Supabase-Account, keine externe Abhängigkeit.","häufige-fragen#Häufige Fragen":"","kann-ich-von-der-desktop-app-auf-rapport-server-migrieren#Kann ich von der Desktop-App auf Rapport Server migrieren?":"Im Login der Desktop-App auf Cloud wechseln, Server-URL eingeben, Account erstellen, Daten manuell wieder anlegen (Bürodaten, Mitarbeiter, Kunden). Ein direkter localStorage → Postgres-Import ist geplant .","postgres-dump#Postgres-Dump":"docker compose exec -T db pg_dumpall -U postgres \u003e backup-$(date +%Y%m%d).sql Empfohlen: per cron täglich + auf externe Disk / S3 / Backblaze sichern.","quellcode#Quellcode":"git.kgva.ch/karim/rapport-server — Issues, Pull Requests und Forks willkommen.","restore#Restore":"docker compose down docker volume rm rapport-server_postgres-data docker compose up -d db sleep 10 cat backup-YYYYMMDD.sql | docker compose exec -T db psql -U postgres docker compose up -d","reverse-proxy--https#Reverse-Proxy + HTTPS":"Für Production-Setups mit eigener Domain — Caddy ist die einfachste Variante (config-as-code, Let’s-Encrypt automatisch):\napp.rapport.studio.ch { reverse_proxy localhost:8080 } api.rapport.studio.ch { reverse_proxy localhost:8000 } In .env dann:\nSITE_URL=https://app.rapport.studio.ch API_EXTERNAL_URL=https://api.rapport.studio.ch Alternativ über Nginx Proxy Manager mit Web-UI — siehe Troubleshooting.","setup-in-5-schritten#Setup in 5 Schritten":"","storage-belege-logos#Storage (Belege, Logos)":"docker compose exec storage tar -czf - /var/lib/storage \u003e storage-$(date +%Y%m%d).tar.gz","updates#Updates":"git pull ./scripts/sync-migrations.sh # falls neue SQL-Migrationen docker compose pull # neueste Container-Versionen docker compose up -d # neu starten Daten bleiben erhalten — das Volume postgres-data wird nicht angetastet.","voraussetzungen#Voraussetzungen":"OS Container-Runtime Linux (Ubuntu 22.04+, Debian 12+, …) Docker Engine + Compose v2 macOS (Mac Mini etc.) Colima + Docker CLI — voll OSS Auf macOS funktionieren auch OrbStack oder Docker Desktop, beide sind aber proprietär. Colima ist die OSS-Alternative und für Selfhost vollkommen ausreichend.\nPlus: ein DNS-Name für TLS (z. B. rapport.studio.ch), und optional ein Reverse-Proxy wie Nginx Proxy Manager oder Caddy .","wann-brauchst-du-rapport-server#Wann brauchst du Rapport Server?":"Szenario Lösung Ein Mensch, ein Mac Desktop-App reicht — Installation Mehrere Personen im Studio Rapport Server auf einem Mac Mini oder Linux-Server Verteiltes Team, Home-Office, Mobile-Zugriff Rapport Server mit Reverse-Proxy + SSL Cloud-Hosting bei einem Anbieter Rapport Server auf VPS/Hetzner/etc. Die Desktop-App speichert lokal als JSON. Rapport Server bringt Postgres + Multi-User + Realtime-Sync — für alle, die zu zweit oder im Team arbeiten.","was-kostet-das#Was kostet das?":"Nichts — Rapport Server ist Open-Source (AGPL-3.0). Du brauchst nur einen Server (Mac Mini, NAS, VPS) und ggf. eine Domain.","wieviel-server-resourcen#Wieviel Server-Resourcen?":"Ein Mac Mini M1 (8 GB RAM) reicht problemlos für ein 5-Personen-Studio. Linux-VPS mit 2 GB RAM + 2 CPU reicht auch."},"title":"Server"}} \ No newline at end of file +{"/docs/":{"data":{"":"Vollständige Anleitung zu RAPPORT — von der Installation über den täglichen Arbeitsablauf bis zur Cloud-Variante und Eigen-Builds.","erste-schritte#Erste Schritte":"Quick-StartIn sechs Schritten von Null zur ersten Rechnung. InstallationmacOS, Gatekeeper, Signatur, geplante Plattformen. EinrichtungBürodaten, Mitarbeiter, Kunden, Projekte initial anlegen.","für-fortgeschrittene#Für Fortgeschrittene":"Web-Modus (Multi-User)Rapport im Browser via Supabase — für Studios mit mehreren Nutzern. Entwicklung \u0026 BuildAus dem Quellcode kompilieren, beitragen, eigenes Release. ChangelogVersionsgeschichte und Breaking Changes.","hilfe--support#Hilfe \u0026amp; Support":"Bei Bugs oder weiteren Fragen → Issue auf Gitea . Siehe auch die FAQ für häufige Fragen.","im-alltag#Im Alltag":"Typischer ArbeitsablaufKunde → Offerte → Projekt → Zeit → Rechnung. Datenhaltung \u0026 BackupWo die Daten liegen, wie du sie sicherst und wiederherstellst. TroubleshootingApp startet nicht, Daten weg, Update hängt."},"title":"Dokumentation"},"/docs/arbeitsablauf/":{"data":{"":"Vom Erstkontakt mit dem Kunden bis zur Schlussrechnung — der typische Weg eines Projekts durch Rapport.","1--kunde-anlegen#1 · Kunde anlegen":"Kunden → Neu — siehe Einrichtung § 3.\nFalls der Kunde später bestellt, lassen sich alle gesammelten Daten (Adresse, Honorartyp) direkt übernehmen.","2--offerte-erstellen#2 · Offerte erstellen":"Offerten → Neu\nFeld Inhalt Kunde aus Kundendatenbank wählen Bezeichnung Projekttitel (z. B. “Einfamilienhaus Müller, Bern”) Honorartyp Stundensatz / SIA 102 / Pauschal Bauschätzwert bei SIA — Bruttowert in CHF Phasen bei SIA — anzuklickende Phasen Positionen bei Stundensatz/Pauschal — Position, Beschreibung, Betrag Mit PDF exportieren — fertige Offerte für den Kunden.","3--offerte--projekt#3 · Offerte → Projekt":"Bei Status “Angenommen”: Knopf “In Projekt konvertieren”.\nDas erzeugt:\nEin neues Projekt mit den Daten der Offerte (Kunde, Bezeichnung, Honorar, Phasen) Eine Verknüpfung zwischen Offerte und Projekt Die Offerte selbst bleibt im Archiv erhalten Siehe auch Projekt-Feature.","4--zeit-erfassen#4 · Zeit erfassen":"Zeit → Mitarbeiter wählen → Woche navigieren\nKlick auf einen Halbstunden-Slot → Eintrag erstellen Drag über mehrere Slots → längerer Eintrag Projekt zuweisen (Pflichtfeld) — aus aktiven Projekten SIA-Phase zuweisen (optional, für detaillierte Auswertung)","5--akonto-rechnung#5 · Akonto-Rechnung":"Während der Projektlaufzeit — typisch nach jeder abgeschlossenen SIA-Phase oder monatlich.\nRechnungen → Neu → Akonto\nFeld Inhalt Projekt aus aktiven Projekten Bezug “Akonto für Phase 31 — Vorprojekt” Betrag Stundensatz × Stunden, oder Phasenanteil × Bausumme Fälligkeit i. d. R. 30 Tage Rapport zieht automatisch die geleisteten Stunden aus der Zeiterfassung — die kannst du als Basis nehmen oder überschreiben.\nPDF inkl. QR-Einzahlungsschein — siehe Rechnungen-Feature.","6--schlussrechnung#6 · Schlussrechnung":"Nach Projektabschluss — Differenz aus Gesamthonorar minus aller Akonto-Beträge.\nRechnungen → Neu → Schlussrechnung\nRapport rechnet die bisherigen Akonto-Rechnungen automatisch ab:\nGesamthonorar (SIA / Pauschal / Stundensatz) − Akonto-Rechnung 1 − Akonto-Rechnung 2 − Akonto-Rechnung 3 = Schlussrechnung","7--projektabschluss#7 · Projektabschluss":"Im Projekt → Status auf “Abgeschlossen”.\nDas Projekt bleibt für historische Auswertungen sichtbar, taucht aber nicht mehr in der Zeiterfassungs-Auswahl auf.","auswertungen#Auswertungen":"Wöchentlich / monatlich / am Jahresende:\nZeit → Auswertungen — Stunden pro Mitarbeiter, pro Projekt, pro Phase Rechnungen → Übersicht — offene Beträge, bezahlt, Mahnungen Buchhaltung → Erfolgsrechnung — Einnahmen vs. Ausgaben Mitarbeiter → Lohnabrechnung — monatlich","offerten-status#Offerten-Status":"Status Bedeutung Entwurf noch nicht versandt Versandt beim Kunden, wartet auf Antwort Angenommen Kunde hat zugesagt — bereit zur Konvertierung Abgelehnt Kunde hat abgelehnt — Archiv","spezialfälle#Spezialfälle":"Ferien — eigener “Projekt”-Typ “Ferien”, in der Auswertung separat Krankheit/Absenz — eigener “Projekt”-Typ, ebenfalls separat Interne Stunden — z. B. Verwaltung, Marketing, IT — eigene interne Projekte","tipps-aus-dem-alltag#Tipps aus dem Alltag":"Zeit jeden Tag erfassen statt rückwirkend — sonst gehen Details verloren Akonto regelmässig statt einmal am Schluss — Liquidität Backups vor Jahresabschluss — siehe Datenhaltung Briefbogen-Logo in hoher Auflösung — sieht im PDF besser aus","übersicht#Übersicht":"Kunde → Offerte → Projekt → Zeit → Akonto → Schluss anlegen erstellen (aus Offerte) erfassen -Rechnung -Rechnung ↓ QR-Schein"},"title":"Arbeitsablauf"},"/docs/changelog/":{"data":{"":"Versionsgeschichte von RAPPORT. Aktuelle Releases: Gitea .","01x--initial#0.1.x — Initial":"Neu\nErste Setup-Routine (Bürodaten, Mitarbeiter, Kunden) Briefe und Lieferscheine Tauri-2-Bundle für macOS","02x--zeiterfassung#0.2.x — Zeiterfassung":"Neu\nWochenraster mit Halbstunden-Slots Drag \u0026 Drop zur Slot-Erfassung Projekt-Zuweisung pro Eintrag Auswertungen pro Mitarbeiter und Projekt","03x--rechnungen--qr#0.3.x — Rechnungen \u0026amp; QR":"Neu\nRechnungsmodul mit QR-Einzahlungsschein (via swissqrbill) Akonto-, Teil- und Schlussrechnungen PDF-Export mit Bürobriefbogen Stundensatz-Rechnungen ziehen direkt aus der Zeiterfassung","04x--projekte--sia-102#0.4.x — Projekte \u0026amp; SIA 102":"Neu\nProjektverwaltung nach SIA 102 Vorgeschlagene Phasen-Anteile am Gesamthonorar Bauschätzwert-basiertes Honorar Verbessert\nZeit-Auswertung pro SIA-Phase Akonto- und Schlussrechnungen mit automatischer Differenzberechnung","05x--mitarbeiter--lohn#0.5.x — Mitarbeiter \u0026amp; Lohn":"Neu\nMitarbeiterverwaltung mit Pensum, Stundensatz, Ferienanspruch Lohnabrechnung mit AHV/IV/EO, ALV, BVG, NBU Jahresabschluss mit Überstundenausgleich Ferien-Prorata bei Eintritt unter Jahr","06x--spesen--buchhaltung#0.6.x — Spesen \u0026amp; Buchhaltung":"Neu\nSpesenerfassung mit Beleg-Upload (Base64 in localStorage) Jahresbudget mit Einnahmen-/Ausgaben-Übersicht Vereinfachte Erfolgsrechnung pro Geschäftsjahr Verbessert\nLohnabrechnung integriert Spesen-Erstattungen CSV-Export aus der Zeiterfassung","070--auto-updater--system-tray#0.7.0 — Auto-Updater \u0026amp; System-Tray":"Neu\nAuto-Updater — Rapport prüft beim Start auf neue Versionen und installiert Updates signiert über Tauri. Einzelne Versionen können übersprungen werden. (Doku) System-Tray — Schnellzugriff über die Menüleiste mit Hide-on-Close. Beim Schliessen läuft Rapport im Hintergrund weiter, Cmd+Q beendet die App vollständig. (Doku) Quick-Open der letzten 5 Projekte direkt aus dem Tray-Menü Verbessert\nSchnellerer App-Start durch lazy-geladene Views Klarere Statusbadges in der Projekt-Übersicht","080081--patch-releases#0.8.0–0.8.1 — Patch-Releases":"Patch-Reihe mit kleineren Verbesserungen und Bugfixes. Details siehe Releases auf Gitea .","082--aktuelle-version-aktuell#0.8.2 — Aktuelle Version \u003cspan class=\"rapport-status new\"\u003eAktuell\u003c/span\u003e":"Veröffentlicht am 2026-05-24.\nNeu / Verbessert\nDiverse Verbesserungen und Bugfixes (Details werden im Release auf Gitea gepflegt) Bekannte Einschränkungen\nBuilds sind Tauri-signiert, aber noch nicht Apple-notarisiert — siehe Installation § Gatekeeper Linux- und Windows-Builds noch nicht verfügbar","roadmap#Roadmap":"Geplant — keine konkreten Termine:\nLinux-Build (Tauri 2 unterstützt es, Bedarf nötig) Windows-Build (analog) Cloud-Modus Stable (Supabase) — derzeit in Web-Modus verfügbar, aber experimentell Französische / Italienische Übersetzung PostgreSQL-Migration aus localStorage (Knopf in der App) Mobile App (iOS Companion zur Zeiterfassung) — offen Wünsche oder Prioritäten → Issue auf Gitea ."},"title":"Changelog"},"/docs/datenhaltung/":{"data":{"":"Wo Rapport seine Daten speichert, wie du sie sicherst und wiederherstellst.\nDiese Seite beschreibt die Desktop-App (Single-User). Wer im Team arbeitet und Rapport gegen einen Rapport Server betreibt, sichert stattdessen die Postgres-Datenbank — siehe Rapport Server § Backup.","a--einfach-manuell#A · Einfach (manuell)":"Den ganzen Ordner kopieren:\ncp -R \"~/Library/Application Support/com.rapport.app\" \\ \"~/Documents/Rapport-Backup-$(date +%Y%m%d)\" → Auf USB-Stick, externen Datenträger oder in die Cloud.","b--time-machine#B · Time Machine":"Wenn Time Machine läuft, ist der Ordner automatisch dabei. Versionierung inbegriffen.\nEinschränkung: Time Machine sichert nur lokal/USB. Für off-site-Backup separat sorgen.","backup-strategien#Backup-Strategien":"","c--cron-job-täglich-automatisch#C · Cron-Job (täglich automatisch)":"# In ~/Library/LaunchAgents/com.rapport.backup.plist hinterlegen # oder als crontab-Eintrag: 0 22 * * * rsync -a \"$HOME/Library/Application Support/com.rapport.app/\" \\ \"$HOME/Backups/rapport/$(date +\\%Y\\%m\\%d)/\"","d--icloud-drive-off-site#D · iCloud Drive (off-site)":"Application-Support liegt nicht automatisch in iCloud. Wer das will:\n# Symlink anlegen mkdir -p \"~/iCloud Drive/Rapport\" ln -s \"~/Library/Application Support/com.rapport.app\" \"~/iCloud Drive/Rapport/data\" Achtung: iCloud-Sync mit aktiver App kann zu Race-Conditions führen. Besser den Sync zeitversetzt (z. B. nachts via Cron).","datenmenge#Datenmenge":"Typische Grössen pro Bürojahr:\nInhalt Grösse Logo (PNG/SVG) 50 KB – 1 MB 1 Jahr Zeiterfassung (1 MA) ~ 80 KB 1 Jahr Zeiterfassung (5 MA) ~ 400 KB 50 Projekte mit je 5 Rechnungen ~ 800 KB Total typisches Solo-Büro / Jahr ~ 1–2 MB localStorage hat Limits (i. d. R. ~10 MB pro Origin). Für Solo-Büros reicht das problemlos für viele Jahre. Wer das Limit erreicht oder im Team arbeitet → Rapport Server.","export-funktionen-in-der-app#Export-Funktionen (in der App)":"Aus Rapport selbst:\nWas Wo Format Zeit-Auswertung Zeit → Export CSV Rechnung Rechnung → PDF PDF (inkl. QR) Offerte Offerte → PDF PDF Lohnabrechnung Mitarbeiter → PDF PDF Jahres-Buchhaltung Buchhaltung → Export CSV Die Exports sind für externe Verwendung (Buchhalter, Treuhänder, Archiv) gedacht — kein Full-Backup.","macos#macOS":"~/Library/Application Support/com.rapport.app/ Dort liegt eine einzelne localStorage-Datenbank des WebView, in der alle Rapport-Daten als JSON unter dem Key studio_data_v1 gespeichert sind:\nBürodaten, Logo, IBAN Mitarbeiter, Kunden, Projekte, Offerten Zeit-Einträge, Rechnungen Spesen, Lohnabrechnungen, Protokolle App-Einstellungen Konsequenz: Wer den Application-Support-Ordner kopiert, hat ein vollständiges Backup. Wer ihn löscht, verliert alle Daten.","schema-migrationen#Schema-Migrationen":"Bei Updates kann sich das Datenformat ändern. Rapport hat einen Migrations-Mechanismus: beim Start prüft die App, ob das gespeicherte Format dem aktuellen entspricht, und migriert es automatisch.\nCode: src/storage/migrations.js .\nEmpfehlung: Vor jedem grösseren Update ein Backup machen — Migrationen sind getestet, aber 100%-Sicherheit gibt es nicht.","selektiv-nur-einzelne-daten#Selektiv (nur einzelne Daten)":"Da alle Daten in einem JSON unter studio_data_v1 liegen, ist selektive Wiederherstellung manuell:\nBackup-localStorage-Datei öffnen (WebKit-Format → mit Tool wie [WebKit Storage Inspector] lesen, oder via Rapport DevTools) Gewünschte Felder in die aktuelle Instanz übertragen In der Praxis: meistens lohnt sich die vollständige Wiederherstellung mehr.","speicherort-desktop-app#Speicherort (Desktop-App)":"Die Desktop-App speichert alles lokal — keine Cloud, kein Server.","vollständig-rapport-komplett-tot#Vollständig (Rapport komplett tot)":"Rapport beenden (Cmd+Q, nicht nur Fenster zu) Aktuellen Ordner umbenennen (falls noch da): mv \"~/Library/Application Support/com.rapport.app\" \\ \"~/Library/Application Support/com.rapport.app.bak\" Backup-Ordner zurück kopieren: cp -R \"~/Documents/Rapport-Backup-20260523\" \\ \"~/Library/Application Support/com.rapport.app\" Rapport starten","warum-localstorage#Warum localStorage?":"In der Desktop-App ist Rapport eine Single-User-Anwendung. localStorage ist dafür:\nSchnell — keine Datenbank-Roundtrips Einfach — keine Migration nötig, JSON-Schema im Code Portabel — eine Datei → ein Backup Für Multi-User-Betrieb existiert Rapport Server — Postgres + Auth + Realtime in einem Docker-Compose. Wechsel zwischen Desktop- und Server-Modus erfolgt im Login-Bildschirm der App.","was-wird-nicht-gespeichert#Was wird \u003cstrong\u003enicht\u003c/strong\u003e gespeichert?":"WebView-Cache — ~/Library/Caches/com.rapport.app/ und ~/Library/WebKit/com.rapport.app/ sind sicher zu löschen (UI-Caches, regenerieren sich) App-Updates — werden bei Bedarf erneut runtergeladen Logs — ~/Library/Logs/com.rapport.app/ (geplant, derzeit nicht geschrieben)","wiederherstellung#Wiederherstellung":""},"title":"Datenhaltung"},"/docs/einrichtung/":{"data":{"":"Nach der Installation: Bürodaten, Mitarbeiter, Kunden und Projekte initial anlegen.","1--bürodaten#1 · Bürodaten":"Einstellungen → Bürodaten\nFeld Beschreibung Verwendung Name Bürobezeichnung Briefbogen, Login-Screen Adresse Strasse, PLZ, Ort Briefbogen, QR-Rechnung (Empfänger) Telefon, E-Mail Kontaktdaten Briefbogen, Rechnung-Footer IBAN CH-IBAN (Format CH XX XXXX …) QR-Einzahlungsschein — Pflicht Logo PNG/SVG-Upload Briefbogen, Rechnung, Brief MwSt.-Nr. optional Rechnung-Footer Tipp: Das Logo wird hochauflösend gespeichert (Base64 im localStorage). Bei sehr grossen Dateien (\u003e1 MB) vorher in Vorschau verkleinern.","2--mitarbeiter#2 · Mitarbeiter":"Einstellungen → Mitarbeiter → Neu\nFeld Beschreibung Name, Vorname wird in Zeiterfassung \u0026 Lohn verwendet Initialen Kürzel für Auswertungen (z. B. “KGE”) Eintrittsdatum für Prorata der Ferien Pensum (%) 100 = Vollzeit Stundensatz (CHF) für Stundensatz-Rechnungen Ferienanspruch (Tage/Jahr) i. d. R. 25–30 Lohn (brutto, monatlich) optional, für Lohnabrechnung Mindestens ein Mitarbeiter (z. B. der Inhaber selbst) muss angelegt sein, sonst lässt sich keine Zeit erfassen.","3--kunden#3 · Kunden":"Kunden → Neu\nFeld Beschreibung Typ Privatperson / Firma Anrede, Name für Brief / Rechnung Adresse Strasse, PLZ, Ort, Land Ansprechperson bei Firmen Telefon, E-Mail Kontakt Honorartyp Default Stundensatz / SIA / Pauschal Stundensatz falls vom Bürostandard abweichend MwSt.-pflichtig ja/nein","4--projekte#4 · Projekte":"Projekte → Neu\nFeld Beschreibung Projekt-Nr. freie Form, oder generiert (2026-001) Bezeichnung Kurztitel Standort Adresse Kunde aus Kundendatenbank Bauschätzwert für SIA-Phasen-Honorar SIA-Phasen Vorprojekt / Bauprojekt / … — alle anwählbar Honorartyp Stundensatz / SIA 102 / Pauschal Status aktiv / pausiert / abgeschlossen","checkliste#Checkliste":"Nach diesen vier Schritten ist Rapport einsatzbereit:\nBürodaten inkl. IBAN erfasst Mindestens ein Mitarbeiter angelegt Erster Kunde angelegt Erstes Projekt angelegt Eine Test-Zeitbuchung erfasst — wird das Projekt korrekt zugewiesen? Eine Test-Rechnung erstellt — kommt der QR-Schein sauber raus? Wenn alles funktioniert: Typischer Arbeitsablauf.","reihenfolge#Reihenfolge":"Die Reihenfolge ist wichtig — jede Stufe baut auf der vorherigen auf:\n1. Bürodaten → 2. Mitarbeiter → 3. Kunden → 4. Projekte ▼ ▼ ▼ ▼ Briefbogen, Zeiterfassung, Adressen, Zeiterfassung, QR-Schein, Lohn Rechnungen Rechnungen Login","sia-102-phasen#SIA-102-Phasen":"Wenn als Honorartyp SIA 102 gewählt ist, werden die Phasen-Anteile am Gesamthonorar vorgeschlagen — siehe Projekt-Feature.","sozialabzüge-optional#Sozialabzüge (optional)":"In Einstellungen → Lohn:\nAbzug Standardwert (CH) AHV / IV / EO 5,3 % ALV 1,1 % BVG (Pensionskasse) variabel — je Mitarbeiter NBU je nach Versicherung Die Standardsätze sind hinterlegt, können aber überschrieben werden."},"title":"Einrichtung"},"/docs/entwicklung/":{"data":{"":"Aus dem Quellcode kompilieren, beitragen, eigenes Release erzeugen.","architektur-in-einem-absatz#Architektur in einem Absatz":"RAPPORT ist eine monolithische SPA: ein React-Root in App.jsx hält den gesamten App-State in einem useState({...}), persistiert ihn synchron in localStorage unter studio_data_v1, und übergibt ihn als Props an lazy-geladene Views. Kein Routing-Framework, kein State-Library, kein TypeScript, kein CSS-Framework. Der Rust-Teil ist 109 Zeilen und macht nur drei Dinge: System-Tray, Window-Hide-on-Close, Plugin-Registrierung (Updater, Process, Log). Keine #[tauri::command] — Frontend ↔ Backend kommuniziert nur über das Event rapport:navigate (Tray → Frontend).\nDetaillierte Karte: ARCHITECTURE.md .","beitragen#Beitragen":"Issues \u0026 Pull Requests sind willkommen. Wertvoll sind:\nBug-Reports mit Reproduktionsschritten Workflow-Verbesserungen aus dem realen Büroalltag Vorlagen (Briefe, Protokolle, Lieferscheine) für andere Büros Übersetzungen / Internationalisierung (FR, IT) Linux-/Windows-Builds und plattformspezifische Fixes Vor grösseren Änderungen → Issue zum Diskutieren.","build#Build":"","desktop-tauri-dmg#Desktop (Tauri DMG)":"npm run build # erst Vite-Build (dist/) npx tauri build # dann Tauri-Bundle (DMG) Output: src-tauri/target/release/bundle/dmg/Rapport__aarch64.dmg","entwicklung#Entwicklung":"","konventionen#Konventionen":"JavaScript statt TypeScript — bewusste Entscheidung für Solo-Dev-Velocity Inline-Styles statt CSS-Framework kein Routing-Framework — view-State in App.jsx triggert Komponente JSON-Schema implizit — definiert durch defaultData in constants.js Migrationen als reine Funktionen in storage/migrations.js","lizenz#Lizenz":"GNU AGPL-3.0-or-later — eigene Builds erlaubt, Modifikationen müssen unter derselben Lizenz veröffentlicht werden, wenn die Software als Service angeboten wird.","native-window-tauri-fenster-mit-desktop-integration#Native Window (Tauri-Fenster mit Desktop-Integration)":"npx tauri dev Echtes Tauri-Fenster System-Tray, Updater, native APIs verfügbar Erster Start dauert lange (Rust-Compile)","release-workflow#Release-Workflow":"# 1 · Version bumpen in package.json + Cargo.toml + tauri.conf.json ./scripts/release.sh 0.7.1 # 2 · Build mit Signatur TAURI_SIGNING_PRIVATE_KEY=$(cat ~/.tauri/rapport-key) \\ TAURI_SIGNING_PRIVATE_KEY_PASSWORD=… \\ npx tauri build # 3 · latest.json aktualisieren mit neuer Signatur # 4 · DMG + latest.json auf Gitea Releases hochladen","setup#Setup":"git clone https://git.kgva.ch/karim/RAPPORT.git cd RAPPORT/APP npm install","verzeichnis-karte#Verzeichnis-Karte":"APP/ ├── src/ React 19 (kein TS, nur .jsx) │ ├── App.jsx Root: State, Navigation, Sidebar, Modals │ ├── constants.js STORAGE_KEY, NAV_ITEMS, defaultData, SIA-Phasen │ ├── utils.js Business-Logik: Kalkulation, QR-Bill, CSV, Lohn │ ├── storage/adapter.js LocalStorageAdapter (Phase 1), SupabaseAdapter (Phase 2) │ ├── storage/migrations.js Schema-Migrationen │ ├── views/ 20 Top-Level-Screens, lazy-geladen │ ├── components/UI.jsx StatusBadge, Modal, FormField, … │ ├── components/Update* Auto-Update-UI │ ├── print/ PrintComponents.jsx — alle Druckansichten │ └── utils/updater.js @tauri-apps/plugin-updater Wrapper │ ├── supabase/migrations/ Postgres-Schema für Cloud-Variante │ ├── src-tauri/ Rust-Backend (Tauri 2.10.3) │ ├── src/lib.rs ~103 Z. — Tray, Window-Events, Plugins │ ├── tauri.conf.json Updater-URL, Public-Key, CSP, Bundle-Targets │ └── capabilities/ Tauri Permissions │ ├── scripts/release.sh Build + Sign + latest.json erzeugen ├── latest.json Updater-Manifest └── deploy/ Docker-Compose für Web-Modus","voraussetzungen#Voraussetzungen":"Tool Version Node.js ≥ 20 (für Vite 8) npm ≥ 10 Rust toolchain ≥ 1.77.2 (via rustup) Plattform-Tools siehe Tauri Prerequisites Plattform-spezifisch:\nmacOS: Xcode Command Line Tools (xcode-select --install) Windows: Microsoft C++ Build Tools + WebView2 Linux: webkit2gtk-4.1, librsvg2-dev, libayatana-appindicator3-dev, build-essential","web-modus-hmr-schnellster-loop#Web-Modus (HMR, schnellster Loop)":"npm run dev # http://localhost:3000 Hot-Module-Replacement Schnellster Iteration-Loop für UI-Arbeit Datenpersistierung: Browser-localStorage","web-statisches-bundle#Web (statisches Bundle)":"npm run build # Output: dist/ (~500 KB) Für Hosting auf einem Static-Server (z. B. Nginx, Caddy, GitHub Pages). Siehe Web-Modus."},"title":"Entwicklung"},"/docs/erste-schritte/":{"data":{"":"Von der Installation bis zur ersten Rechnung — in sechs Schritten.","01--installation#01 · Installation":"DMG von Gitea Releases herunterladen. Rapport in den Programme-Ordner ziehen. Beim ersten Start: Systemeinstellungen → Datenschutz \u0026 Sicherheit öffnen und Rapport zulassen.\nDie Pre-Release-Builds sind signiert über Tauri, aber (noch) nicht über die Apple-Notarisierung gegangen — daher der manuelle Freigabe-Schritt.","02--einrichtung#02 · Einrichtung":"In den Einstellungen hinterlegen:\nBürodaten — Name, Adresse, IBAN, Logo Mitarbeiter — Namen, Pensum, Stundensatz, Ferienanspruch Kunden — Adresse, Ansprechperson, Honorartyp Projekte — SIA-102-Phasen, Budget, Beteiligte Danach ist die Zeiterfassung bereit.","03--zeiterfassung#03 · Zeiterfassung":"Im Modul Zeit:\nMitarbeiter wählen Woche navigieren Stunden per Klick oder Drag erfassen Jedem Eintrag ein Projekt zuweisen Auswertungen pro Mitarbeiter und pro Projekt sind unter Zeit → Auswertungen abrufbar. Halbe Tage und Mehrfacheinträge pro Slot werden unterstützt.","04--rechnungen#04 · Rechnungen":"Aus einer Offerte oder direkt erstellen:\nSIA-Phasen, Stundensatz oder Pauschal wählen Akonto-, Teil- oder Schlussrechnung Mit PDF exportieren wird die fertige Rechnung inkl. QR-Einzahlungsschein generiert Offerten lassen sich nahtlos in Projekte und Rechnungen konvertieren.","05--backup#05 · Backup":"In der Desktop-App liegen alle Daten als JSON im Applikationsordner:\n~/Library/Application Support/com.rapport.app/ Für ein Backup reicht es, diesen Ordner zu kopieren — z. B. auf einen externen Datenträger oder in die Cloud. Empfohlen: regelmässig (wöchentlich oder via Time Machine). Im Server-Modus läuft das Backup über Postgres-Dumps — siehe Rapport Server § Backup.","06--probleme-melden#06 · Probleme melden":"Ein Issue auf Gitea erstellen — mit kurzer Beschreibung, was passiert ist. Screenshots helfen. Bitte die Rapport-Version (links unten in der App) angeben.\nTipp: Wenn die App nicht mehr startet, hilft oft, den Cache-Ordner zu sichern und neu zu starten. Die JSON-Daten selbst bleiben unverändert."},"title":"Erste Schritte"},"/docs/installation/":{"data":{"":"Schritt-für-Schritt-Anleitung für die Installation der Desktop-App.","1--download#1 · Download":"Aktueller Build: Downloads-Seite oder direkt Releases auf Gitea .\nDatei Plattform RAPPORT__aarch64.dmg macOS Apple Silicon RAPPORT__x86_64.dmg macOS Intel (auf Anfrage)","2--dmg-öffnen--installieren#2 · DMG öffnen \u0026amp; installieren":"DMG doppelklicken Rapport.app in den Applications-Ordner ziehen DMG auswerfen","3--erster-start-macos-gatekeeper#3 · Erster Start (macOS Gatekeeper)":"Beim ersten Start verweigert macOS den Start, weil die Pre-Release-Builds Tauri-signiert, aber (noch) nicht Apple-notarisiert sind.","4--erstes-setup#4 · Erstes Setup":"Beim ersten Start zeigt Rapport den Setup-Bildschirm. Hier werden die Stammdaten erfasst — siehe Einrichtung.","5--update-strategie#5 · Update-Strategie":"Ab Version 0.7.0 prüft Rapport beim Start automatisch auf neue Versionen (siehe Auto-Updater). Updates können in den Einstellungen deaktiviert werden.\nManuelle Updates: einfach das neuere DMG installieren — die Daten bleiben erhalten, da sie unabhängig von der App liegen (siehe Datenhaltung).","alternative-terminal#Alternative (Terminal)":"Falls der GUI-Weg nicht funktioniert:\nxattr -d com.apple.quarantine /Applications/Rapport.app Das entfernt das Quarantäne-Flag und macOS akzeptiert den Start.","bekannte-probleme#Bekannte Probleme":"Problem Lösung App lässt sich nicht öffnen trotz Freigabe Terminal-Variante mit xattr “Rapport is damaged” DMG erneut von Gitea ziehen (Browser-Cache hat evtl. Müll) Schwarzer Bildschirm beim Start ~/Library/WebKit/com.rapport.app löschen, neu starten Mehr unter Troubleshooting.","deinstallation#Deinstallation":"# App entfernen rm -rf /Applications/Rapport.app # Daten entfernen (optional!) rm -rf \"~/Library/Application Support/com.rapport.app\" # Caches rm -rf \"~/Library/Caches/com.rapport.app\" rm -rf \"~/Library/WebKit/com.rapport.app\" Achtung: Schritt 2 löscht alle Rapport-Daten unwiederbringlich. Vorher Backup machen — siehe Datenhaltung.","lösung#Lösung":"Systemeinstellungen → Datenschutz \u0026 Sicherheit öffnen Bis ganz nach unten scrollen — es erscheint: “Rapport” wurde blockiert, da es nicht von einem identifizierten Entwickler stammt.\nAuf “Trotzdem öffnen” klicken Bestätigen Ab dem zweiten Start läuft Rapport ohne Rückfragen.","voraussetzungen#Voraussetzungen":"Plattform Status Versionen macOS Apple Silicon (M1 – M4) ✅ Unterstützt macOS 12+ macOS Intel ⚠ Build auf Anfrage macOS 12+ Linux 🕐 Geplant — Windows 🕐 Geplant — Eine Portierung auf Linux und Windows ist mit Tauri 2 möglich. Issue erstellen , wenn du eine Plattform brauchst."},"title":"Installation"},"/docs/troubleshooting/":{"data":{"":"Typische Probleme und Lösungen. Wenn dein Problem nicht dabei ist → Issue auf Gitea .","app-startet-nicht#App startet nicht":"","app-startet-zeigt-aber-schwarzen-bildschirm#App startet, zeigt aber schwarzen Bildschirm":"Ursache: WebView-Cache korrupt.\nLösung:\nrm -rf \"~/Library/Caches/com.rapport.app\" rm -rf \"~/Library/WebKit/com.rapport.app\" App neu starten. Daten gehen dabei nicht verloren (liegen in Application Support, nicht im Cache).","app-stürzt-sofort-beim-start-ab#App stürzt sofort beim Start ab":"Ursache: wahrscheinlich beschädigte JSON-Daten in studio_data_v1.\nDiagnose:\n# Daten ansehen (DevTools-Output) open \"~/Library/Application Support/com.rapport.app\" Lösung:\nBackup wiederherstellen (siehe Datenhaltung) Oder als letzter Ausweg: Daten zurücksetzen mv \"~/Library/Application Support/com.rapport.app\" \\ \"~/Library/Application Support/com.rapport.app.bad\" App neu starten → erstellt frische Daten. Anschliessend Setup-Screen.","auto-update-findet-nichts#Auto-Update findet nichts":"Diagnose:\ncurl -s https://git.kgva.ch/karim/RAPPORT/raw/branch/main/APP/latest.json → sollte JSON liefern. Wenn nicht: Server-/Netzwerkproblem.","daten-weg#Daten weg":"","debug-informationen-sammeln#Debug-Informationen sammeln":"Bei einem Issue helfen folgende Infos:\n# Rapport-Version defaults read /Applications/Rapport.app/Contents/Info.plist CFBundleShortVersionString # macOS-Version sw_vers # Architektur uname -m # Datenverzeichnis-Grösse du -sh \"~/Library/Application Support/com.rapport.app\" # Cache-Verzeichnis-Grösse du -sh \"~/Library/Caches/com.rapport.app\" → Bei Issue mit anhängen.","diese-version-überspringen-rückgängig-machen#\u0026ldquo;Diese Version überspringen\u0026rdquo; rückgängig machen":"In Einstellungen → Updates → Übersprungene Versionen zurücksetzen. Beim nächsten Start wird die Version wieder angeboten.","localstorage-voll#localStorage voll":"Symptom: Rapport schreibt Fehler-Toast “Speicher voll” beim Sichern.\nUrsache: macOS WebView limitiert localStorage auf ~10 MB pro Origin.\nLösung:\nSehr grosse Logos durch kleinere ersetzen (Bürodaten → Logo) Belege (Spesen) selektiv löschen oder als externe Datei archivieren Auf Web-Modus wechseln (Postgres ohne praktisches Limit)","login-screen-zeigt-keine-server-url#Login-Screen zeigt keine Server-URL":"Ursache: .env.production enthielt nicht den richtigen VITE_SUPABASE_URL zur Build-Zeit.\nLösung: .env.production prüfen, dann npm run build neu, Container restart.","nach-einem-app-update-fehlen-einträge#Nach einem App-Update fehlen Einträge":"Ursache: mögliche fehlgeschlagene Migration.\nSofortmassnahme:\nRapport beenden (Cmd+Q, nicht nur Fenster zu) Aktuelles Datenverzeichnis sichern: cp -R \"~/Library/Application Support/com.rapport.app\" \\ \"~/Documents/Rapport-Notfall-$(date +%Y%m%d-%H%M)\" Issue erstellen mit: Version vor dem Update (falls bekannt) Version nach dem Update Was fehlt Optional: gesicherter Datenordner (via Pastebin oder verschlüsselt zugesandt)","pdf--qr-schein#PDF / QR-Schein":"","pdf-export-ist-leer--weisses-blatt#PDF-Export ist leer / weisses Blatt":"Ursache: Print-View hat keine Daten (möglicherweise Race-Condition beim Laden).\nLösung: Rechnung schliessen, erneut öffnen, dann PDF.","pdf-schrift-sieht-falsch-aus#PDF-Schrift sieht falsch aus":"Ursache: Web-Schrift nicht geladen, Fallback greift.\nLösung: Vor dem Drucken warten, bis das Vorschau-Bild komplett geladen ist (3–5 Sek).","qr-schein-hat-falsche-daten#QR-Schein hat falsche Daten":"Diagnose-Checkliste:\nIBAN korrekt? (CH, 21 Zeichen, keine Leerzeichen) Empfänger-Adresse vollständig? (PLZ und Ort beide gefüllt) Schuldner-Adresse vollständig? Betrag \u003e 0? Referenz nicht zu lang? (max 27 Zeichen) QR-Bibliothek: swissqrbill — bei merkwürdigen Fehlern dort nachschauen.","rapport-ist-beschädigt-beim-ersten-start#\u0026ldquo;Rapport ist beschädigt\u0026rdquo; beim ersten Start":"Ursache: macOS Gatekeeper blockt unsignierte/nicht-notarisierte Apps.\nLösung: siehe Installation § 3. Kurz:\nxattr -d com.apple.quarantine /Applications/Rapport.app","realtime-updates-kommen-nicht-an#Realtime-Updates kommen nicht an":"Ursache: Websocket-Support fehlt im Reverse Proxy.\nLösung: In Nginx Proxy Manager für api.* Websocket Support aktivieren.\nSiehe Web-Modus § Troubleshooting.","system-tray#System-Tray":"","tray-icon-erscheint-nicht#Tray-Icon erscheint nicht":"Plattform-Hinweis: Tray-Icons unter macOS sind bei extrem voller Menüleiste oder unter “Bartender”/“Hidden Bar” eventuell unsichtbar.\nDiagnose:\nps aux | grep -i rapport → wenn Prozess läuft, aber kein Icon: in den Tray-Manager-Apps prüfen.\nKonfiguration: Einstellungen → System-Tray → Tray-Icon ausblenden (aus → Icon erzwingen).","tray-menü-reagiert-nicht--hängt#Tray-Menü reagiert nicht / hängt":"Lösung: App via Activity Monitor hart beenden und neu starten. Daten gehen nicht verloren (alle Schreibungen sind synchron in localStorage).","update-lädt-lässt-sich-aber-nicht-installieren#Update lädt, lässt sich aber nicht installieren":"Ursache: Signaturprüfung scheitert (Public-Key in App ≠ Signatur in latest.json).\nLösung: Manuelles Update — DMG direkt von Releases laden und installieren. Daten bleiben erhalten.","updates#Updates":"","web-modus#Web-Modus":"","wenn-nichts-hilft#Wenn nichts hilft":"Neues Issue auf Gitea mit:\nWas du gemacht hast Was passiert ist Was du erwartet hättest Screenshots (auch von DevTools-Konsole falls möglich) Rapport-Version und macOS-Version"},"title":"Troubleshooting"},"/docs/web-modus/":{"data":{"":"Hinweis: Der frühere Supabase-basierte Web-Modus wurde durch Rapport Server abgelöst — den vollständigen Selfhost-Stack mit eigenem Postgres, Auth, Realtime und Storage. Keine externe Cloud-Abhängigkeit mehr.\nDiese Seite bleibt als Referenz erhalten, der empfohlene Weg für Multi-User-Setups ist Rapport Server.","architektur-kurzfassung#Architektur (Kurzfassung)":"┌────────────┐ HTTPS ┌──────────────┐ SQL ┌────────────┐ │ Browser │ ──────────────│ nginx │ ─────────────│ Postgres │ │ / Desktop │ │ (Frontend) │ │ + GoTrue │ └────────────┘ └──────────────┘ │ + REST │ │ + Realtime │ │ + Storage │ └────────────┘ Frontend: dieselbe React-App, aber Vite-Build statt Tauri (npm run build) Backend: Postgres-Stack (Rapport Server) Auth: E-Mail / Passwort über GoTrue Storage: Belege, Logos in Object-Storage","migration-desktop--cloud#Migration Desktop → Cloud":"Wer mit der Desktop-App startet und später auf den Web-Modus wechseln möchte:\nAktuell: manueller Export aus Rapport (CSV/PDF) und manuelles Wiederanlegen im neuen Setup Geplant: “localStorage → Postgres”-Import-Knopf direkt in der App Status: Issue auf Gitea .","setup#Setup":"Alle Setup-Schritte (Repo klonen, .env erstellen, Migrations syncen, Docker-Compose starten, Reverse-Proxy konfigurieren) sind in Rapport Server dokumentiert.","troubleshooting#Troubleshooting":"Siehe Rapport Server § Troubleshooting oder allgemeine Troubleshooting-Seite.","wann-brauchst-du-das#Wann brauchst du das?":"Anwendungsfall Empfehlung Solo-Büro, ein Mac Desktop-App — siehe Installation 2–5 Personen, gleicher Standort Rapport Server auf einem Mac Mini im LAN Verteiltes Team / Home-Office Rapport Server mit SSL + Reverse Proxy Hosted Backend (eigener VPS) Rapport Server auf Linux-VPS"},"title":"Web-Modus"},"/downloads/":{"data":{"":"Aktuelle Builds von Rapport. Quellcode und ältere Versionen auf Gitea .\nRapport besteht aus zwei Komponenten:\nKomponente Für wen Aktuelle Version Desktop-App Solo-Büro, lokale Datenhaltung 0.8.2 Rapport Server Team / Multi-User / Selfhost 0.1.0","auto-update#Auto-Update":"Seit 0.7.0 prüft die Desktop-App beim Start automatisch auf neue Versionen — siehe Auto-Updater. Für Rapport Server: git pull \u0026\u0026 docker compose pull \u0026\u0026 docker compose up -d.","desktop-app--pre-release-082#Desktop-App — Pre-Release 0.8.2":"Aktuelle Version\nNeuerungen — siehe Changelog für Details.","docker-linux--vps--headless#Docker (Linux / VPS / Headless)":"Für Linux-Server, NAS oder VPS — der reine Docker-Compose-Stack ohne GUI.\ngit clone https://git.kgva.ch/karim/rapport-server.git cd rapport-server git checkout 0.1.0 cp .env.example .env # .env editieren (POSTGRES_PASSWORD, JWT_SECRET, SITE_URL) docker compose up -d Vollständige Anleitung mit .env-Variablen, Reverse-Proxy und Backup → Server-Seite.\nContainer-Images werden von Docker Hub / Gitea-Registry gezogen — docker compose pull aktualisiert auf die neuesten Tags.","linux--windows#Linux \u0026amp; Windows":"Geplant. Rapport basiert auf Tauri 2 — eine Portierung ist möglich, sobald der Bedarf besteht. Issue erstellen , wenn du eine Plattform brauchst.","macos#macOS":"Architektur Download Apple Silicon (M1–M4) RAPPORT_0.8.2_aarch64.dmg Intel (x86_64) auf Anfrage Erstinstallation: Systemeinstellungen → Datenschutz \u0026 Sicherheit öffnen und Rapport zulassen. Die Builds sind über Tauri signiert, aber (noch) nicht Apple-notarisiert.","quellcode#Quellcode":"Desktop-App — Tauri / React:\ngit clone https://git.kgva.ch/karim/RAPPORT.git cd RAPPORT/APP npm install npm run tauri dev Voraussetzungen: Node 20+, Rust (stable), Xcode-CLI (macOS).\nRapport Server:\ngit clone https://git.kgva.ch/karim/rapport-server.git Beide Repos auf Gitea — Issues und PRs willkommen.","rapport-server--010#Rapport Server — 0.1.0":"Erstes Release\nSelfhost-Backend für Multi-User-Setups — Postgres, Auth, Realtime-Sync, Storage. Details und Setup-Anleitung auf der Server-Seite.","server-app-macos#Server-App (macOS)":"GUI zum Starten, Stoppen und Verwalten der Server-Instanz auf einem Mac (Mac Mini, Studio-Rechner). Bündelt den Docker-Compose-Stack.\nArchitektur Download Apple Silicon (M1–M4) RAPPORT_SERVER_0.1.0_aarch64.dmg Intel (x86_64) auf Anfrage Voraussetzung: Colima oder Docker Desktop muss installiert sein. Die App verwaltet den Container-Stack darüber."},"title":"Downloads"},"/faq/":{"data":{"":"Häufige Fragen zu RAPPORT. Bei Bugs oder weiteren Fragen → Issue auf Gitea .","für-wen-ist-rapport-gedacht#Für wen ist Rapport gedacht?":"Für kleine Architekturbüros in der Schweiz. Die Strukturen folgen der SIA 102 (Phasen, Honorar). Rapport wurde für den internen Gebrauch entwickelt und wird mit diesem Projekt öffentlich geteilt.","ist-die-software-stabil-genug-für-den-betrieb#Ist die Software stabil genug für den Betrieb?":"Noch nicht. Aktuell befindet sich Rapport in aktiver Entwicklung (Pre-Release 0.8.2). Funktionen können sich ändern, Bugs sind möglich. Regelmässige Backups sind empfohlen. Testen und Feedback geben ist erwünscht.","ist-rapport-kostenlos#Ist Rapport kostenlos?":"Ja, vollständig. Quellcode unter GNU AGPL-3.0-or-later. Keine versteckten Kosten, keine Telemetrie. Die Daten bleiben lokal auf deinem Computer bzw. in deiner Instanz. Du hast die komplette Kontrolle über deine Daten.","kann-ich-zum-projekt-beitragen#Kann ich zum Projekt beitragen?":"Ja. Issues und Pull Requests sind willkommen auf Gitea . Rapport ist kein Framework — konkrete Verbesserungen für den Büroalltag sind am wertvollsten:\nBug-Reports mit Reproduktionsschritten Workflow-Verbesserungen aus dem realen Büroalltag Vorlagen (Briefe, Protokolle, Lieferscheine) für andere Büros Übersetzungen / Internationalisierung","warum-open-source#Warum Open Source?":"Bürowissen sollte nicht in proprietären Tools eingesperrt sein. Studio-Management-Workflows sind in der Branche gut etabliert — ein Tool, das die Schweizer Konventionen (SIA 102, QR-Rechnung) sauber umsetzt, gehört allen.\nAGPL-3.0 stellt sicher, dass Verbesserungen wieder ins Projekt fliessen.","was-ist-mit-dem-qr-einzahlungsschein#Was ist mit dem QR-Einzahlungsschein?":"Rapport erzeugt Schweizer QR-Rechnungen nach Norm — direkt eingebettet in das PDF der Rechnung. IBAN, Bürodaten und Empfänger werden aus den Einstellungen bzw. den Kundendaten gezogen. Akonto-, Teil- und Schlussrechnungen werden unterstützt.","welche-systeme-werden-unterstützt#Welche Systeme werden unterstützt?":"Aktuell nur macOS (Intel \u0026 Apple Silicon). Rapport basiert auf Tauri — eine Portierung auf Linux und Windows ist möglich, sobald der Bedarf seitens Community besteht.","wie-erhalte-ich-hilfe-bei-einem-problem#Wie erhalte ich Hilfe bei einem Problem?":"Ein Issue auf Gitea ist der beste Weg. Bitte beschreibe, was du gemacht hast und was passiert ist. Screenshots helfen. Die Rapport-Version (links unten in der App) bitte angeben.\nKanal Verwendung Gitea Issues Bugs, Feature-Wünsche, allgemeine Fragen gabrielevarano.ch Entwickler-Kontakt","wie-funktioniert-die-zeiterfassung#Wie funktioniert die Zeiterfassung?":"Tages- und Wochenraster mit Drag \u0026 Drop. Jeder Eintrag wird einem Projekt zugewiesen. Auswertungen pro Mitarbeiter und Projekt sind unter Zeit abrufbar. Ferienverwaltung mit Prorata und Jahresabschluss mit Überstundenausgleich.","wo-werden-die-daten-gespeichert#Wo werden die Daten gespeichert?":"Rapport unterstützt zwei Modi, beide selbst-gehostet:\nDesktop-App (Single-User) — alle Daten liegen lokal auf deinem Mac (localStorage im Applikationsordner). Kein Server nötig, kein Cloud-Account, keine Telemetrie. Server-Modus (Multi-User) — Daten in einer eigenen PostgreSQL-Datenbank über Rapport Server. Mehrere Personen, Realtime-Sync, eigene Domain. Wechsel direkt im Login-Bildschirm der App. In beiden Fällen bleibt die Kontrolle über die Daten bei dir."},"title":"FAQ"},"/features/":{"data":{"":"Die Bausteine von RAPPORT — Studio-Management für Schweizer Architekturbüros.","module#Module":"ZeiterfassungTages- \u0026 Wochenraster mit Drag \u0026 Drop. Rechnungen \u0026 OffertenQR-Einzahlungsscheine, SIA-Phasen, Akonto. Projekt- \u0026 KundenverwaltungSIA 102, Budget, Phasen, Beteiligte. MitarbeiterFerien, Absenzen, Lohnabrechnung. Spesen \u0026 BürobudgetBelegupload, Jahresbudget, Internes. Protokolle \u0026 LieferscheineSitzungsprotokolle, Briefe, Lieferscheine. Auto-UpdaterSignierte Updates via Tauri. System-TrayHide-on-Close, Quick-Open."},"title":"Features"},"/features/auto-updater/":{"data":{"":"Neu in 0.7.0\nRapport prüft beim Start automatisch auf neue Versionen und installiert Updates signiert über Tauri. Einzelne Versionen können übersprungen werden.","funktionsweise#Funktionsweise":"Beim App-Start:\nAbfrage gegen https://git.kgva.ch/karim/RAPPORT/releases/latest.json Versionsvergleich mit lokaler version im Tauri-Bundle Bei neuer Version → Update-Dialog Bei Bestätigung → Download + Signaturprüfung + Installation + Neustart","latest-endpoint#Latest-Endpoint":"{ \"version\": \"0.8.2\", \"notes\": \"Rapport 0.8.2\", \"pub_date\": \"2026-05-24T00:00:00Z\", \"platforms\": { \"darwin-aarch64\": { \"signature\": \"…\", \"url\": \"https://git.kgva.ch/karim/RAPPORT/releases/download/0.8.2/RAPPORT%20PRE-RELEASE.app.tar.gz\" } } }","optionen#Optionen":"Update installieren — Download \u0026 Neustart Diese Version überspringen — überspringt nur diese eine Version Später erinnern — beim nächsten Start erneut fragen Updates können in den Einstellungen komplett deaktiviert werden.","sicherheit#Sicherheit":"Updates werden mit dem Tauri-Updater-Schlüssel signiert Manipulierte Downloads werden abgelehnt Quellcode und Build sind reproduzierbar (Gitea CI, geplant)"},"title":"Auto-Updater"},"/features/mitarbeiter/":{"data":{"":"In Arbeit\nFerienverwaltung, interne Stunden / Absenzen und Lohnabrechnung. Jahresabschluss mit Überstundenausgleich.","absenzen#Absenzen":"Krankheit, Militär, Mutterschaft, unbezahlter Urlaub — getrennt erfasst, mit Auswertung pro Mitarbeiter.","ferienverwaltung#Ferienverwaltung":"Prorata-Berechnung bei Eintritt unter Jahr Ferien-Saldo in Tagen (live) Halbtage unterstützt Übertrag ins Folgejahr oder Auszahlung","jahresabschluss#Jahresabschluss":"Ferien-Restguthaben übertragen oder auszahlen Überstunden ausgleichen oder vergüten Lohnausweis vorbereiten (Export)","lohnabrechnung#Lohnabrechnung":"Monatliche Abrechnung mit:\nGrundlohn (basierend auf Pensum) Überstunden-Vergütung Spesen-Erstattung Sozialabzüge (AHV, ALV, Pensionskasse) PDF-Export pro Mitarbeiter.","stammdaten#Stammdaten":"Pro Mitarbeiter:\nName, Eintrittsdatum, Pensum (%) Stundensatz (intern, für Rechnungen) Ferienanspruch (Tage / Jahr) Lohn (monatlich, brutto)","verwandte-module#Verwandte Module":"Zeiterfassung — Pensum-Soll vs. Stunden-Ist Spesen — Spesen-Erstattung in der Lohnabrechnung"},"title":"Mitarbeiter"},"/features/projekte/":{"data":{"":"In Arbeit\nProjekte nach SIA 102 mit Budget, Phasen und Beteiligten. Erstellung aus einer Offerte mit Verknüpfung zu Zeiterfassung und Rechnungen.","auswertung#Auswertung":"Pro Projekt:\nGeleistete Stunden vs. Budget Honorar-Saldo (verrechnet / Akonto / offen) Phasen-Fortschritt","kundendatenbank#Kundendatenbank":"Adresse, Ansprechperson, Telefon, E-Mail Honorartyp (Stundensatz / SIA / Pauschal) Verknüpfung zu allen Projekten und Rechnungen des Kunden","projektstruktur#Projektstruktur":"Jedes Projekt besitzt:\nStammdaten — Nummer, Bezeichnung, Standort, Bauschätzwert Kunde — verknüpft mit Kundendatenbank Beteiligte — Bauleitung, Fachplaner, Behörden Phasen — SIA 102 (Vorprojekt, Bauprojekt, Ausschreibung, …) Budget — Gesamthonorar, pro Phase aufgeteilt","sia-102#SIA 102":"Standard-Phasenverteilung wird vorgeschlagen, kann pro Projekt überschrieben werden.\nPhase Anteil (Standard) 31 — Vorprojekt 9 % 32 — Bauprojekt 21 % 33 — Bewilligung 3 % 41 — Ausschreibung 18 % 51 — Ausführung 38 % 52 — Inbetriebnahme 6 % 53 — Abschluss 5 %","verwandte-module#Verwandte Module":"Rechnungen — Offerte → Projekt Zeiterfassung — Stunden-Auswertung pro Phase"},"title":"Projekte"},"/features/protokolle/":{"data":{"":"In Arbeit\nEinfache Erstellung von Sitzungsprotokollen mit Beschlüssen und Aufgaben. Briefe und Lieferscheine im gleichen Erscheinungsbild.","briefe#Briefe":"Brief-Editor mit:\nEmpfänger aus Kundendatenbank Bezugszeile, Anrede, Text, Grussformel Briefbogen-Vorlage mit Logo PDF-Export","lieferscheine#Lieferscheine":"Pro Lieferung:\nEmpfänger, Datum, Bezug Positionen (Plan-Nummer, Bezeichnung, Anzahl, Massstab) Unterschriftenfeld Konsistentes Erscheinungsbild über alle Dokumenttypen — eine Briefbogen-Vorlage, mehrere Verwendungen.","sitzungsprotokolle#Sitzungsprotokolle":"Pro Sitzung:\nDatum, Ort, Teilnehmer (aus Beteiligten-Liste) Traktanden als nummerierte Liste Pro Traktandum: Beschluss, Aufgabe, Verantwortlich, Frist Anhänge PDF-Export mit Bürobriefbogen.","verwandte-module#Verwandte Module":"Projekte — Beteiligte als Empfänger"},"title":"Protokolle"},"/features/rechnungen/":{"data":{"":"In Arbeit\nQR-Einzahlungsscheine, SIA-Phasen, Akonto-, Teil- und Schlussrechnungen. Offerten sind in Projekte und Rechnungen konvertierbar. PDF-Export.","honorarmodelle#Honorarmodelle":"Modell Berechnung Verwendung Stundensatz Aus Zeiterfassung × Mitarbeiter-Stundensatz Kleinaufträge, Beratung SIA-Phasen Bauschätzwert × Honorarsatz × Phasenanteil Reguläre Architektur-Aufträge Pauschal Fester Betrag Auf Wunsch des Kunden","pdf-export#PDF-Export":"Druckfertige Rechnung inkl. QR-Schein. Layout aus dem Büro-Briefbogen (mit Logo). Mehrsprachig DE/FR/IT (geplant).","qr-einzahlungsschein#QR-Einzahlungsschein":"Schweizer QR-Rechnung nach Norm — direkt eingebettet in die PDF.\nAusgelesen aus:\nBürodaten — IBAN, Empfänger-Adresse Kundendaten — Schuldner-Adresse Rechnungs-Daten — Betrag, Referenz, Zusatzinformation","verwandte-module#Verwandte Module":"Projekte — Honorarstruktur stammt aus dem Projekt Zeiterfassung — Stundensatz-Rechnungen","workflow#Workflow":"Offerte erstellen — auf Basis SIA 102 oder pauschal Kunde nimmt an → konvertieren in Projekt + Rechnung Akonto-Rechnungen während der Projektlaufzeit Schlussrechnung mit Differenz zum bisher Akonto-bezahlten"},"title":"Rechnungen"},"/features/spesen/":{"data":{"":"In Arbeit\nSpesenerfassung mit Belegupload. Jahresbudget mit Einnahmen und Ausgaben. Internes Rechnungswesen.","auswertung#Auswertung":"Einnahmen pro Kunde / Projekt Ausgaben pro Kategorie / Mitarbeiter Erfolgsrechnung pro Geschäftsjahr (vereinfacht)","jahresbudget#Jahresbudget":"Übersicht über:\nEinnahmen — Rechnungsbeträge, sortiert nach Eingang Ausgaben — Spesen, Bürokosten, Löhne, Sozialabzüge Saldo pro Monat / Quartal / Jahr","spesenerfassung#Spesenerfassung":"Pro Mitarbeiter:\nDatum, Betrag, Kategorie Beleg-Upload (PDF, JPG, PNG) Projekt-Zuordnung (optional) Status (offen / erstattet) Kategorien: Reise, Verpflegung, Material, Telefon, Sonstiges.","verwandte-module#Verwandte Module":"Mitarbeiter — Spesen-Erstattung in der Lohnabrechnung Rechnungen — Einnahmen-Quelle"},"title":"Spesen"},"/features/system-tray/":{"data":{"":"Neu in 0.7.0\nSchnellzugriff über die Menüleiste mit Hide-on-Close. Beim Schliessen läuft Rapport im Hintergrund weiter — Cmd+Q beendet die App vollständig.","konfiguration#Konfiguration":"In den Einstellungen:\nBeim Systemstart starten (Login-Item) — Standard: aus Beim Schliessen beenden statt ins Tray — Standard: aus Tray-Icon ausblenden — App läuft, aber kein Menüleisten-Icon","tray-menü#Tray-Menü":"Rapport zeigen — Fenster nach vorne Neue Zeiterfassung — direkt im Zeit-Modul Neue Rechnung — direkt im Rechnungs-Modul Letzte Projekte — Quick-Open der letzten 5 Projekte Einstellungen Rapport beenden","verhalten#Verhalten":"Aktion Verhalten Fenster schliessen (⌘W oder rotes X) App läuft im Tray weiter Cmd+Q App wird vollständig beendet Klick auf Tray-Icon Fenster nach vorne, oder zeigen Rechtsklick auf Tray-Icon Menü mit Schnellzugriffen","verwandte-module#Verwandte Module":"Auto-Updater — prüft Updates im Hintergrund"},"title":"System-Tray"},"/features/zeiterfassung/":{"data":{"":"In Arbeit\nTages- und Wochenraster mit Drag \u0026 Drop. Auswertungen pro Mitarbeiter und Projekt. Ferienverwaltung mit Prorata und Jahresabschluss.","auswertungen#Auswertungen":"Pro Mitarbeiter und pro Projekt:\nGeleistete Stunden vs. Soll-Pensum Ferienanspruch / -saldo (mit Prorata bei Eintritt unter Jahr) Überstunden-Saldo Stundenaufschlüsselung nach SIA-Phase pro Projekt","eingabe#Eingabe":"Wochenraster mit den 5 (oder 7) Arbeitstagen Halbstunden-Slots von 06:00 bis 22:00 Klick oder Drag über mehrere Slots Jeder Eintrag wird einem Projekt zugewiesen (Pflichtfeld) Mehrfacheinträge pro Slot möglich (z. B. parallele Telefonate)","jahresabschluss#Jahresabschluss":"Am Jahresende:\nFerien-Restguthaben übertragen oder auszahlen Überstunden ausgleichen oder vergüten Neues Jahr automatisch initialisieren","konzept#Konzept":"Die Zeiterfassung ist das Kernmodul von RAPPORT — alle anderen Module (Rechnungen, Auswertungen, Lohnabrechnung) greifen auf die hier erfassten Stunden zu.","verwandte-module#Verwandte Module":"Rechnungen — Stundensatz-Rechnungen ziehen direkt aus der Zeiterfassung Projekte — Stunden-Auswertung pro SIA-Phase Mitarbeiter — Pensum, Ferienanspruch"},"title":"Zeiterfassung"},"/glossary":{"data":{},"title":"Glossary"},"/lizenz/":{"data":{"":"Lizenz von RAPPORT, Zugehörigkeit zu OpenBureau und Attribution der verwendeten Open-Source-Software.","desktop-wrapper#Desktop-Wrapper":"Software Verwendung Lizenz Tauri 2 Cross-Platform Desktop-Wrapper MIT / Apache-2.0 WebKit WebView-Engine (macOS) LGPL-2.1 / BSD","diese-website#Diese Website":"Software Verwendung Lizenz Hugo Static-Site-Generator Apache-2.0 Hextra Hugo-Theme (von Xin) MIT Inter UI-Schrift (Rasmus Andersson) SIL OFL 1.1 Playfair Display Headings SIL OFL 1.1 Alle Logos und Marken-Namen gehören ihren jeweiligen Eigentümern.","frontend#Frontend":"Software Verwendung Lizenz React 19 UI-Bibliothek MIT Vite Build-Tool, Dev-Server MIT swissqrbill QR-Einzahlungsscheine MIT","kontakt#Kontakt":"Fragen zur Lizenz, kommerzieller Einsatz, Spezialfälle: Issue auf Gitea oder via gabrielevarano.ch .","lizenz#Lizenz":"Lizenziert unter GNU Affero General Public License v3.0 oder höher (AGPL-3.0-or-later ).\nDies bedeutet im Kern:\nFreie Nutzung für jeden Zweck (privat, kommerziell, behördlich) Freier Zugang zum Quellcode Freie Modifikation und Weitergabe — unter derselben Lizenz Netzwerk-Nutzung gilt als Weitergabe — wer eine modifizierte Version als Service anbietet, muss den Quellcode offenlegen Eigene Builds, eigene Forks, eigene Anpassungen — alles erlaubt, solange Modifikationen wieder unter AGPL-3.0 veröffentlicht werden.","lizenz-volltexte#Lizenz-Volltexte":"Die vollständigen Lizenztexte:\nAGPL-3.0 — RAPPORT MIT — React, Vite, Tauri, Hextra, swissqrbill Apache-2.0 — Tauri, Hugo, Supabase SIL OFL 1.1 — Inter, Playfair Display","mitwirkende#Mitwirkende":"RAPPORT wird derzeit als Ein-Personen-Projekt von Karim Gabriele Varano entwickelt. Beiträge — Code, Issues, Übersetzungen, Vorlagen — sind willkommen.\nWer beitragen möchte → Gitea Issues .","openbureau#OpenBureau":"RAPPORT ist Teil der OpenBureau-Initiative — einer Sammlung freier Software-Werkzeuge für den Architektur-Büro-Alltag.\nDie Idee: Bürowissen — Workflows, Konventionen, Vorlagen — sollte nicht in proprietären Tools eingesperrt sein. OpenBureau-Tools setzen die in der Branche etablierten Konventionen (SIA-Normen, QR-Rechnung, Plan-Verwaltung) sauber um und stehen unter freien Lizenzen zur Verfügung.\nTool Zweck Status RAPPORT Studio-Management Desktop-App (Zeit, Rechnungen, Projekte) Pre-Release Rapport Server Selfhost-Stack (Postgres + Auth + Realtime + Storage) Pre-Release DOSSIER Rhino-8-Plugin für Plan- und Dokumentationsausgabe Pre-Release Mehr unter gabrielevarano.ch .","rapport#RAPPORT":"RAPPORT — Studio Management Software für Architekturbüros.\nQuellcode: git.kgva.ch/karim/RAPPORT Autor: Karim Gabriele Varano","rapport-server-selfhost-stack#Rapport Server (Selfhost-Stack)":"Software Verwendung Lizenz PostgreSQL Datenbank PostgreSQL-Lizenz GoTrue Authentication-Service MIT PostgREST REST-API über Postgres-Schema MIT Realtime WebSocket-Sync Apache-2.0 Storage Object-Storage für Belege \u0026 Logos Apache-2.0 Kong API-Gateway Apache-2.0 nginx Frontend-Webserver BSD-2-Clause Docker Compose Orchestrierung Apache-2.0","verwendete-open-source-software#Verwendete Open-Source-Software":"RAPPORT baut auf freier Software auf. Diese Liste nennt die wichtigsten Komponenten und ihre jeweiligen Lizenzen."},"title":"Lizenz"},"/server/":{"data":{"":"Self-Hosting\nRapport Server — der vollständige Selfhost-Stack für Rapport. Eigene Daten, eigene Domain, eigener Server. Komplett Open-Source, Docker-Compose, AGPL-3.0.","1--repo-klonen#1 · Repo klonen":"git clone https://git.kgva.ch/karim/rapport-server.git cd rapport-server","2--env-erstellen#2 · \u003ccode\u003e.env\u003c/code\u003e erstellen":"cp .env.example .env In .env müssen mindestens diese Werte ersetzt werden:\nVariable Was POSTGRES_PASSWORD DB-Passwort (≥ 32 Zeichen, zufällig) JWT_SECRET JWT-Signatur (≥ 32 Zeichen, zufällig) ANON_KEY / SERVICE_ROLE_KEY aus JWT-Secret abgeleitet SITE_URL Public-URL der Instanz (z. B. https://app.rapport.studio.ch) Zufallswerte generieren:\nopenssl rand -hex 32 # für POSTGRES_PASSWORD und JWT_SECRET node scripts/generate-keys.mjs # ANON_KEY + SERVICE_ROLE_KEY aus JWT_SECRET","3--migrations-holen#3 · Migrations holen":"Die SQL-Migrations stammen aus dem App-Repo. Einmal initial holen:\n./scripts/sync-migrations.sh Bei späteren Rapport-Updates erneut ausführen, dann docker compose down \u0026\u0026 docker compose up -d.","4--stack-starten#4 · Stack starten":"docker compose up -d Erststart dauert ~1 Minute (Postgres initialisiert sich, Migrations laufen, Container starten).","5--health-check#5 · Health-Check":"docker compose ps Alle Container sollten healthy zeigen. Frontend ist dann erreichbar unter http://localhost:8080.","architektur#Architektur":"Rapport Server bündelt sechs Open-Source-Komponenten zu einem stimmigen Stack:\n┌──────────────────────────────────────────────────────┐ │ Browser / Desktop-App │ └──────────────┬───────────────────────┬───────────────┘ │ │ ▼ ▼ ┌──────────┐ ┌──────────┐ │ nginx │ │ Kong │ ← API-Gateway │ (app) │ │ │ └──────────┘ └──────────┘ │ ┌───────────────────┼─────────────────────┐ ▼ ▼ ▼ ┌────────┐ ┌──────────┐ ┌─────────┐ │ GoTrue │ │PostgREST │ │ Realtime│ │ (Auth) │ │ (API) │ │ (WS) │ └────────┘ └──────────┘ └─────────┘ │ │ │ └───────────────────┼─────────────────────┘ ▼ ┌─────────────────┐ │ PostgreSQL │ └─────────────────┘ │ ▼ ┌─────────────────┐ │ Storage │ ← Belege, Logos └─────────────────┘ Komponente Funktion PostgreSQL Datenbank — alle Rapport-Daten GoTrue Authentication — Email/Passwort, JWT-Tokens PostgREST REST-API direkt aus dem Postgres-Schema Realtime WebSocket-Sync für Live-Updates Storage Object-Storage für Belege \u0026 Logos Kong API-Gateway, routet alle Calls app (nginx) Liefert das Rapport-Frontend (React-Build) Alles in einem Docker-Compose. Keine Cloud-Abhängigkeit, keine Telemetrie.","backup#Backup":"","bezug-rapport--rapport-server#Bezug Rapport ↔ Rapport Server":"Komponente Wo Lizenz Rapport Desktop-App git.kgva.ch/karim/RAPPORT AGPL-3.0 Rapport Server git.kgva.ch/karim/rapport-server AGPL-3.0 Die Desktop-App kann wahlweise im Lokal-Modus (JSON, kein Server nötig) oder im Cloud-Modus (gegen Rapport Server) betrieben werden. Wechsel erfolgt im Login-Bildschirm der App.","brauche-ich-supabase-cloud#Brauche ich Supabase Cloud?":"Nein. Rapport Server ist die Selfhost-Variante derselben Komponenten (Postgres + GoTrue + PostgREST + Realtime + Storage), aber komplett auf eigener Infrastruktur. Kein Supabase-Account, keine externe Abhängigkeit.","häufige-fragen#Häufige Fragen":"","kann-ich-von-der-desktop-app-auf-rapport-server-migrieren#Kann ich von der Desktop-App auf Rapport Server migrieren?":"Im Login der Desktop-App auf Cloud wechseln, Server-URL eingeben, Account erstellen, Daten manuell wieder anlegen (Bürodaten, Mitarbeiter, Kunden). Ein direkter localStorage → Postgres-Import ist geplant .","postgres-dump#Postgres-Dump":"docker compose exec -T db pg_dumpall -U postgres \u003e backup-$(date +%Y%m%d).sql Empfohlen: per cron täglich + auf externe Disk / S3 / Backblaze sichern.","quellcode#Quellcode":"git.kgva.ch/karim/rapport-server — Issues, Pull Requests und Forks willkommen.","restore#Restore":"docker compose down docker volume rm rapport-server_postgres-data docker compose up -d db sleep 10 cat backup-YYYYMMDD.sql | docker compose exec -T db psql -U postgres docker compose up -d","reverse-proxy--https#Reverse-Proxy + HTTPS":"Für Production-Setups mit eigener Domain — Caddy ist die einfachste Variante (config-as-code, Let’s-Encrypt automatisch):\napp.rapport.studio.ch { reverse_proxy localhost:8080 } api.rapport.studio.ch { reverse_proxy localhost:8000 } In .env dann:\nSITE_URL=https://app.rapport.studio.ch API_EXTERNAL_URL=https://api.rapport.studio.ch Alternativ über Nginx Proxy Manager mit Web-UI — siehe Troubleshooting.","setup-in-5-schritten#Setup in 5 Schritten":"","storage-belege-logos#Storage (Belege, Logos)":"docker compose exec storage tar -czf - /var/lib/storage \u003e storage-$(date +%Y%m%d).tar.gz","updates#Updates":"git pull ./scripts/sync-migrations.sh # falls neue SQL-Migrationen docker compose pull # neueste Container-Versionen docker compose up -d # neu starten Daten bleiben erhalten — das Volume postgres-data wird nicht angetastet.","voraussetzungen#Voraussetzungen":"OS Container-Runtime Linux (Ubuntu 22.04+, Debian 12+, …) Docker Engine + Compose v2 macOS (Mac Mini etc.) Colima + Docker CLI — voll OSS Auf macOS funktionieren auch OrbStack oder Docker Desktop, beide sind aber proprietär. Colima ist die OSS-Alternative und für Selfhost vollkommen ausreichend.\nPlus: ein DNS-Name für TLS (z. B. rapport.studio.ch), und optional ein Reverse-Proxy wie Nginx Proxy Manager oder Caddy .","wann-brauchst-du-rapport-server#Wann brauchst du Rapport Server?":"Szenario Lösung Ein Mensch, ein Mac Desktop-App reicht — Installation Mehrere Personen im Studio Rapport Server auf einem Mac Mini oder Linux-Server Verteiltes Team, Home-Office, Mobile-Zugriff Rapport Server mit Reverse-Proxy + SSL Cloud-Hosting bei einem Anbieter Rapport Server auf VPS/Hetzner/etc. Die Desktop-App speichert lokal als JSON. Rapport Server bringt Postgres + Multi-User + Realtime-Sync — für alle, die zu zweit oder im Team arbeiten.","was-kostet-das#Was kostet das?":"Nichts — Rapport Server ist Open-Source (AGPL-3.0). Du brauchst nur einen Server (Mac Mini, NAS, VPS) und ggf. eine Domain.","wieviel-server-resourcen#Wieviel Server-Resourcen?":"Ein Mac Mini M1 (8 GB RAM) reicht problemlos für ein 5-Personen-Studio. Linux-VPS mit 2 GB RAM + 2 CPU reicht auch."},"title":"Server"}} \ No newline at end of file diff --git a/public/de.search.js b/public/de.search.js deleted file mode 100644 index 4907b47..0000000 --- a/public/de.search.js +++ /dev/null @@ -1,490 +0,0 @@ -// Search functionality using FlexSearch. - -// Change shortcut key to cmd+k on Mac, iPad or iPhone. -document.addEventListener("DOMContentLoaded", function () { - if (/iPad|iPhone|Macintosh/.test(navigator.userAgent)) { - // select the kbd element under the .hextra-search-wrapper class - const keys = document.querySelectorAll(".hextra-search-wrapper kbd"); - keys.forEach(key => { - key.innerHTML = 'K'; - }); - } -}); - -// Render the search data as JSON. -// -// -// -// - -(function () { - const searchDataURL = '/de.search-data.json'; - const resultsFoundTemplate = '%d Ergebnisse gefunden'; - - const inputElements = document.querySelectorAll('.hextra-search-input'); - for (const el of inputElements) { - el.addEventListener('focus', init); - el.addEventListener('keyup', search); - el.addEventListener('keydown', handleKeyDown); - el.addEventListener('input', handleInputChange); - } - - const shortcutElements = document.querySelectorAll('.hextra-search-wrapper kbd'); - - function setShortcutElementsOpacity(opacity) { - shortcutElements.forEach(el => { - el.style.opacity = opacity; - }); - } - - function handleInputChange(e) { - const opacity = e.target.value.length > 0 ? 0 : 100; - setShortcutElementsOpacity(opacity); - } - - // Get the search wrapper, input, and results elements. - function getActiveSearchElement() { - const inputs = Array.from(document.querySelectorAll('.hextra-search-wrapper')).filter(el => el.clientHeight > 0); - if (inputs.length === 1) { - return { - wrapper: inputs[0], - inputElement: inputs[0].querySelector('.hextra-search-input'), - resultsElement: inputs[0].querySelector('.hextra-search-results') - }; - } - return undefined; - } - - const INPUTS = ['input', 'select', 'button', 'textarea'] - - // Focus the search input when pressing ctrl+k/cmd+k or /. - document.addEventListener('keydown', function (e) { - const { inputElement } = getActiveSearchElement(); - if (!inputElement) return; - - const activeElement = document.activeElement; - const tagName = activeElement && activeElement.tagName; - if ( - inputElement === activeElement || - !tagName || - INPUTS.includes(tagName) || - (activeElement && activeElement.isContentEditable)) - return; - - if ( - e.key === '/' || - (e.key === 'k' && - (e.metaKey /* for Mac */ || /* for non-Mac */ e.ctrlKey)) - ) { - e.preventDefault(); - inputElement.focus(); - } else if (e.key === 'Escape' && inputElement.value) { - inputElement.blur(); - } - }); - - // Dismiss the search results when clicking outside the search box. - document.addEventListener('mousedown', function (e) { - const { inputElement, resultsElement } = getActiveSearchElement(); - if (!inputElement || !resultsElement) return; - if ( - e.target !== inputElement && - e.target !== resultsElement && - !resultsElement.contains(e.target) - ) { - setShortcutElementsOpacity(100); - hideSearchResults(); - } - }); - - // Get the currently active result and its index. - function getActiveResult() { - const { resultsElement } = getActiveSearchElement(); - if (!resultsElement) return { result: undefined, index: -1 }; - - const result = resultsElement.querySelector('.hextra-search-active'); - if (!result) return { result: undefined, index: -1 }; - - const index = parseInt(result.dataset.index, 10); - return { result, index }; - } - - // Set the active result by index. - function setActiveResult(index) { - const { resultsElement } = getActiveSearchElement(); - if (!resultsElement) return; - - const { result: activeResult } = getActiveResult(); - activeResult && activeResult.classList.remove('hextra-search-active'); - const result = resultsElement.querySelector(`[data-index="${index}"]`); - if (result) { - result.classList.add('hextra-search-active'); - result.focus(); - } - } - - // Get the number of search results from the DOM. - function getResultsLength() { - const { resultsElement } = getActiveSearchElement(); - if (!resultsElement) return 0; - return resultsElement.dataset.count; - } - - // Finish the search by hiding the results and clearing the input. - function finishSearch() { - const { inputElement } = getActiveSearchElement(); - if (!inputElement) return; - hideSearchResults(); - inputElement.value = ''; - inputElement.blur(); - } - - function hideSearchResults() { - const { resultsElement } = getActiveSearchElement(); - if (!resultsElement) return; - resultsElement.classList.add('hx:hidden'); - } - - // Handle keyboard events. - function handleKeyDown(e) { - const { inputElement } = getActiveSearchElement(); - if (!inputElement) return; - - const resultsLength = getResultsLength(); - const { result: activeResult, index: activeIndex } = getActiveResult(); - - switch (e.key) { - case 'ArrowUp': - e.preventDefault(); - if (activeIndex > 0) setActiveResult(activeIndex - 1); - break; - case 'ArrowDown': - e.preventDefault(); - if (activeIndex + 1 < resultsLength) setActiveResult(activeIndex + 1); - break; - case 'Enter': - e.preventDefault(); - if (activeResult) { - activeResult.click(); - } - finishSearch(); - case 'Escape': - e.preventDefault(); - hideSearchResults(); - // Clear the input when pressing escape - inputElement.value = ''; - inputElement.dispatchEvent(new Event('input')); - // Remove focus from the input - inputElement.blur(); - break; - } - } - - // Initializes the search. - function init(e) { - e.target.removeEventListener('focus', init); - if (!(window.pageIndex && window.sectionIndex)) { - preloadIndex(); - } - } - - /** - * Preloads the search index by fetching data and adding it to the FlexSearch index. - * @returns {Promise} A promise that resolves when the index is preloaded. - */ - async function preloadIndex() { - const tokenize = 'forward'; - - // https://github.com/TryGhost/Ghost/pull/21148 - const regex = new RegExp( - `[\u{4E00}-\u{9FFF}\u{3040}-\u{309F}\u{30A0}-\u{30FF}\u{AC00}-\u{D7A3}\u{3400}-\u{4DBF}\u{20000}-\u{2A6DF}\u{2A700}-\u{2B73F}\u{2B740}-\u{2B81F}\u{2B820}-\u{2CEAF}\u{2CEB0}-\u{2EBEF}\u{30000}-\u{3134F}\u{31350}-\u{323AF}\u{2EBF0}-\u{2EE5F}\u{F900}-\u{FAFF}\u{2F800}-\u{2FA1F}]|[0-9A-Za-zа-я\u00C0-\u017F\u0400-\u04FF\u0600-\u06FF\u0980-\u09FF\u1E00-\u1EFF\u0590-\u05FF]+`, - 'mug' - ); - const encode = (str) => { return ('' + str).toLowerCase().match(regex) ?? []; } - - window.pageIndex = new FlexSearch.Document({ - tokenize, - encode, - cache: 100, - document: { - id: 'id', - store: ['title', 'crumb'], - index: "content" - } - }); - - window.sectionIndex = new FlexSearch.Document({ - tokenize, - encode, - cache: 100, - document: { - id: 'id', - store: ['title', 'content', 'url', 'display', 'crumb'], - index: "content", - tag: [{ - field: "pageId" - }] - } - }); - - const resp = await fetch(searchDataURL); - const data = await resp.json(); - let pageId = 0; - for (const route in data) { - let pageContent = ''; - ++pageId; - const urlParts = route.split('/').filter(x => x != "" && !x.startsWith('#')); - - let crumb = ''; - let searchUrl = '/'; - for (let i = 0; i < urlParts.length; i++) { - const urlPart = urlParts[i]; - searchUrl += urlPart + '/' - - const crumbData = data[searchUrl]; - if (!crumbData) { - console.debug('Excluded page', searchUrl, '- will not be included for search result breadcrumb for', route); - continue; - } - - let title = data[searchUrl].title; - if (title == "_index") { - title = urlPart.split("-").map(x => x).join(" "); - } - crumb += title; - - if (i < urlParts.length - 1) { - crumb += ' > '; - } - } - - for (const heading in data[route].data) { - const [hash, text] = heading.split('#'); - const url = route.trimEnd('/') + (hash ? '#' + hash : ''); - const title = text || data[route].title; - - const content = data[route].data[heading] || ''; - const paragraphs = content.split('\n').filter(Boolean); - - sectionIndex.add({ - id: url, - url, - title, - crumb, - pageId: `page_${pageId}`, - content: title, - ...(paragraphs[0] && { display: paragraphs[0] }) - }); - - for (let i = 0; i < paragraphs.length; i++) { - sectionIndex.add({ - id: `${url}_${i}`, - url, - title, - crumb, - pageId: `page_${pageId}`, - content: paragraphs[i] - }); - } - - pageContent += ` ${title} ${content}`; - } - - window.pageIndex.add({ - id: pageId, - title: data[route].title, - crumb, - content: pageContent - }); - - } - } - - /** - * Performs a search based on the provided query and displays the results. - * @param {Event} e - The event object. - */ - function search(e) { - const query = e.target.value; - if (!e.target.value) { - hideSearchResults(); - return; - } - - const { resultsElement } = getActiveSearchElement(); - while (resultsElement.firstChild) { - resultsElement.removeChild(resultsElement.firstChild); - } - resultsElement.classList.remove('hx:hidden'); - - // Configurable search limits with sensible defaults - const maxPageResults = parseInt('20', 10); - const maxSectionResults = parseInt('10', 10); - const pageResults = window.pageIndex.search(query, maxPageResults, { enrich: true, suggest: true })[0]?.result || []; - - const results = []; - const pageTitleMatches = {}; - - for (let i = 0; i < pageResults.length; i++) { - const result = pageResults[i]; - pageTitleMatches[i] = 0; - - const sectionResults = window.sectionIndex.search(query, - { enrich: true, suggest: true, tag: { 'pageId': `page_${result.id}` } })[0]?.result || []; - let isFirstItemOfPage = true - const occurred = {} - - const nResults = Math.min(sectionResults.length, maxSectionResults); - for (let j = 0; j < nResults; j++) { - const { doc } = sectionResults[j] - const isMatchingTitle = doc.display !== undefined - if (isMatchingTitle) { - pageTitleMatches[i]++ - } - const { url, title } = doc - const content = doc.display || doc.content - - if (occurred[url + '@' + content]) continue - occurred[url + '@' + content] = true - results.push({ - _page_rk: i, - _section_rk: j, - route: url, - prefix: isFirstItemOfPage ? result.doc.crumb : undefined, - children: { title, content } - }) - isFirstItemOfPage = false - } - } - const sortedResults = results - .sort((a, b) => { - // Sort by number of matches in the title. - if (a._page_rk === b._page_rk) { - return a._section_rk - b._section_rk - } - if (pageTitleMatches[a._page_rk] !== pageTitleMatches[b._page_rk]) { - return pageTitleMatches[b._page_rk] - pageTitleMatches[a._page_rk] - } - return a._page_rk - b._page_rk - }) - .map(res => ({ - id: `${res._page_rk}_${res._section_rk}`, - route: res.route, - prefix: res.prefix, - children: res.children - })); - displayResults(sortedResults, query); - } - - /** - * Displays the search results on the page. - * - * @param {Array} results - The array of search results. - * @param {string} query - The search query. - */ - function displayResults(results, query) { - const { resultsElement } = getActiveSearchElement(); - if (!resultsElement) return; - - if (!results.length) { - resultsElement.innerHTML = `Keine Ergebnisse gefunden.`; - // Announce no results to screen readers - const wrapper = resultsElement.closest('.hextra-search-wrapper'); - const statusEl = wrapper ? wrapper.querySelector('.hextra-search-status') : null; - if (statusEl) { - statusEl.textContent = 'Keine Ergebnisse gefunden.'; - } - return; - } - - // Append text with highlighted matches using safe text nodes. - function appendHighlightedText(container, text, query) { - if (!text) return; - if (!query) { - container.textContent = text; - return; - } - - const escapedQuery = query.replace(/[-\\^$*+?.()|[\]{}]/g, '\\$&'); - if (!escapedQuery) { - container.textContent = text; - return; - } - - const regex = new RegExp(escapedQuery, 'gi'); - let lastIndex = 0; - let match; - while ((match = regex.exec(text)) !== null) { - if (match.index > lastIndex) { - container.appendChild(document.createTextNode(text.slice(lastIndex, match.index))); - } - const span = document.createElement('span'); - span.className = 'hextra-search-match'; - span.textContent = match[0]; - container.appendChild(span); - lastIndex = match.index + match[0].length; - } - if (lastIndex < text.length) { - container.appendChild(document.createTextNode(text.slice(lastIndex))); - } - } - - function handleMouseMove(e) { - const target = e.target.closest('a'); - if (target) { - const active = resultsElement.querySelector('a.hextra-search-active'); - if (active) { - active.classList.remove('hextra-search-active'); - } - target.classList.add('hextra-search-active'); - } - } - - const fragment = document.createDocumentFragment(); - for (let i = 0; i < results.length; i++) { - const result = results[i]; - if (result.prefix) { - const prefix = document.createElement('div'); - prefix.className = 'hextra-search-prefix'; - prefix.textContent = result.prefix; - fragment.appendChild(prefix); - } - const li = document.createElement('li'); - const link = document.createElement('a'); - link.dataset.index = i; - link.href = result.route; - if (i === 0) { - link.classList.add('hextra-search-active'); - } - - const title = document.createElement('div'); - title.className = 'hextra-search-title'; - appendHighlightedText(title, result.children.title, query); - link.appendChild(title); - - if (result.children.content) { - const excerpt = document.createElement('div'); - excerpt.className = 'hextra-search-excerpt'; - appendHighlightedText(excerpt, result.children.content, query); - link.appendChild(excerpt); - } - - li.appendChild(link); - li.addEventListener('mousemove', handleMouseMove); - li.addEventListener('keydown', handleKeyDown); - link.addEventListener('click', finishSearch); - fragment.appendChild(li); - } - resultsElement.appendChild(fragment); - resultsElement.dataset.count = results.length; - - // Announce results count to screen readers - const wrapper = resultsElement.closest('.hextra-search-wrapper'); - const statusEl = wrapper ? wrapper.querySelector('.hextra-search-status') : null; - if (statusEl) { - statusEl.textContent = results.length > 0 - ? resultsFoundTemplate.replace('%d', results.length.toString()) - : 'Keine Ergebnisse gefunden.'; - } - } -})(); diff --git a/public/docs/changelog/index.html b/public/docs/changelog/index.html index 968aa16..02a4262 100644 --- a/public/docs/changelog/index.html +++ b/public/docs/changelog/index.html @@ -1,13 +1,13 @@ Changelog – RAPPORTZum Inhalt springen
Changelog

Changelog

Versionsgeschichte von RAPPORT. Aktuelle Releases: Gitea.

0.8.2 — Aktuelle Version Aktuell +

Veröffentlicht am 2026-05-24.

Neu / Verbessert

Bekannte Einschränkungen

  • Builds sind Tauri-signiert, aber noch nicht Apple-notarisiert — siehe Installation § Gatekeeper
  • Linux- und Windows-Builds noch nicht verfügbar

0.8.0–0.8.1 — Patch-Releases +

Patch-Reihe mit kleineren Verbesserungen und Bugfixes. Details siehe Releases auf Gitea.

0.7.0 — Auto-Updater & System-Tray

Neu

  • Auto-Updater — Rapport prüft beim Start auf neue Versionen und installiert Updates signiert über Tauri. Einzelne Versionen können übersprungen werden. (Doku)
  • System-Tray — Schnellzugriff über die Menüleiste mit Hide-on-Close. Beim Schliessen läuft Rapport im Hintergrund weiter, Cmd+Q beendet die App vollständig. (Doku)
  • Quick-Open der letzten 5 Projekte direkt aus dem Tray-Menü

Verbessert

  • Schnellerer App-Start durch lazy-geladene Views
  • Klarere Statusbadges in der Projekt-Übersicht

0.6.x — Spesen & Buchhaltung

Neu

  • Spesenerfassung mit Beleg-Upload (Base64 in localStorage)
  • Jahresbudget mit Einnahmen-/Ausgaben-Übersicht
  • Vereinfachte Erfolgsrechnung pro Geschäftsjahr

Verbessert

  • Lohnabrechnung integriert Spesen-Erstattungen
  • CSV-Export aus der Zeiterfassung

0.5.x — Mitarbeiter & Lohn

Neu

  • Mitarbeiterverwaltung mit Pensum, Stundensatz, Ferienanspruch
  • Lohnabrechnung mit AHV/IV/EO, ALV, BVG, NBU
  • Jahresabschluss mit Überstundenausgleich
  • Ferien-Prorata bei Eintritt unter Jahr

0.4.x — Projekte & SIA 102 diff --git a/public/docs/index.xml b/public/docs/index.xml index 01c79dc..c596201 100644 --- a/public/docs/index.xml +++ b/public/docs/index.xml @@ -1365,11 +1365,11 @@ data-copied-label="Kopiert!" <p>Versionsgeschichte von RAPPORT. Aktuelle Releases: <a href="https://git.kgva.ch/karim/RAPPORT/releases"target="_blank" rel="noopener">Gitea<svg class="hx:inline hx:rtl:rotate-270 hx:align-baseline" height="1em" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> <path d="m9.1716 7.7574h7.0711m0 0v7.0711m0-7.0711-8.4853 8.4853" stroke-linecap="round" stroke-linejoin="round"/> </svg></a>.</p> -<h2>0.8.3 — Aktuelle Version <span class="rapport-status new">Aktuell</span><span class="hx:absolute hx:-mt-20" id="083--aktuelle-version-aktuell"></span> -<a href="#083--aktuelle-version-aktuell" class="subheading-anchor" aria-label="Permalink für diesen Abschnitt"></a></h2><p>Veröffentlicht am 2026-05-24.</p> +<h2>0.8.2 — Aktuelle Version <span class="rapport-status new">Aktuell</span><span class="hx:absolute hx:-mt-20" id="082--aktuelle-version-aktuell"></span> +<a href="#082--aktuelle-version-aktuell" class="subheading-anchor" aria-label="Permalink für diesen Abschnitt"></a></h2><p>Veröffentlicht am 2026-05-24.</p> <p><strong>Neu / Verbessert</strong></p> <ul> -<li>Diverse Verbesserungen und Bugfixes (Details werden im <a href="https://git.kgva.ch/karim/RAPPORT/releases/tag/0.8.3"target="_blank" rel="noopener">Release auf Gitea<svg class="hx:inline hx:rtl:rotate-270 hx:align-baseline" height="1em" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> +<li>Diverse Verbesserungen und Bugfixes (Details werden im <a href="https://git.kgva.ch/karim/RAPPORT/releases/tag/0.8.2"target="_blank" rel="noopener">Release auf Gitea<svg class="hx:inline hx:rtl:rotate-270 hx:align-baseline" height="1em" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> <path d="m9.1716 7.7574h7.0711m0 0v7.0711m0-7.0711-8.4853 8.4853" stroke-linecap="round" stroke-linejoin="round"/> </svg></a> gepflegt)</li> </ul> @@ -1378,8 +1378,8 @@ data-copied-label="Kopiert!" <li>Builds sind Tauri-signiert, aber noch nicht Apple-notarisiert — siehe <a href="../installation#3--erster-start-macos-gatekeeper">Installation § Gatekeeper</a></li> <li>Linux- und Windows-Builds noch nicht verfügbar</li> </ul> -<h2>0.8.0–0.8.2 — Patch-Releases<span class="hx:absolute hx:-mt-20" id="080082--patch-releases"></span> -<a href="#080082--patch-releases" class="subheading-anchor" aria-label="Permalink für diesen Abschnitt"></a></h2><p>Patch-Reihe mit kleineren Verbesserungen und Bugfixes. Details siehe <a href="https://git.kgva.ch/karim/RAPPORT/releases"target="_blank" rel="noopener">Releases auf Gitea<svg class="hx:inline hx:rtl:rotate-270 hx:align-baseline" height="1em" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> +<h2>0.8.0–0.8.1 — Patch-Releases<span class="hx:absolute hx:-mt-20" id="080081--patch-releases"></span> +<a href="#080081--patch-releases" class="subheading-anchor" aria-label="Permalink für diesen Abschnitt"></a></h2><p>Patch-Reihe mit kleineren Verbesserungen und Bugfixes. Details siehe <a href="https://git.kgva.ch/karim/RAPPORT/releases"target="_blank" rel="noopener">Releases auf Gitea<svg class="hx:inline hx:rtl:rotate-270 hx:align-baseline" height="1em" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> <path d="m9.1716 7.7574h7.0711m0 0v7.0711m0-7.0711-8.4853 8.4853" stroke-linecap="round" stroke-linejoin="round"/> </svg></a>.</p> <h2>0.7.0 — Auto-Updater &amp; System-Tray<span class="hx:absolute hx:-mt-20" id="070--auto-updater--system-tray"></span> diff --git a/public/downloads/index.html b/public/downloads/index.html index 4947920..605fc7b 100644 --- a/public/downloads/index.html +++ b/public/downloads/index.html @@ -1,8 +1,8 @@ Downloads – RAPPORTZum Inhalt springen

Downloads

Aktuelle Builds von Rapport. Quellcode und ältere Versionen auf Gitea.

Rapport besteht aus zwei Komponenten:

KomponenteFür wenAktuelle Version
Desktop-AppSolo-Büro, lokale Datenhaltung0.8.2
Rapport ServerTeam / Multi-User / Selfhost0.1.0

Desktop-App — Pre-Release 0.8.2 +

Aktuelle Version

Neuerungen — siehe Changelog für Details.

macOS +

ArchitekturDownload
Apple Silicon (M1–M4)RAPPORT_0.8.2_aarch64.dmg
Intel (x86_64)auf Anfrage

Erstinstallation: Systemeinstellungen → Datenschutz & Sicherheit öffnen und Rapport zulassen. Die Builds sind über Tauri signiert, aber (noch) nicht Apple-notarisiert.

Linux & Windows

Geplant. Rapport basiert auf Tauri 2 — eine Portierung ist möglich, sobald der Bedarf besteht. Issue erstellen, wenn du eine Plattform brauchst.


Rapport Server — 0.1.0

Erstes Release

Selfhost-Backend für Multi-User-Setups — Postgres, Auth, Realtime-Sync, Storage. Details und Setup-Anleitung auf der Server-Seite.

Server-App (macOS)

GUI zum Starten, Stoppen und Verwalten der Server-Instanz auf einem Mac (Mac Mini, Studio-Rechner). Bündelt den Docker-Compose-Stack.

ArchitekturDownload
Apple Silicon (M1–M4)RAPPORT_SERVER_0.1.0_aarch64.dmg
Intel (x86_64)auf Anfrage

Voraussetzung: Colima oder Docker Desktop muss installiert sein. Die App verwaltet den Container-Stack darüber.

Docker (Linux / VPS / Headless) diff --git a/public/faq/index.html b/public/faq/index.html index be8711e..2937fa0 100644 --- a/public/faq/index.html +++ b/public/faq/index.html @@ -35,7 +35,7 @@ System

Ja, vollständig. Quellcode unter GNU AGPL-3.0-or-later. Keine versteckten Kosten, keine Telemetrie. Die Daten bleiben lokal auf deinem Computer bzw. in deiner Instanz. Du hast die komplette Kontrolle über deine Daten.

Welche Systeme werden unterstützt?

Aktuell nur macOS (Intel & Apple Silicon). Rapport basiert auf Tauri — eine Portierung auf Linux und Windows ist möglich, sobald der Bedarf seitens Community besteht.

Wo werden die Daten gespeichert?

Rapport unterstützt zwei Modi, beide selbst-gehostet:

  • Desktop-App (Single-User) — alle Daten liegen lokal auf deinem Mac (localStorage im Applikationsordner). Kein Server nötig, kein Cloud-Account, keine Telemetrie.
  • Server-Modus (Multi-User) — Daten in einer eigenen PostgreSQL-Datenbank über Rapport Server. Mehrere Personen, Realtime-Sync, eigene Domain. Wechsel direkt im Login-Bildschirm der App.

In beiden Fällen bleibt die Kontrolle über die Daten bei dir.

Ist die Software stabil genug für den Betrieb? -

Noch nicht. Aktuell befindet sich Rapport in aktiver Entwicklung (Pre-Release 0.8.3). Funktionen können sich ändern, Bugs sind möglich. Regelmässige Backups sind empfohlen. Testen und Feedback geben ist erwünscht.

Was ist mit dem QR-Einzahlungsschein? +

Noch nicht. Aktuell befindet sich Rapport in aktiver Entwicklung (Pre-Release 0.8.2). Funktionen können sich ändern, Bugs sind möglich. Regelmässige Backups sind empfohlen. Testen und Feedback geben ist erwünscht.

Was ist mit dem QR-Einzahlungsschein?

Rapport erzeugt Schweizer QR-Rechnungen nach Norm — direkt eingebettet in das PDF der Rechnung. IBAN, Bürodaten und Empfänger werden aus den Einstellungen bzw. den Kundendaten gezogen. Akonto-, Teil- und Schlussrechnungen werden unterstützt.

Wie funktioniert die Zeiterfassung?

Tages- und Wochenraster mit Drag & Drop. Jeder Eintrag wird einem Projekt zugewiesen. Auswertungen pro Mitarbeiter und Projekt sind unter Zeit abrufbar. Ferienverwaltung mit Prorata und Jahresabschluss mit Überstundenausgleich.

Kann ich zum Projekt beitragen?

Ja. Issues und Pull Requests sind willkommen auf Gitea. Rapport ist kein Framework — konkrete Verbesserungen für den Büroalltag sind am wertvollsten:

  • Bug-Reports mit Reproduktionsschritten
  • Workflow-Verbesserungen aus dem realen Büroalltag
  • Vorlagen (Briefe, Protokolle, Lieferscheine) für andere Büros
  • Übersetzungen / Internationalisierung

Wie erhalte ich Hilfe bei einem Problem? diff --git a/public/features/auto-updater/index.html b/public/features/auto-updater/index.html index b1eeb2d..57f728e 100644 --- a/public/features/auto-updater/index.html +++ b/public/features/auto-updater/index.html @@ -60,13 +60,13 @@ System

  • Updates werden mit dem Tauri-Updater-Schlüssel signiert
  • Manipulierte Downloads werden abgelehnt
  • Quellcode und Build sind reproduzierbar (Gitea CI, geplant)

Optionen

  • Update installieren — Download & Neustart
  • Diese Version überspringen — überspringt nur diese eine Version
  • Später erinnern — beim nächsten Start erneut fragen

Updates können in den Einstellungen komplett deaktiviert werden.

Latest-Endpoint

{
-  "version": "0.8.3",
-  "notes": "Rapport 0.8.3",
+  "version": "0.8.2",
+  "notes": "Rapport 0.8.2",
   "pub_date": "2026-05-24T00:00:00Z",
   "platforms": {
     "darwin-aarch64": {
       "signature": "…",
-      "url": "https://git.kgva.ch/karim/RAPPORT/releases/download/0.8.3/RAPPORT%20PRE-RELEASE.app.tar.gz"
+      "url": "https://git.kgva.ch/karim/RAPPORT/releases/download/0.8.2/RAPPORT%20PRE-RELEASE.app.tar.gz"
     }
   }
 }